LCOV - code coverage report
Current view: top level - apps/filterWheelCtrl - filterWheelCtrl.hpp (source / functions) Coverage Total Hit
Test: MagAOX Lines: 1.6 % 435 7
Test Date: 2026-04-15 19:34:29 Functions: 7.4 % 27 2

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

Generated by: LCOV version 2.0-1