LCOV - code coverage report
Current view: top level - apps/filterWheelCtrl - filterWheelCtrl.hpp (source / functions) Coverage Total Hit
Test: MagAOX Lines: 0.0 % 380 0
Test Date: 2026-01-03 21:03:39 Functions: 0.0 % 26 0

            Line data    Source code
       1              : /** \file filterWheelCtrl.hpp
       2              :   * \brief The MagAO-X Filter Wheel Controller
       3              :   *
       4              :   * \ingroup filterWheelCtrl_files
       5              :   */
       6              : 
       7              : 
       8              : #ifndef filterWheelCtrl_hpp
       9              : #define filterWheelCtrl_hpp
      10              : 
      11              : 
      12              : #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
      13              : #include "../../magaox_git_version.h"
      14              : 
      15              : /** \defgroup filterWheelCtrl Filter Wheel Control
      16              :   * \brief Control of MagAO-X MCBL-based f/w.
      17              :   *
      18              :   * <a href="../handbook/operating/software/apps/filterWheelCtrl.html">Application Documentation</a>
      19              :   *
      20              :   * \ingroup apps
      21              :   *
      22              :   */
      23              : 
      24              : /** \defgroup filterWheelCtrl_files Filter Wheel Control Files
      25              :   * \ingroup filterWheelCtrl
      26              :   */
      27              : 
      28              : namespace MagAOX
      29              : {
      30              : namespace app
      31              : {
      32              : 
      33              : /** MagAO-X application to control a Faulhaber MCBL controlled filter wheel.
      34              :   *
      35              :   * \todo add temperature monitoring
      36              :   * \todo add INDI props to md doc
      37              :   * \todo should move in least time direction, rather than always in the same direction.
      38              :   * \todo add tests
      39              :   * \todo should be an iodevice
      40              :   *
      41              :   * \ingroup filterWheelCtrl
      42              :   */
      43              : class filterWheelCtrl : public MagAOXApp<>, public tty::usbDevice, public dev::stdMotionStage<filterWheelCtrl>, public dev::telemeter<filterWheelCtrl>
      44              : {
      45              : 
      46              :    friend class dev::stdMotionStage<filterWheelCtrl>;
      47              : 
      48              :    friend class dev::telemeter<filterWheelCtrl>;
      49              : 
      50              : protected:
      51              : 
      52              :    /** \name Non-configurable parameters
      53              :      *@{
      54              :      */
      55              : 
      56              :    int m_motorType {2};
      57              : 
      58              :    ///@}
      59              : 
      60              :    /** \name Configurable Parameters
      61              :      * @{
      62              :      */
      63              : 
      64              :    int m_writeTimeOut {1000};  ///< The timeout for writing to the device [msec].
      65              :    int m_readTimeOut {1000}; ///< The timeout for reading from the device [msec].
      66              : 
      67              :    double m_acceleration {100};
      68              :    double m_deceleration {50};
      69              :    double m_motorSpeed {3000};
      70              : 
      71              :    long m_circleSteps {0}; ///< The number of position counts in 1 360-degree revolution.
      72              :    long m_homeOffset {0}; ///< The number of position counts to offset from the home position
      73              : 
      74              : 
      75              : 
      76              :    ///@}
      77              : 
      78              :    /** \name Status
      79              :      * @{
      80              :      */
      81              : 
      82              :    bool m_switch{false}; ///< The home switch status
      83              : 
      84              :    long m_rawPos {0}; ///< The position of the wheel in motor counts.
      85              : 
      86              :    int m_homingState{0}; ///< The homing state, tracks the stages of homing.
      87              :    ///@}
      88              : 
      89              : 
      90              : public:
      91              : 
      92              :    /// Default c'tor.
      93              :    filterWheelCtrl();
      94              : 
      95              :    /// D'tor, declared and defined for noexcept.
      96            0 :    ~filterWheelCtrl() noexcept
      97            0 :    {}
      98              : 
      99              :    /// Setup the configuration system (called by MagAOXApp::setup())
     100              :    virtual void setupConfig();
     101              : 
     102              :    /// load the configuration system results (called by MagAOXApp::setup())
     103              :    virtual void loadConfig();
     104              : 
     105              :    /// Startup functions
     106              :    /** Setsup the INDI vars.
     107              :      *
     108              :      * \returns 0 on success
     109              :      * \returns -1 on error.
     110              :      */
     111              :    virtual int appStartup();
     112              : 
     113              :    /// Implementation of the FSM for the TTM Modulator
     114              :    /**
     115              :      * \returns 0 on success
     116              :      * \returns -1 on error.
     117              :      */
     118              :    virtual int appLogic();
     119              : 
     120              :    /// Do any needed shutdown tasks.  Currently nothing in this app.
     121              :    /**
     122              :      * \returns 0 on success
     123              :      * \returns -1 on error.
     124              :      */
     125              :    virtual int appShutdown();
     126              : 
     127              : 
     128              :    /// This method is called when the change to poweroff is detected.
     129              :    /**
     130              :      * \returns 0 on success.
     131              :      * \returns -1 on any error which means the app should exit.
     132              :      */
     133              :    virtual int onPowerOff();
     134              : 
     135              :    /// This method is called while the power is off, once per FSM loop.
     136              :    /**
     137              :      * \returns 0 on success.
     138              :      * \returns -1 on any error which means the app should exit.
     139              :      */
     140              :    virtual int whilePowerOff();
     141              : 
     142              : protected:
     143              : 
     144              :    //declare our properties
     145              : 
     146              :    ///The position of the wheel in counts
     147              :    pcf::IndiProperty m_indiP_counts;
     148              : 
     149              : public:
     150            0 :    INDI_NEWCALLBACK_DECL(filterWheelCtrl, m_indiP_counts);
     151              : 
     152              : protected:
     153              :    //Each of these should have m_indiMutex locked before being called.
     154              : 
     155              :    /// Set up the MCBL controller, called after each power-on/connection
     156              :    /**
     157              :      * \returns 0 on success.
     158              :      * \returns -1 on error.
     159              :      */
     160              :    int onPowerOnConnect();
     161              : 
     162              :    /// Get the home switch status, sets m_switch to true or false.
     163              :    /**
     164              :      * \returns 0 on success.
     165              :      * \returns -1 on error.
     166              :      */
     167              :    int getSwitch();
     168              : 
     169              :    /// Get the moving-state of the wheel, sets m_moving to true or false.
     170              :    /**
     171              :      * \returns 0 on success.
     172              :      * \returns -1 on error.
     173              :      */
     174              :    int getMoving();
     175              : 
     176              :    /// Get the current position of the wheel, sets m_rawPos to the current motor counts.
     177              :    /**
     178              :      * \returns 0 on success.
     179              :      * \returns -1 on error.
     180              :      */
     181              :    int getPos();
     182              : 
     183              :    /// Start a high-level homing sequence.
     184              :    /** For this device this includes the homing dither.
     185              :      *
     186              :      * \returns 0 on success.
     187              :      * \returns -1 on error.
     188              :      */
     189              :    int startHoming();
     190              : 
     191              :    int presetNumber();
     192              : 
     193              :    /// Start a low-level homing sequence.
     194              :    /** This initiates the device homing sequence.
     195              :      *
     196              :      * \returns 0 on success.
     197              :      * \returns -1 on error.
     198              :      */
     199              :    int home();
     200              : 
     201              :    /// Stop the wheel motion immediately.
     202              :    /**
     203              :      * \returns 0 on success.
     204              :      * \returns -1 on error.
     205              :      */
     206              :    int stop();
     207              : 
     208              :    /// Move to an absolute position in raw counts.
     209              :    /**
     210              :      * \returns 0 on success.
     211              :      * \returns -1 on error.
     212              :      */
     213              :    int moveToRaw( const long & counts /**< [in] The new position in absolute motor counts*/);
     214              : 
     215              :    /// Move to a new position relative to current, in raw counts.
     216              :    /**
     217              :      * \returns 0 on success.
     218              :      * \returns -1 on error.
     219              :      */
     220              :    int moveToRawRelative( const long & counts /**< [in] The new position in relative motor counts*/ );
     221              : 
     222              :    /// Move to an absolute position in filter units.
     223              :    /**
     224              :      * \returns 0 on success.
     225              :      * \returns -1 on error.
     226              :      */
     227              :    int moveTo( const double & filters /**< [in] The new position in absolute filter units*/ );
     228              : 
     229              :    /** \name Telemeter Interface
     230              :      *
     231              :      * @{
     232              :      */
     233              :    int checkRecordTimes();
     234              : 
     235              :    int recordTelem( const telem_stage * );
     236              : 
     237              :    int recordTelem( const telem_position * );
     238              : 
     239              :    int recordStage( bool force = false );
     240              : 
     241              :    int recordPosition( bool force = false );
     242              : 
     243              :    ///@}
     244              : };
     245              : 
     246              : inline
     247              : filterWheelCtrl::filterWheelCtrl() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
     248              : {
     249              :    m_presetNotation = "filter"; //sets the name of the configs, etc.
     250              : 
     251              :    m_powerMgtEnabled = true;
     252              : 
     253              :    return;
     254              : }
     255              : 
     256              : inline
     257            0 : void filterWheelCtrl::setupConfig()
     258              : {
     259            0 :    tty::usbDevice::setupConfig(config);
     260              : 
     261            0 :    config.add("timeouts.write", "", "timeouts.write", argType::Required, "timeouts", "write", false, "int", "The timeout for writing to the device [msec]. Default = 1000");
     262            0 :    config.add("timeouts.read", "", "timeouts.read", argType::Required, "timeouts", "read", false, "int", "The timeout for reading the device [msec]. Default = 1000");
     263              : 
     264            0 :    config.add("motor.acceleration", "", "motor.acceleration", argType::Required, "motor", "acceleration", false, "real", "The motor acceleration parameter. Default=100.");
     265            0 :    config.add("motor.deceleration", "", "motor.deceleration", argType::Required, "motor", "deceleration", false, "real", "The motor deceleration parameter. Default=50.");
     266            0 :    config.add("motor.speed", "", "motor.speed", argType::Required, "motor", "speed", false, "real", "The motor speed parameter.  Default=3000.");
     267            0 :    config.add("motor.circleSteps", "", "motor.circleSteps", argType::Required, "motor", "circleSteps", false, "long", "The number of steps in 1 revolution.");
     268            0 :    config.add("stage.homeOffset", "", "stage.homeOffset", argType::Required, "stage", "homeOffset", false, "long", "The homing offset in motor counts.");
     269              : 
     270            0 :    dev::stdMotionStage<filterWheelCtrl>::setupConfig(config);
     271              : 
     272            0 :    dev::telemeter<filterWheelCtrl>::setupConfig(config);
     273            0 : }
     274              : 
     275              : inline
     276            0 : void filterWheelCtrl::loadConfig()
     277              : {
     278            0 :    this->m_baudRate = B9600; //default for MCBL controller.  Will be overridden by any config setting.
     279              : 
     280            0 :    int rv = tty::usbDevice::loadConfig(config);
     281              : 
     282            0 :    if(rv != 0 && rv != TTY_E_NODEVNAMES && rv != TTY_E_DEVNOTFOUND) //Ignore error if not plugged in
     283              :    {
     284            0 :       log<software_error>( {__FILE__, __LINE__, rv, tty::ttyErrorString(rv)});
     285              :    }
     286              : 
     287            0 :    config(m_writeTimeOut, "timeouts.write");
     288            0 :    config(m_readTimeOut, "timeouts.read");
     289              : 
     290            0 :    config(m_acceleration, "motor.acceleration");
     291            0 :    config(m_deceleration, "motor.deceleration");
     292            0 :    config(m_motorSpeed, "motor.speed");
     293            0 :    config(m_circleSteps, "motor.circleSteps");
     294            0 :    config(m_homeOffset, "stage.homeOffset");
     295              : 
     296              : 
     297            0 :    dev::stdMotionStage<filterWheelCtrl>::loadConfig(config);
     298              : 
     299            0 :    dev::telemeter<filterWheelCtrl>::loadConfig(config);
     300            0 : }
     301              : 
     302              : inline
     303            0 : int filterWheelCtrl::appStartup()
     304              : {
     305            0 :    if( state() == stateCodes::UNINITIALIZED )
     306              :    {
     307            0 :       log<text_log>( "In appStartup but in state UNINITIALIZED.", logPrio::LOG_CRITICAL );
     308            0 :       return -1;
     309              :    }
     310              : 
     311              :    // set up the  INDI properties
     312            0 :    createStandardIndiNumber<long>( m_indiP_counts, "counts", std::numeric_limits<long>::lowest(), std::numeric_limits<long>::max(), 0.0, "%ld");
     313            0 :    registerIndiPropertyNew( m_indiP_counts, INDI_NEWCALLBACK(m_indiP_counts)) ;
     314              : 
     315              : 
     316            0 :    dev::stdMotionStage<filterWheelCtrl>::appStartup();
     317              : 
     318            0 :    if(dev::telemeter<filterWheelCtrl>::appStartup() < 0)
     319              :    {
     320            0 :       return log<software_error,-1>({__FILE__,__LINE__});
     321              :    }
     322              : 
     323            0 :    return 0;
     324              : }
     325              : 
     326              : inline
     327            0 : int filterWheelCtrl::appLogic()
     328              : {
     329            0 :    if( state() == stateCodes::INITIALIZED )
     330              :    {
     331            0 :       log<text_log>( "In appLogic but in state INITIALIZED.", logPrio::LOG_CRITICAL );
     332            0 :       return -1;
     333              :    }
     334              : 
     335            0 :    if( state() == stateCodes::POWERON )
     336              :    {
     337            0 :       if(m_deviceName == "") state(stateCodes::NODEVICE);
     338              :       else
     339              :       {
     340            0 :          state(stateCodes::NOTCONNECTED);
     341            0 :          std::stringstream logs;
     342            0 :          logs << "USB Device " << m_idVendor << ":" << m_idProduct << ":" << m_serial << " found in udev as " << m_deviceName;
     343            0 :          log<text_log>(logs.str());
     344            0 :       }
     345              :    }
     346              : 
     347            0 :    if( state() == stateCodes::NODEVICE )
     348              :    {
     349            0 :       int rv = tty::usbDevice::getDeviceName();
     350            0 :       if(rv < 0 && rv != TTY_E_DEVNOTFOUND && rv != TTY_E_NODEVNAMES)
     351              :       {
     352            0 :          state(stateCodes::FAILURE);
     353            0 :          if(!stateLogged())
     354              :          {
     355            0 :             log<software_critical>({__FILE__, __LINE__, rv, tty::ttyErrorString(rv)});
     356              :          }
     357            0 :          return -1;
     358              :       }
     359              : 
     360            0 :       if(rv == TTY_E_DEVNOTFOUND || rv == TTY_E_NODEVNAMES)
     361              :       {
     362            0 :          state(stateCodes::NODEVICE);
     363              : 
     364            0 :          if(!stateLogged())
     365              :          {
     366            0 :             std::stringstream logs;
     367            0 :             logs << "USB Device " << m_idVendor << ":" << m_idProduct << ":" << m_serial << " not found in udev";
     368            0 :             log<text_log>(logs.str());
     369            0 :          }
     370            0 :          return 0;
     371              :       }
     372              :       else
     373              :       {
     374            0 :          state(stateCodes::NOTCONNECTED);
     375            0 :          if(!stateLogged())
     376              :          {
     377            0 :             std::stringstream logs;
     378            0 :             logs << "USB Device " << m_idVendor << ":" << m_idProduct << ":" << m_serial << " found in udev as " << m_deviceName;
     379            0 :             log<text_log>(logs.str());
     380            0 :          }
     381              :       }
     382              :    }
     383              : 
     384            0 :    if( state() == stateCodes::NOTCONNECTED )
     385              :    {
     386              :       int rv;
     387              :       {
     388            0 :          elevatedPrivileges elPriv(this);
     389            0 :          rv = connect();
     390            0 :       }
     391              : 
     392            0 :       if(rv < 0)
     393              :       {
     394            0 :          int nrv = tty::usbDevice::getDeviceName();
     395            0 :          if(nrv < 0 && nrv != TTY_E_DEVNOTFOUND && nrv != TTY_E_NODEVNAMES)
     396              :          {
     397            0 :             state(stateCodes::FAILURE);
     398            0 :             if(!stateLogged()) log<software_critical>({__FILE__, __LINE__, nrv, tty::ttyErrorString(nrv)});
     399            0 :             return -1;
     400              :          }
     401              : 
     402            0 :          if(nrv == TTY_E_DEVNOTFOUND || nrv == TTY_E_NODEVNAMES)
     403              :          {
     404            0 :             state(stateCodes::NODEVICE);
     405              : 
     406            0 :             if(!stateLogged())
     407              :             {
     408            0 :                std::stringstream logs;
     409            0 :                logs << "USB Device " << m_idVendor << ":" << m_idProduct << ":" << m_serial << " no longer found in udev";
     410            0 :                log<text_log>(logs.str());
     411            0 :             }
     412            0 :             return 0;
     413              :          }
     414              : 
     415              :          //if connect failed, and there is a device, then we have some other problem.
     416            0 :          sleep(1); //wait to see if power state updates
     417            0 :          if(m_powerState == 0) return 0;
     418              : 
     419              :          //Ok we can't figure this out, die.
     420            0 :          state(stateCodes::FAILURE);
     421            0 :          if(!stateLogged()) log<software_error>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
     422            0 :          return -1;
     423              : 
     424              :       }
     425              : 
     426              : 
     427              : 
     428            0 :       if( getPos() == 0 ) state(stateCodes::CONNECTED);
     429              :       else
     430              :       {
     431            0 :          return 0;
     432              :       }
     433              : 
     434            0 :       if(state() == stateCodes::CONNECTED)
     435              :       {
     436            0 :          std::stringstream logs;
     437            0 :          logs << "Connected to filter wheel on " << m_deviceName;
     438            0 :          log<text_log>(logs.str());
     439            0 :       }
     440              : 
     441              :    }
     442              : 
     443            0 :    if( state() == stateCodes::CONNECTED )
     444              :    {
     445            0 :       int rv = onPowerOnConnect();
     446              : 
     447            0 :       if(rv < 0)
     448              :       {
     449            0 :          log<software_error>({__FILE__,__LINE__});
     450            0 :          state(stateCodes::ERROR);
     451              : 
     452            0 :          return 0;
     453              :       }
     454              : 
     455            0 :       std::string landfill;
     456            0 :       tty::ttyRead(landfill, "\r", m_fileDescrip, m_readTimeOut); //read to timeout to kill any missed chars.
     457              : 
     458            0 :       if(m_powerOnHome)
     459              :       {
     460            0 :          std::lock_guard<std::mutex> guard(m_indiMutex);
     461              : 
     462            0 :          if(startHoming()<0)
     463              :          {
     464            0 :             state(stateCodes::ERROR);
     465            0 :             log<software_error>({__FILE__,__LINE__});
     466            0 :             return 0;
     467              :          }
     468            0 :       }
     469            0 :       else state(stateCodes::NOTHOMED);
     470              : 
     471              : 
     472            0 :    }
     473              : 
     474            0 :    if( state() == stateCodes::NOTHOMED || state() == stateCodes::READY || state() == stateCodes::OPERATING || state() == stateCodes::HOMING)
     475              :    {
     476              :       { //mutex scope
     477              :          //Make sure we have exclusive attention of the device
     478            0 :          std::lock_guard<std::mutex> guard(m_indiMutex);  //Lock the mutex before conducting any communications.
     479              : 
     480            0 :          int rv = getSwitch();
     481              : 
     482            0 :          if(rv  != 0 )
     483              :          {
     484            0 :             state(stateCodes::NOTCONNECTED);
     485            0 :             return 0;
     486              :          }
     487              : 
     488            0 :          rv = getMoving();
     489              : 
     490            0 :          if(rv  != 0 )
     491              :          {
     492            0 :             state(stateCodes::NOTCONNECTED);
     493            0 :             return 0;
     494              :          }
     495              : 
     496            0 :          rv = getPos();
     497              : 
     498            0 :          if(rv  != 0 )
     499              :          {
     500            0 :             state(stateCodes::NOTCONNECTED);
     501            0 :             return 0;
     502              :          }
     503              : 
     504            0 :          recordPosition();
     505            0 :       }
     506              : 
     507            0 :       if(m_moving)
     508              :       {
     509              :          //Started moving but we don't know yet.
     510            0 :          if(state() == stateCodes::READY) state(stateCodes::OPERATING);
     511              :       }
     512              :       else
     513              :       {
     514            0 :          if(state() == stateCodes::OPERATING)
     515              :          {
     516            0 :             if(m_movingState == 1)
     517              :             {
     518            0 :                std::lock_guard<std::mutex> guard(m_indiMutex);
     519            0 :                if(moveToRawRelative(-20000) < 0)
     520              :                {
     521            0 :                   sleep(1);
     522            0 :                   if(m_powerState == 0) return 0;
     523              : 
     524            0 :                   state(stateCodes::ERROR);
     525            0 :                   return log<software_error,0>({__FILE__,__LINE__});
     526              :                }
     527              : 
     528            0 :                m_movingState=2;
     529            0 :             }
     530            0 :             else if(m_movingState == 2)
     531              :             {
     532            0 :                std::lock_guard<std::mutex> guard(m_indiMutex);
     533            0 :                if(moveTo(m_preset_target) < 0)
     534              :                {
     535            0 :                   sleep(1);
     536            0 :                   if(m_powerState == 0) return 0;
     537              : 
     538            0 :                   state(stateCodes::ERROR);
     539            0 :                   return log<software_error,0>({__FILE__,__LINE__});
     540              :                }
     541              : 
     542            0 :                m_movingState=3;
     543            0 :             }
     544              :             else
     545              :             {
     546            0 :                m_movingState = 0;
     547            0 :                state(stateCodes::READY); //stopped moving but was just changing pos
     548              :             }
     549              : 
     550              :          }
     551            0 :          else if (state() == stateCodes::HOMING) //stopped moving but was in the homing sequence
     552              :          {
     553            0 :             if(m_homingState == 1)
     554              :             {
     555            0 :                std::lock_guard<std::mutex> guard(m_indiMutex);
     556            0 :                if(moveToRawRelative(-50000) < 0)
     557              :                {
     558            0 :                   sleep(1);
     559            0 :                   if(m_powerState == 0) return 0;
     560              : 
     561            0 :                   state(stateCodes::ERROR);
     562            0 :                   return log<software_error,0>({__FILE__,__LINE__});
     563              :                }
     564              : 
     565            0 :                m_homingState=2;
     566            0 :             }
     567            0 :             else if (m_homingState == 2)
     568              :             {
     569            0 :                std::lock_guard<std::mutex> guard(m_indiMutex);
     570            0 :                if(home()<0)
     571              :                {
     572            0 :                   sleep(1);
     573            0 :                   if(m_powerState == 0) return 0;
     574              : 
     575            0 :                   state(stateCodes::ERROR);
     576            0 :                   return log<software_error,0>({__FILE__,__LINE__});
     577              :                }
     578            0 :                m_homingState = 3;
     579            0 :             }
     580            0 :             else if(m_homingState == 3)
     581              :             {
     582            0 :                std::lock_guard<std::mutex> guard(m_indiMutex);
     583            0 :                if(moveToRaw(m_homeOffset)<0)
     584              :                {
     585            0 :                   sleep(1);
     586            0 :                   if(m_powerState == 0) return 0;
     587              : 
     588            0 :                   state(stateCodes::ERROR);
     589            0 :                   return log<software_error,0>({__FILE__,__LINE__});
     590              :                }
     591            0 :                m_homingState=4;
     592            0 :             }
     593            0 :             else if(m_homingState == 4)
     594              :             {
     595            0 :                if(m_homePreset >= 0)
     596              :                {
     597            0 :                   m_preset_target = m_presetPositions[m_homePreset];
     598            0 :                   updateIfChanged(m_indiP_preset, "target",  m_preset_target, INDI_BUSY);
     599              : 
     600            0 :                   moveTo(m_preset_target);
     601              :                }
     602            0 :                m_homingState = 5;
     603              :             }
     604              :             else
     605              :             {
     606            0 :                m_homingState = 0;
     607            0 :                state(stateCodes::READY);
     608              : 
     609            0 :                m_preset_target = ((double) m_rawPos-m_homeOffset)/m_circleSteps*m_presetNames.size() + 1.0;
     610              :             }
     611              :          }
     612              :       }
     613              : 
     614            0 :       std::lock_guard<std::mutex> guard(m_indiMutex);
     615              : 
     616            0 :       if(m_moving)
     617              :       {
     618            0 :          updateIfChanged(m_indiP_counts, "current", m_rawPos, INDI_BUSY);
     619              :       }
     620              :       else
     621              :       {
     622            0 :          updateIfChanged(m_indiP_counts, "current", m_rawPos, INDI_IDLE);
     623              :       }
     624              : 
     625            0 :       m_preset = ((double) m_rawPos-m_homeOffset)/m_circleSteps*m_presetNames.size() + 1.0;
     626              : 
     627            0 :       stdMotionStage<filterWheelCtrl>::updateINDI();
     628            0 :       recordStage();
     629              : 
     630            0 :       if(telemeter<filterWheelCtrl>::appLogic() < 0)
     631              :       {
     632            0 :          log<software_error>({__FILE__, __LINE__});
     633            0 :          return 0;
     634              :       }
     635              : 
     636            0 :       return 0;
     637            0 :    }
     638              : 
     639            0 :    if(state() == stateCodes::ERROR)
     640              :    {
     641            0 :       sleep(1);
     642            0 :       if(m_powerState == 0) return 0;
     643              : 
     644            0 :       return log<software_error,-1>({__FILE__,__LINE__, "In state ERROR but no recovery implemented.  Terminating."});
     645              :    }
     646              : 
     647            0 :    return log<software_error,-1>({__FILE__,__LINE__, "appLogic fell through.  Terminating."});
     648              : 
     649              : }
     650              : 
     651              : 
     652              : 
     653              : inline
     654            0 : int filterWheelCtrl::appShutdown()
     655              : {
     656              :    //don't bother
     657            0 :    return 0;
     658              : }
     659              : 
     660              : inline
     661            0 : int filterWheelCtrl::onPowerOff()
     662              : {
     663            0 :    if( stdMotionStage<filterWheelCtrl>::onPowerOff() < 0)
     664              :    {
     665            0 :       log<software_error>({__FILE__,__LINE__});
     666              :    }
     667              : 
     668            0 :    recordStage(true);
     669            0 :    recordPosition(true);
     670              : 
     671            0 :    return 0;
     672              : }
     673              : 
     674              : inline
     675            0 : int filterWheelCtrl::whilePowerOff()
     676              : {
     677            0 :    if( stdMotionStage<filterWheelCtrl>::whilePowerOff() < 0)
     678              :    {
     679            0 :       log<software_error>({__FILE__,__LINE__});
     680              :    }
     681              : 
     682              :    //record telem if it's been longer than 10 sec:
     683            0 :    if(telemeter<filterWheelCtrl>::appLogic() < 0)
     684              :    {
     685            0 :       log<software_error>({__FILE__, __LINE__});
     686              :    }
     687              : 
     688            0 :    return 0;
     689              : }
     690              : 
     691            0 : INDI_NEWCALLBACK_DEFN(filterWheelCtrl, m_indiP_counts)(const pcf::IndiProperty &ipRecv)
     692              : {
     693            0 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_counts, ipRecv);
     694              : 
     695            0 :     double counts = -1;
     696            0 :     double target_abs = -1;
     697            0 :     if(ipRecv.find("current"))
     698              :     {
     699            0 :        counts = ipRecv["current"].get<double>();
     700              :     }
     701            0 :     if(ipRecv.find("target"))
     702              :     {
     703            0 :        target_abs = ipRecv["target"].get<double>();
     704              :     }
     705            0 :     if(target_abs == -1) target_abs = counts;
     706              : 
     707              : 
     708            0 :     m_preset_target = ((double) target_abs - m_homeOffset)/m_circleSteps*m_presetNames.size() + 1.0;
     709            0 :     std::lock_guard<std::mutex> guard(m_indiMutex);
     710            0 :     return moveToRaw(target_abs);
     711              : 
     712            0 : }
     713              : 
     714              : 
     715              : 
     716              : 
     717            0 : int filterWheelCtrl::onPowerOnConnect()
     718              : {
     719            0 :    std::string com;
     720              : 
     721              :    int rv;
     722              : 
     723            0 :    std::lock_guard<std::mutex> guard(m_indiMutex);
     724              : 
     725            0 :    rv = tty::ttyWrite( "ANSW0\r", m_fileDescrip, m_writeTimeOut); //turn off replies and asynchronous comms.
     726            0 :    if(rv < 0) return log<software_error,-1>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
     727              : 
     728              :    //Send motor type
     729            0 :    com = "MOTTYP" + std::to_string(m_motorType) + "\r";
     730            0 :    rv = tty::ttyWrite( com, m_fileDescrip, m_writeTimeOut);
     731            0 :    if(rv < 0) return log<software_error,-1>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
     732              : 
     733              :    //Set up acceleration and speed.
     734            0 :    com = "AC" + std::to_string(m_acceleration) + "\r";
     735            0 :    rv = tty::ttyWrite( com, m_fileDescrip, m_writeTimeOut);
     736            0 :    if(rv < 0) return log<software_error,-1>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
     737              : 
     738              :    //Set up acceleration and speed.
     739            0 :    com = "DEC" + std::to_string(m_deceleration) + "\r";
     740            0 :    rv = tty::ttyWrite( com, m_fileDescrip, m_writeTimeOut);
     741            0 :    if(rv < 0) return log<software_error,-1>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
     742              : 
     743            0 :    com = "SP" + std::to_string(m_motorSpeed) + "\r";
     744            0 :    rv = tty::ttyWrite( com, m_fileDescrip,m_writeTimeOut);
     745            0 :    if(rv < 0) return log<software_error,-1>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
     746              : 
     747            0 :    return 0;
     748            0 : }
     749              : 
     750            0 : int filterWheelCtrl::getSwitch()
     751              : {
     752              :    int rv;
     753            0 :    std::string resp;
     754              : 
     755            0 :    rv = tty::ttyWriteRead( resp, "GAST\r", "\r\n", false, m_fileDescrip, m_writeTimeOut, m_readTimeOut);
     756              : 
     757            0 :    if(rv == 0)
     758              :    {
     759              : 
     760            0 :       if(resp == "1011") m_switch=true;
     761            0 :       else m_switch=false;
     762              : 
     763            0 :       return 0;
     764              :    }
     765              : 
     766              : 
     767            0 :    return rv;
     768              : 
     769            0 : }
     770              : 
     771            0 : int filterWheelCtrl::getMoving()
     772              : {
     773              :    int rv;
     774            0 :    std::string resp;
     775              : 
     776            0 :    rv = tty::ttyWriteRead( resp, "GN\r", "\r\n", false, m_fileDescrip, m_writeTimeOut, m_readTimeOut);
     777              : 
     778            0 :    if(rv == 0)
     779              :    {
     780              :       int speed;
     781            0 :       try{ speed = std::stol(resp.c_str());}
     782            0 :       catch(...){speed=0;}
     783              : 
     784            0 :       if(fabs(speed) > 0.1*m_motorSpeed)
     785              :       {
     786            0 :          if(m_homingState) m_moving = 2;
     787            0 :          else m_moving = 1;
     788              :       }
     789            0 :       else m_moving = 0;
     790              : 
     791            0 :       return 0;
     792              :    }
     793              : 
     794              : 
     795            0 :    return rv;
     796              : 
     797            0 : }
     798              : 
     799            0 : int filterWheelCtrl::getPos()
     800              : {
     801              :    int rv;
     802            0 :    std::string resp;
     803              : 
     804            0 :    rv = tty::ttyWriteRead( resp, "POS\r", "\r\n", false, m_fileDescrip, m_writeTimeOut, m_readTimeOut);
     805              : 
     806            0 :    if(rv == 0)
     807              :    {
     808            0 :       try{ m_rawPos = std::stol(resp.c_str());}
     809            0 :       catch(...){m_rawPos=0;}
     810              :    }
     811              : 
     812              : 
     813            0 :    return rv;
     814              : 
     815            0 : }
     816              : 
     817            0 : int filterWheelCtrl::startHoming()
     818              : {
     819            0 :    m_homingState = 1;
     820            0 :    m_moving = 2;
     821            0 :    recordStage(true);
     822            0 :    recordPosition(true);
     823              : 
     824            0 :    updateSwitchIfChanged(m_indiP_home, "request", pcf::IndiElement::Off, INDI_IDLE);
     825            0 :    return home();
     826              : }
     827              : 
     828            0 : int filterWheelCtrl::presetNumber()
     829              : {
     830              :    //First we calculate current preset name
     831            0 :    int n = floor(m_preset + 0.5) - 1;
     832            0 :    if(n < 0)
     833              :    {
     834            0 :       while(n < 0) n += m_presetNames.size();
     835              :    }
     836            0 :    if( n > (long) m_presetNames.size()-1 )
     837              :    {
     838            0 :       while( n > (long) m_presetNames.size()-1 ) n -= m_presetNames.size();
     839              :    }
     840              : 
     841            0 :    if( n < 0)
     842              :    {
     843            0 :       log<software_error>({__FILE__,__LINE__, "error calculating " + m_presetNotation + " index, n < 0"});
     844            0 :       return -1;
     845              :    }
     846              : 
     847            0 :    return n;
     848              : }
     849              : 
     850            0 : int filterWheelCtrl::home()
     851              : {
     852              : 
     853            0 :    state(stateCodes::HOMING);
     854              : 
     855              :    int rv;
     856              : 
     857            0 :    rv = tty::ttyWrite( "EN\r", m_fileDescrip, m_writeTimeOut);
     858            0 :    if(rv < 0) return log<software_error,-1>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
     859              : 
     860            0 :    rv = tty::ttyWrite( "HA4\r", m_fileDescrip, m_writeTimeOut);
     861            0 :    if(rv < 0) return log<software_error,-1>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
     862              : 
     863            0 :    rv = tty::ttyWrite( "HL4\r", m_fileDescrip, m_writeTimeOut);
     864            0 :    if(rv < 0) return log<software_error,-1>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
     865              : 
     866            0 :    rv = tty::ttyWrite( "CAHOSEQ\r", m_fileDescrip, m_writeTimeOut);
     867            0 :    if(rv < 0) return log<software_error,-1>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
     868              : 
     869            0 :    rv = tty::ttyWrite( "HP0\r", m_fileDescrip, m_writeTimeOut);
     870            0 :    if(rv < 0) return log<software_error,-1>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
     871              : 
     872            0 :    std::string com = "HOSP" + std::to_string(m_motorSpeed) + "\r";
     873            0 :    rv = tty::ttyWrite( com, m_fileDescrip, m_writeTimeOut);
     874            0 :    if(rv < 0) return log<software_error,-1>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
     875              : 
     876            0 :    rv = tty::ttyWrite( "GOHOSEQ\r", m_fileDescrip, m_writeTimeOut);
     877            0 :    if(rv < 0) return log<software_error,-1>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
     878              : 
     879              : 
     880              : 
     881            0 :    return 0;
     882            0 : }
     883              : 
     884            0 : int filterWheelCtrl::stop()
     885              : {
     886            0 :    m_homingState = 0;
     887              :    //First try without locking
     888            0 :    tty::ttyWrite( "DI\r", m_fileDescrip, m_writeTimeOut);
     889              : 
     890              :    //Now make sure it goes through
     891            0 :    std::lock_guard<std::mutex> guard(m_indiMutex);
     892            0 :    int rv = tty::ttyWrite( "DI\r", m_fileDescrip, m_writeTimeOut);
     893              : 
     894            0 :    updateSwitchIfChanged(m_indiP_stop, "request", pcf::IndiElement::Off, INDI_IDLE);
     895              : 
     896            0 :    if(rv < 0) return log<software_error,-1>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
     897              : 
     898            0 :    return 0;
     899            0 : }
     900              : 
     901            0 : int filterWheelCtrl::moveToRaw( const long & counts )
     902              : {
     903              : 
     904            0 :    std::string com;
     905              :    int rv;
     906              : 
     907            0 :    m_moving = 1;
     908            0 :    recordStage(true);
     909            0 :    recordPosition(true);
     910              : 
     911            0 :    rv = tty::ttyWrite( "EN\r", m_fileDescrip, m_writeTimeOut);
     912            0 :    if(rv < 0) return log<software_error,-1>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
     913              : 
     914            0 :    com = "LA" + std::to_string(counts) + "\r";
     915            0 :    rv = tty::ttyWrite( com, m_fileDescrip, m_writeTimeOut);
     916            0 :    if(rv < 0) return log<software_error,-1>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
     917              : 
     918            0 :    rv = tty::ttyWrite( "M\r", m_fileDescrip, m_writeTimeOut);
     919            0 :    if(rv < 0) return log<software_error,-1>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
     920              : 
     921            0 :    updateIfChanged(m_indiP_counts, "target", counts, pcf::IndiProperty::Busy);
     922              : 
     923            0 :    return 0;
     924            0 : }
     925              : 
     926            0 : int filterWheelCtrl::moveToRawRelative( const long & counts_relative )
     927              : {
     928              : 
     929            0 :    std::string com;
     930              :    int rv;
     931              : 
     932            0 :    m_moving = 1;
     933            0 :    recordStage(true);
     934            0 :    recordPosition(true);
     935              : 
     936            0 :    rv = tty::ttyWrite( "EN\r", m_fileDescrip, m_writeTimeOut);
     937            0 :    if(rv < 0) return log<software_error,-1>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
     938              : 
     939            0 :    com = "LR" + std::to_string(counts_relative) +"\r";
     940            0 :    rv = tty::ttyWrite( com, m_fileDescrip, m_writeTimeOut);
     941            0 :    if(rv < 0) return log<software_error,-1>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
     942              : 
     943            0 :    rv = tty::ttyWrite( "M\r", m_fileDescrip, m_writeTimeOut);
     944            0 :    if(rv < 0) return log<software_error,-1>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
     945              : 
     946              : 
     947              : 
     948            0 :    return 0;
     949            0 : }
     950              : 
     951            0 : int filterWheelCtrl::moveTo( const double & filters )
     952              : {
     953              :    long counts;
     954              : 
     955            0 :    if(m_circleSteps ==0 || m_presetNames.size() == 0) counts = filters;
     956            0 :    else counts = m_homeOffset + m_circleSteps/m_presetNames.size() * (filters-1);
     957              : 
     958            0 :    return moveToRaw(counts);
     959              : 
     960              : }
     961              : 
     962            0 : int filterWheelCtrl::checkRecordTimes()
     963              : {
     964            0 :    return dev::telemeter<filterWheelCtrl>::checkRecordTimes(telem_stage(), telem_position());
     965              : }
     966              : 
     967            0 : int filterWheelCtrl::recordTelem( const telem_stage * )
     968              : {
     969            0 :    return recordStage(true);
     970              : }
     971              : 
     972            0 : int filterWheelCtrl::recordTelem( const telem_position * )
     973              : {
     974            0 :    return recordPosition(true);
     975              : }
     976              : 
     977            0 : int filterWheelCtrl::recordStage(bool force)
     978              : {
     979            0 :    return dev::stdMotionStage<filterWheelCtrl>::recordStage(force);
     980              : }
     981              : 
     982            0 : int filterWheelCtrl::recordPosition(bool force)
     983              : {
     984              :    static long last_pos = 999999999999;
     985              : 
     986            0 :    if( m_rawPos != last_pos || force )
     987              :    {
     988            0 :       float fpos = m_rawPos;
     989              : 
     990            0 :       telem<telem_position>(fpos);
     991              : 
     992            0 :       last_pos = m_rawPos;
     993              :    }
     994              : 
     995            0 :    return 0;
     996              : }
     997              : 
     998              : } //namespace app
     999              : } //namespace MagAOX
    1000              : 
    1001              : #endif //filterWheelCtrl_hpp
        

Generated by: LCOV version 2.0-1