LCOV - code coverage report
Current view: top level - libMagAOX/app/dev - dssShutter.hpp (source / functions) Coverage Total Hit
Test: MagAOX Lines: 35.0 % 220 77
Test Date: 2026-04-15 19:34:29 Functions: 63.6 % 22 14

            Line data    Source code
       1              : /** \file dssShutter.hpp
       2              :   * \brief Uniblitz DSS shutter interface
       3              :   *
       4              :   * \author Jared R. Males (jaredmales@gmail.com)
       5              :   *
       6              :   * \ingroup app_files
       7              :   */
       8              : 
       9              : #ifndef dssShutter_hpp
      10              : #define dssShutter_hpp
      11              : 
      12              : 
      13              : namespace MagAOX
      14              : {
      15              : namespace app
      16              : {
      17              : namespace dev
      18              : {
      19              : 
      20              : /// MagAO-X Uniblitz DSS Shutter interface
      21              : /** This is actually an interface to the digital I/O system, which controls the shutter.
      22              :   *
      23              :   * The derived class `derivedT` must be a MagAOXApp\<true\>, and should declare this class a friend like so:
      24              :    \code
      25              :     friend class dev::dssShutter<derivedT>;
      26              :    \endcode
      27              :   *
      28              :   *
      29              :   * Calls to this class's `setupConfig`, `loadConfig`, `appStartup`, `appLogic`, `appShutdown`
      30              :   * `onPowerOff`, `whilePowerOff`, functions must be placed in the derived class's functions of the same name.
      31              :   *
      32              :   *
      33              :   * \ingroup appdev
      34              :   */
      35              : template<class derivedT>
      36              : class dssShutter
      37              : {
      38              : protected:
      39              : 
      40              :    /** \name Configurable Parameters
      41              :     * @{
      42              :     */
      43              : 
      44              :    std::string m_powerDevice;    ///< The device controlling this shutter's power
      45              :    std::string m_powerChannel;   ///< The channel controlling this shutter's power
      46              : 
      47              :    std::string m_dioDevice;      ///< The device controlling this shutter's digital I/O.
      48              :    std::string m_sensorChannel;  ///< The channel reading this shutter's sensor
      49              :    std::string m_triggerChannel; ///< The channel sending this shutter's trigger
      50              : 
      51              :    unsigned m_shutterWait {100};  ///< The time to pause between checks of the sensor state during open/shut [msec]. Default is 100.
      52              : 
      53              :    unsigned m_shutterTimeout {2000}; ///< Total time to wait for sensor to change state before timing out [msec]. Default is 2000.
      54              :    ///@}
      55              : 
      56              :    int m_powerState {-1};  ///< The current power state, -1 is unknown, 0 is off, 1 is on.
      57              : 
      58              :    int m_sensorState {-1}; ///< The current sensor state, -1 is unknown, 0 is shut, 1 is open.
      59              : 
      60              :    int m_triggerState {-1}; ///< The current trigger state.  -1 is unknown, 0 is low, 1 is high.
      61              : 
      62              : public:
      63              : 
      64              :    /// Default c'tor
      65              :    /**
      66              :      * Sets derived().m_hasShutter to true.
      67              :      */
      68              :    dssShutter();
      69              : 
      70              :    /// Setup the configuration system
      71              :    /**
      72              :      * This should be called in `derivedT::setupConfig` as
      73              :      * \code
      74              :        dssShutter<derivedT>::setupConfig(config);
      75              :        \endcode
      76              :      * with appropriate error checking.
      77              :      */
      78              :    void setupConfig(mx::app::appConfigurator & config /**< [out] the derived classes configurator*/);
      79              : 
      80              :    /// load the configuration system results
      81              :    /**
      82              :      * This should be called in `derivedT::loadConfig` as
      83              :      * \code
      84              :        dssShutter<derivedT>::loadConfig(config);
      85              :        \endcode
      86              :      * with appropriate error checking.
      87              :      */
      88              :    void loadConfig(mx::app::appConfigurator & config /**< [in] the derived classes configurator*/);
      89              : 
      90              :    /// Startup function
      91              :    /**
      92              :      * This should be called in `derivedT::appStartup` as
      93              :      * \code
      94              :        dssShutter<derivedT>::appStartup();
      95              :        \endcode
      96              :      * with appropriate error checking.
      97              :      *
      98              :      * \returns 0 on success
      99              :      * \returns -1 on error, which is logged.
     100              :      */
     101              :    int appStartup();
     102              : 
     103              :    /// application logic
     104              :    /** This should be called in `derivedT::appLogic` as
     105              :      * \code
     106              :        dssShutter<derivedT>::appLogic();
     107              :        \endcode
     108              :      * with appropriate error checking.
     109              :      *
     110              :      * \returns 0 on success
     111              :      * \returns -1 on error, which is logged.
     112              :      */
     113              :    int appLogic();
     114              : 
     115              :    /// applogic shutdown
     116              :    /** This should be called in `derivedT::appShutdown` as
     117              :      * \code
     118              :        dssShutter<derivedT>::appShutdown();
     119              :        \endcode
     120              :      * with appropriate error checking.
     121              :      *
     122              :      * \returns 0 on success
     123              :      * \returns -1 on error, which is logged.
     124              :      */
     125              :    int appShutdown();
     126              : 
     127              :    /// Actions on power off
     128              :    /** This should be called in `derivedT::appPowerOff` as
     129              :      * \code
     130              :        dssShutter<derivedT>::appPowerOff();
     131              :        \endcode
     132              :      * with appropriate error checking.
     133              :      *
     134              :      * \returns 0 on success
     135              :      * \returns -1 on error, which is logged.
     136              :      */
     137              :    int onPowerOff();
     138              : 
     139              :    /// Actions while powered off
     140              :    /** This should be called in `derivedT::whilePowerOff` as
     141              :      * \code
     142              :        dssShutter<derivedT>::whilePowerOff();
     143              :        \endcode
     144              :      * with appropriate error checking.
     145              :      *
     146              :      * \returns 0 on success
     147              :      * \returns -1 on error, which is logged.
     148              :      */
     149              :    int whilePowerOff();
     150              : 
     151              :    /// Change shutter state
     152              :    /** Sets m_doOpen or m_doShut and signals the appropriate thread.
     153              :      * \returns 0 on success
     154              :      * \returns -1 on error
     155              :      */
     156              :    int setShutterState( int sh /**< Desired shutter state. 0 for shut,1 for open*/);
     157              : 
     158              :    /// Open the shutter
     159              :    /** Do not lock the mutex before calling this.
     160              :      *
     161              :      * \returns 0 on success
     162              :      * \returns -1 on error
     163              :      */
     164              :    int open();
     165              : 
     166              :    /// Shut the shutter
     167              :    /** Do not lock the mutex before calling this.
     168              :      *
     169              :      * \returns 0 on success
     170              :      * \returns -1 on error
     171              :      */
     172              :    int shut();
     173              : 
     174              : protected:
     175              : 
     176              :    /** \name Open/Shut Threads
     177              :      *
     178              :      * Separate threads are used since we need INDI updates while trying to open/shut.
     179              :      * These threads sleep(1), unless interrupted by a signal.  When signaled, they check
     180              :      * for the m_doOpen or m_doShut flag, and if true the appropriate open() or shut()
     181              :      * function is called.  If not, they go back to sleep unless m_shutdown is true.
     182              :      *
     183              :      * @{
     184              :      */
     185              : 
     186              :    bool m_doOpen {false}; ///< Flag telling the open thread that it should actually open the shutter, not just go back to sleep.
     187              : 
     188              :    bool m_openThreadInit {true}; ///< Initialization flag for the open thread.
     189              : 
     190              :    pid_t m_openThreadID {0}; ///< Open thread PID.
     191              : 
     192              :    pcf::IndiProperty m_openThreadProp; ///< The property to hold the open thread details.
     193              : 
     194              :    std::thread m_openThread; ///< The opening thread.
     195              : 
     196              :    /// Open thread starter function
     197              :    static void openThreadStart( dssShutter * d /**< [in] pointer to this */);
     198              : 
     199              :    /// Open thread function
     200              :    /** Runs until m_shutdown is true.
     201              :      */
     202              :    void openThreadExec();
     203              : 
     204              :    bool m_doShut {false}; ///< Flag telling the shut thread that it should actually shut the shutter, not just go back to sleep.
     205              : 
     206              :    bool m_shutThreadInit {true}; ///< Initialization flag for the shut thread.
     207              : 
     208              :    pid_t m_shutThreadID {0}; ///< Shut thread PID.
     209              : 
     210              :    pcf::IndiProperty m_shutThreadProp; ///< The property to hold the shut thread details.
     211              : 
     212              :    std::thread m_shutThread; ///< The shutting thread
     213              : 
     214              :    /// Shut thread starter function.
     215              :    static void shutThreadStart( dssShutter * d /**< [in] pointer to this */);
     216              : 
     217              :    /// Shut thread function
     218              :    /** Runs until m_shutdown is true.
     219              :      */
     220              :    void shutThreadExec();
     221              : 
     222              :    ///@}
     223              : protected:
     224              :     /** \name INDI
     225              :       *
     226              :       *@{
     227              :       */
     228              : protected:
     229              :    //declare our properties
     230              : 
     231              :    pcf::IndiProperty m_indiP_powerChannel; ///< Property used to monitor the shutter's power state
     232              :    pcf::IndiProperty m_indiP_sensorChannel; ///< Property used to monitor the shutter's hall sensor
     233              :    pcf::IndiProperty m_indiP_triggerChannel; ///< Property used to monitor and set the shutter's trigger
     234              : 
     235              : public:
     236              : 
     237              :    /// The static callback function to be registered for shutter power channel changes
     238              :    /**
     239              :      * \returns 0 on success.
     240              :      * \returns -1 on error.
     241              :      */
     242              :    static int st_setCallBack_powerChannel( void * app, ///< [in] a pointer to this, will be static_cast-ed to derivedT.
     243              :                                            const pcf::IndiProperty &ipRecv ///< [in] the INDI property sent with the the new property request.
     244              :                                          );
     245              : 
     246              :    /// The callback called by the static version, to actually process the new request.
     247              :    /**
     248              :      * \returns 0 on success.
     249              :      * \returns -1 on error.
     250              :      */
     251              :    int setCallBack_powerChannel( const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/);
     252              : 
     253              : 
     254              :    /// The static callback function to be registered for shutter sensor channel changes
     255              :    /**
     256              :      * \returns 0 on success.
     257              :      * \returns -1 on error.
     258              :      */
     259              :    static int st_setCallBack_sensorChannel( void * app, ///< [in] a pointer to this, will be static_cast-ed to derivedT.
     260              :                                            const pcf::IndiProperty &ipRecv ///< [in] the INDI property sent with the the new property request.
     261              :                                          );
     262              : 
     263              :    /// The callback called by the static version, to actually process the new request.
     264              :    /**
     265              :      * \returns 0 on success.
     266              :      * \returns -1 on error.
     267              :      */
     268              :    int setCallBack_sensorChannel( const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/);
     269              : 
     270              :    /// The static callback function to be registered for shutter trigger channel changes
     271              :    /**
     272              :      * \returns 0 on success.
     273              :      * \returns -1 on error.
     274              :      */
     275              :    static int st_setCallBack_triggerChannel( void * app, ///< [in] a pointer to this, will be static_cast-ed to derivedT.
     276              :                                            const pcf::IndiProperty &ipRecv ///< [in] the INDI property sent with the the new property request.
     277              :                                          );
     278              : 
     279              :    /// The callback called by the static version, to actually process the new request.
     280              :    /**
     281              :      * \returns 0 on success.
     282              :      * \returns -1 on error.
     283              :      */
     284              :    int setCallBack_triggerChannel( const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/);
     285              : 
     286              : 
     287              :    ///@}
     288              : 
     289              : private:
     290              : 
     291              :    /// Access the derived class.
     292           51 :    derivedT & derived()
     293              :    {
     294           51 :       return *static_cast<derivedT *>(this);
     295              :    }
     296              : };
     297              : 
     298              : template<class derivedT>
     299          111 : dssShutter<derivedT>::dssShutter()
     300              : {
     301          111 : }
     302              : 
     303              : template<class derivedT>
     304            4 : void dssShutter<derivedT>::setupConfig(mx::app::appConfigurator & config)
     305              : {
     306           56 :    config.add("shutter.powerDevice", "", "shutter.powerDevice", argType::Required, "shutter", "powerDevice", false, "string", "The device controlling this shutter's power");
     307           56 :    config.add("shutter.powerChannel", "", "shutter.powerChannel", argType::Required, "shutter", "powerChannel", false, "string", "The channel controlling this shutter's power");
     308              : 
     309           56 :    config.add("shutter.dioDevice", "", "shutter.dioDevice", argType::Required, "shutter", "dioDevice", false, "string", "The device controlling this shutter's digital I/O.");
     310              : 
     311           56 :    config.add("shutter.sensorChannel", "", "shutter.sensorChannel", argType::Required, "shutter", "sensorChannel", false, "string", "The channel reading this shutter's sensor.");
     312              : 
     313           56 :    config.add("shutter.triggerChannel", "", "shutter.triggerChannel", argType::Required, "shutter", "triggerChannel", false, "string", "The channel sending this shutter's trigger.");
     314              : 
     315           56 :    config.add("shutter.wait", "", "shutter.wait", argType::Required, "shutter", "wait", false, "int", "The time to pause between checks of the sensor state during open/shut [msec]. Default is 100.");
     316              : 
     317           52 :    config.add("shutter.timeout", "", "shutter.timeout", argType::Required, "shutter", "timeout", false, "int", "Total time to wait for sensor to change state before timing out [msec]. Default is 2000.");
     318              : 
     319            4 : }
     320              : 
     321              : template<class derivedT>
     322            4 : void dssShutter<derivedT>::loadConfig(mx::app::appConfigurator & config)
     323              : {
     324            8 :    config(m_powerDevice, "shutter.powerDevice");
     325            8 :    config(m_powerChannel, "shutter.powerChannel");
     326            8 :    config(m_dioDevice, "shutter.dioDevice");
     327            8 :    config(m_sensorChannel, "shutter.sensorChannel");
     328            8 :    config(m_triggerChannel, "shutter.triggerChannel");
     329            8 :    config(m_shutterWait, "shutter.wait");
     330            4 :    config(m_shutterTimeout, "shutter.timeout");
     331            4 : }
     332              : 
     333              : 
     334              : template<class derivedT>
     335            1 : int dssShutter<derivedT>::appStartup()
     336              : {
     337              :    //Register the powerChannel property for updates
     338            1 :    if( derived().registerIndiPropertySet( m_indiP_powerChannel, m_powerDevice, m_powerChannel, st_setCallBack_powerChannel) < 0)
     339              :    {
     340              :       #ifndef DSSSHUTTER_TEST_NOLOG
     341            0 :       derivedT::template log<software_error>({__FILE__,__LINE__});
     342              :       #endif
     343            0 :       return -1;
     344              :    }
     345              : 
     346              :    //Register the sensorChannel property for updates
     347            1 :    if( derived().registerIndiPropertySet( m_indiP_sensorChannel, m_dioDevice, m_sensorChannel, st_setCallBack_sensorChannel) < 0)
     348              :    {
     349              :       #ifndef DSSSHUTTER_TEST_NOLOG
     350            0 :       derivedT::template log<software_error>({__FILE__,__LINE__});
     351              :       #endif
     352            0 :       return -1;
     353              :    }
     354              : 
     355              :    //Register the triggerChannel property for updates
     356            1 :    if( derived().registerIndiPropertySet( m_indiP_triggerChannel, m_dioDevice, m_triggerChannel, st_setCallBack_triggerChannel) < 0)
     357              :    {
     358              :       #ifndef DSSSHUTTER_TEST_NOLOG
     359            0 :       derivedT::template log<software_error>({__FILE__,__LINE__});
     360              :       #endif
     361            0 :       return -1;
     362              :    }
     363              : 
     364              : 
     365              : 
     366            5 :    if(derived().threadStart( m_openThread, m_openThreadInit, m_openThreadID, m_openThreadProp, 0, "", "open", this, openThreadStart) < 0)
     367              :    {
     368            0 :       derivedT::template log<software_error>({__FILE__, __LINE__});
     369            0 :       return -1;
     370              :    }
     371              : 
     372            5 :    if(derived().threadStart( m_shutThread, m_shutThreadInit, m_shutThreadID, m_shutThreadProp, 0, "", "shut", this, shutThreadStart) < 0)
     373              :    {
     374            0 :       derivedT::template log<software_error>({__FILE__, __LINE__});
     375            0 :       return -1;
     376              :    }
     377              : 
     378              :    //Install empty signal handler for USR1, which is used to interrupt sleeps in the open/shut threads.
     379              :    struct sigaction act;
     380              :    sigset_t set;
     381              : 
     382            1 :    act.sa_sigaction = &sigUsr1Handler;
     383            1 :    act.sa_flags = SA_SIGINFO;
     384            1 :    sigemptyset(&set);
     385            1 :    act.sa_mask = set;
     386              : 
     387            1 :    errno = 0;
     388            1 :    if( sigaction(SIGUSR1, &act, 0) < 0 )
     389              :    {
     390            0 :       std::string logss = "Setting handler for SIGUSR1 failed. Errno says: ";
     391            0 :       logss += strerror(errno);
     392              : 
     393            0 :       derivedT::template log<software_error>({__FILE__, __LINE__, errno, 0, logss});
     394              : 
     395            0 :       return -1;
     396            0 :    }
     397              : 
     398            1 :    return 0;
     399              : 
     400              : }
     401              : 
     402              : template<class derivedT>
     403           21 : int dssShutter<derivedT>::appLogic()
     404              : {
     405           21 :    if(m_powerState !=0 && m_powerState != 1)
     406              :    {
     407           21 :       derived().m_shutterStatus = "UNKNOWN";
     408           21 :       derived().m_shutterState = -1;
     409           21 :       return 0;
     410              :    }
     411              : 
     412            0 :    if(m_powerState == 0)
     413              :    {
     414            0 :       derived().m_shutterStatus = "POWEROFF";
     415            0 :       derived().m_shutterState = -1;
     416            0 :       return 0;
     417              :    }
     418              : 
     419            0 :    derived().m_shutterStatus = "READY";
     420              : 
     421            0 :    if(m_sensorState == 0)
     422              :    {
     423            0 :       derived().m_shutterState = 0;
     424            0 :       return 0;
     425              :    }
     426              : 
     427            0 :    if(m_sensorState == 1)
     428              :    {
     429            0 :       derived().m_shutterState = 1;
     430            0 :       return 0;
     431              :    }
     432              : 
     433            0 :    return 0;
     434              : }
     435              : 
     436              : template<class derivedT>
     437            2 : int dssShutter<derivedT>::appShutdown()
     438              : {
     439            2 :    if(m_openThread.joinable())
     440              :    {
     441            1 :       pthread_kill(m_openThread.native_handle(), SIGUSR1);
     442              :    }
     443              : 
     444            2 :    if(m_shutThread.joinable())
     445              :    {
     446            1 :       pthread_kill(m_shutThread.native_handle(), SIGUSR1);
     447              :    }
     448              : 
     449            2 :    if(m_openThread.joinable())
     450              :    {
     451              :       try
     452              :       {
     453            1 :          m_openThread.join(); //this will throw if it was already joined
     454              :       }
     455            0 :       catch(...)
     456              :       {
     457              :       }
     458              :    }
     459              : 
     460            2 :    if(m_shutThread.joinable())
     461              :    {
     462              :       try
     463              :       {
     464            1 :          m_shutThread.join(); //this will throw if it was already joined
     465              :       }
     466            0 :       catch(...)
     467              :       {
     468              :       }
     469              :    }
     470            2 :    return 0;
     471              : }
     472              : 
     473              : template<class derivedT>
     474            1 : int dssShutter<derivedT>::onPowerOff()
     475              : {
     476            1 :    return appLogic(); //Power state of derived() does not say anything about power state of the shutter
     477              : }
     478              : 
     479              : template<class derivedT>
     480            1 : int dssShutter<derivedT>::whilePowerOff()
     481              : {
     482            1 :    return appLogic(); //Power state of derived() does not say anything about power state of the shutter
     483              : }
     484              : 
     485              : template<class derivedT>
     486            1 : int dssShutter<derivedT>::setShutterState( int sh )
     487              : {
     488            1 :    if( sh == 1 )
     489              :    {
     490            0 :       m_doOpen = true;
     491              : 
     492            0 :       pthread_kill(m_openThread.native_handle(), SIGUSR1);
     493              : 
     494            0 :       return 0;
     495              :    }
     496            1 :    else if( sh == 0)
     497              :    {
     498            0 :       m_doShut = true;
     499              : 
     500            0 :       pthread_kill(m_shutThread.native_handle(), SIGUSR1);
     501              : 
     502            0 :       return 0;
     503              :    }
     504              :    else
     505              :    {
     506            1 :       derivedT::template log<software_error>({ __FILE__, __LINE__,"invalid shutter request"});
     507              : 
     508            1 :       return -1;
     509              :    }
     510              : }
     511              : 
     512              : template<class derivedT>
     513            0 : int dssShutter<derivedT>::open()
     514              : {
     515            0 :    if(m_powerState != 1) return 0;
     516              : 
     517            0 :    int startss = m_sensorState;
     518              : 
     519            0 :    derived().recordCamera(true);
     520            0 :    if(startss) return 0; //already open
     521              : 
     522              :    //First try:
     523            0 :    int startts = m_triggerState;
     524              : 
     525            0 :    derived().sendNewProperty (m_indiP_triggerChannel, "target", (int) !m_triggerState);
     526              : 
     527            0 :    double t0 = mx::sys::get_curr_time();
     528            0 :    while( m_sensorState != 1 )
     529              :    {
     530            0 :       mx::sys::milliSleep( m_shutterWait );
     531            0 :       if( (mx::sys::get_curr_time() - t0)*1000 > m_shutterTimeout) break;
     532              :    }
     533              : 
     534            0 :    if(m_sensorState == 1)
     535              :    {
     536            0 :       derived().recordCamera(true);
     537            0 :       derivedT::template log<text_log>("shutter open");
     538            0 :       return 0;
     539              :    }
     540              : 
     541            0 :    if( m_triggerState == startts )
     542              :    {
     543            0 :       return derivedT::template log<software_error,-1>({__FILE__, __LINE__, "shutter trigger did not change state"});
     544              :    }
     545              : 
     546              :    //If here, shutter is not open, and trigger did flip, so it's a starting state issue.
     547              :    //So we try again.
     548              : 
     549            0 :    derived().sendNewProperty (m_indiP_triggerChannel, "target", (int) !m_triggerState);
     550              : 
     551            0 :    t0 = mx::sys::get_curr_time();
     552            0 :    while( m_sensorState != 1 )
     553              :    {
     554            0 :       mx::sys::milliSleep( m_shutterWait );
     555            0 :       if( (mx::sys::get_curr_time() - t0)*1000 > m_shutterTimeout) break;
     556              :    }
     557              : 
     558              :    ///\todo need shutter log types
     559            0 :    if(m_sensorState == 1)
     560              :    {
     561            0 :       derived().recordCamera(true);
     562            0 :       derivedT::template log<text_log>("shutter open");
     563            0 :       return 0;
     564              :    }
     565              : 
     566            0 :    if( m_triggerState == !startts )
     567              :    {
     568            0 :       return derivedT::template log<software_error,-1>({__FILE__, __LINE__, "shutter trigger did not change state"});
     569              :    }
     570              : 
     571            0 :    return derivedT::template log<software_error,-1>({__FILE__, __LINE__, "shutter failed to open"});
     572              : }
     573              : 
     574              : template<class derivedT>
     575            0 : int dssShutter<derivedT>::shut()
     576              : {
     577            0 :    if(m_powerState != 1) return 0;
     578              : 
     579            0 :    int startss = m_sensorState;
     580              : 
     581            0 :    if(!startss) return 0; //already shut
     582              : 
     583              :    //First try:
     584            0 :    int startts = m_triggerState;
     585              : 
     586            0 :    derived().sendNewProperty (m_indiP_triggerChannel, "target", (int) !m_triggerState);
     587              : 
     588            0 :    double t0 = mx::sys::get_curr_time();
     589            0 :    while( m_sensorState != 0 )
     590              :    {
     591            0 :       mx::sys::milliSleep( m_shutterWait );
     592            0 :       if( (mx::sys::get_curr_time() - t0)*1000 > m_shutterTimeout) break;
     593              :    }
     594              : 
     595              :    ///\todo need shutter log types
     596            0 :    if(m_sensorState == 0)
     597              :    {
     598            0 :       derived().recordCamera(true);
     599            0 :       derivedT::template log<text_log>("shutter shut");
     600            0 :       return 0;
     601              :    }
     602              : 
     603            0 :    if( m_triggerState == startts )
     604              :    {
     605            0 :       return derivedT::template log<software_error,-1>({__FILE__, __LINE__, "shutter trigger did not change state"});
     606              :    }
     607              : 
     608              : 
     609              :    //If here, shutter is not open, and trigger did flip, so it's a starting state issue.
     610              :    //So we try again.
     611              : 
     612            0 :    derived().sendNewProperty (m_indiP_triggerChannel, "target", (int) !m_triggerState);
     613              : 
     614            0 :    t0 = mx::sys::get_curr_time();
     615            0 :    while( m_sensorState != 0 )
     616              :    {
     617            0 :       mx::sys::milliSleep( m_shutterWait );
     618            0 :       if( (mx::sys::get_curr_time() - t0)*1000 > m_shutterTimeout) break;
     619              :    }
     620              : 
     621              :    ///\todo need shutter log types
     622            0 :    if(m_sensorState == 0)
     623              :    {
     624            0 :       derived().recordCamera(true);
     625            0 :       derivedT::template log<text_log>("shutter shut");
     626            0 :       return 0;
     627              :    }
     628              : 
     629            0 :    if( m_triggerState == !startts )
     630              :    {
     631            0 :       return derivedT::template log<software_error,-1>({__FILE__, __LINE__, "shutter trigger did not change state"});
     632              :    }
     633              : 
     634            0 :    return derivedT::template log<software_error,-1>({__FILE__, __LINE__, "shutter failed to shut"});
     635              : 
     636              : 
     637              : }
     638              : 
     639              : template<class derivedT>
     640            1 : void dssShutter<derivedT>::openThreadStart( dssShutter * d )
     641              : {
     642            1 :    d->openThreadExec();
     643            1 : }
     644              : 
     645              : template<class derivedT>
     646            1 : void dssShutter<derivedT>::openThreadExec( )
     647              : {
     648            1 :    m_openThreadID = syscall(SYS_gettid);
     649              : 
     650            2 :    while( m_openThreadInit == true && derived().shutdown() == 0)
     651              :    {
     652            1 :       sleep(1);
     653              :    }
     654              : 
     655            1 :    while(derived().shutdown() == 0)
     656              :    {
     657            0 :       if( m_doOpen )
     658              :       {
     659            0 :          if(open() < 0)
     660              :          {
     661            0 :             derivedT::template log<software_error>({__FILE__,__LINE__});
     662              :          }
     663            0 :          m_doOpen = false;
     664              :       }
     665              : 
     666            0 :       sleep(1);
     667              : 
     668              :    }
     669              : 
     670            1 :    return;
     671              : }
     672              : 
     673              : template<class derivedT>
     674            1 : void dssShutter<derivedT>::shutThreadStart( dssShutter * d )
     675              : {
     676            1 :    d->shutThreadExec();
     677            1 : }
     678              : 
     679              : template<class derivedT>
     680            1 : void dssShutter<derivedT>::shutThreadExec( )
     681              : {
     682            1 :    m_shutThreadID = syscall(SYS_gettid);
     683              : 
     684            2 :    while( m_shutThreadInit == true && derived().shutdown() == 0)
     685              :    {
     686            1 :       sleep(1);
     687              :    }
     688              : 
     689            1 :    while(derived().shutdown() == 0)
     690              :    {
     691            0 :       if( m_doShut )
     692              :       {
     693            0 :          if(shut() < 0)
     694              :          {
     695            0 :             derivedT::template log<software_error>({__FILE__,__LINE__});
     696              :          }
     697            0 :          m_doShut = false;
     698              :       }
     699              : 
     700            0 :       sleep(1);
     701              :    }
     702              : 
     703            1 :    return;
     704              : }
     705              : 
     706              : template<class derivedT>
     707            0 : int dssShutter<derivedT>::st_setCallBack_powerChannel( void * app,
     708              :                                                        const pcf::IndiProperty &ipRecv
     709              :                                                       )
     710              : {
     711            0 :    return static_cast<derivedT *>(app)->setCallBack_powerChannel(ipRecv);
     712              : }
     713              : 
     714              : template<class derivedT>
     715            0 : int dssShutter<derivedT>::setCallBack_powerChannel( const pcf::IndiProperty &ipRecv )
     716              : {
     717            0 :    std::string ps;
     718              : 
     719            0 :    if(ipRecv.getName() != m_indiP_powerChannel.getName()) return 0;
     720              : 
     721            0 :    m_indiP_powerChannel = ipRecv;
     722              : 
     723            0 :    if(!ipRecv.find("state")) return 0;
     724              : 
     725            0 :    ps = ipRecv["state"].get<std::string>();
     726              : 
     727            0 :    if(ps == "On")
     728              :    {
     729            0 :       m_powerState = 1;
     730              :    }
     731            0 :    else if (ps == "Off")
     732              :    {
     733            0 :       m_powerState = 0;
     734              :    }
     735              :    else
     736              :    {
     737            0 :       m_powerState = -1;
     738              :    }
     739              : 
     740            0 :    return 0;
     741            0 : }
     742              : 
     743              : template<class derivedT>
     744            0 : int dssShutter<derivedT>::st_setCallBack_sensorChannel( void * app,
     745              :                                                         const pcf::IndiProperty &ipRecv
     746              :                                                       )
     747              : {
     748            0 :    return static_cast<derivedT *>(app)->setCallBack_sensorChannel(ipRecv);
     749              : }
     750              : 
     751              : template<class derivedT>
     752            0 : int dssShutter<derivedT>::setCallBack_sensorChannel( const pcf::IndiProperty &ipRecv )
     753              : {
     754              : 
     755            0 :    if(ipRecv.getName() != m_indiP_sensorChannel.getName()) return 0;
     756              : 
     757            0 :    m_indiP_sensorChannel = ipRecv;
     758              : 
     759            0 :    if(!ipRecv.find("current")) return 0;
     760              : 
     761            0 :    int ss = ipRecv["current"].get<int>();
     762              : 
     763            0 :    if(ss == 1)
     764              :    {
     765            0 :       m_sensorState = 1;
     766              :    }
     767            0 :    else if (ss == 0)
     768              :    {
     769            0 :       m_sensorState = 0;
     770              :    }
     771              :    else
     772              :    {
     773            0 :       m_sensorState = -1;
     774              :    }
     775              : 
     776            0 :    return 0;
     777              : }
     778              : 
     779              : 
     780              : template<class derivedT>
     781            0 : int dssShutter<derivedT>::st_setCallBack_triggerChannel( void * app,
     782              :                                                          const pcf::IndiProperty &ipRecv
     783              :                                                        )
     784              : {
     785            0 :    return static_cast<derivedT *>(app)->setCallBack_triggerChannel(ipRecv);
     786              : }
     787              : 
     788              : template<class derivedT>
     789            0 : int dssShutter<derivedT>::setCallBack_triggerChannel( const pcf::IndiProperty &ipRecv )
     790              : {
     791            0 :    if(ipRecv.getName() != m_indiP_triggerChannel.getName()) return 0;
     792              : 
     793            0 :    m_indiP_triggerChannel = ipRecv;
     794              : 
     795            0 :    if(!ipRecv.find("current")) return 0;
     796              : 
     797            0 :    int ts = ipRecv["current"].get<int>();
     798              : 
     799            0 :    if(ts == 1)
     800              :    {
     801            0 :       m_triggerState = 1;
     802              :    }
     803            0 :    else if (ts == 0)
     804              :    {
     805            0 :       m_triggerState = 0;
     806              :    }
     807              :    else
     808              :    {
     809            0 :       m_triggerState = -1;
     810              :    }
     811              : 
     812            0 :    return 0;
     813              : }
     814              : 
     815              : 
     816              : 
     817              : 
     818              : 
     819              : } //namespace dev
     820              : } //namespace app
     821              : } //namespace MagAOX
     822              : 
     823              : #endif //dssShutter_hpp
        

Generated by: LCOV version 2.0-1