LCOV - code coverage report
Current view: top level - apps/xt1121Ctrl - xt1121Ctrl.hpp (source / functions) Coverage Total Hit
Test: MagAOX Lines: 4.5 % 312 14
Test Date: 2026-04-15 19:34:29 Functions: 6.8 % 44 3

            Line data    Source code
       1              : /** \file xt1121Ctrl.hpp
       2              :  * \brief The MagAO-X Acromag XT 1121digital I/O controller.
       3              :  *
       4              :  * \author Jared R. Males (jaredmales@gmail.com)
       5              :  *
       6              :  * \ingroup xt1121Ctrl_files
       7              :  */
       8              : 
       9              : #ifndef xt1121Ctrl_hpp
      10              : #define xt1121Ctrl_hpp
      11              : 
      12              : #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
      13              : #include "../../magaox_git_version.h"
      14              : 
      15              : #include "xtChannels.hpp"
      16              : 
      17              : namespace MagAOX
      18              : {
      19              : namespace app
      20              : {
      21              : 
      22              : /** \defgroup xt1121Ctrl Acromag xt1121Controller
      23              :  * \brief Control of an Acromag xt1121digital I/O module
      24              :  *
      25              :  * <a href="../handbook/operating/software/apps/xt1121Ctrl.html">Application Documentation</a>
      26              :  *
      27              :  * \ingroup apps
      28              :  *
      29              :  */
      30              : 
      31              : /** \defgroup xt1121Ctrl_files Acromag xt1121Controller Files
      32              :  * \ingroup xt1121Ctrl
      33              :  */
      34              : 
      35              : /** MagAO-X application to control an Acromag xt1121digital i/o module
      36              :  *
      37              :  * \ingroup xt1121Ctrl
      38              :  *
      39              :  */
      40              : class xt1121Ctrl : public MagAOXApp<>, public xt1121Channels
      41              : {
      42              : 
      43              :   protected:
      44              :     /** \name configurable parameters
      45              :      *@{
      46              :      */
      47              : 
      48              :     std::string m_address; ///< The I.P. address of the device
      49              : 
      50              :     uint16_t m_port{ 502 }; ///< The port to use.  Default is 502 for modbus.
      51              : 
      52              :     ///@}
      53              : 
      54              :     std::mutex m_modbusMutex; ///< Protects m_mb lifetime and all modbus socket I/O.
      55              : 
      56              :     std::atomic<bool> m_callbacksEnabled{ true }; ///< Gates INDI callbacks during shutdown/teardown.
      57              : 
      58              :     modbus *m_mb{ nullptr }; ///< The modbus protocol communication object
      59              : 
      60              :     /// Close and delete the current modbus object under m_modbusMutex.
      61              :     void closeModbus();
      62              : 
      63              :   public:
      64              :     /// Default c'tor
      65              :     xt1121Ctrl();
      66              : 
      67              :     /// Destructor
      68              :     ~xt1121Ctrl() noexcept;
      69              : 
      70              :     /// Setup the configuration system (called by MagAOXApp::setup())
      71              :     virtual void setupConfig();
      72              : 
      73              :     /// load the configuration system results (called by MagAOXApp::setup())
      74              :     virtual void loadConfig();
      75              : 
      76              :     /// Startup functions
      77              :     /** Sets up the INDI vars.
      78              :      *
      79              :      */
      80              :     virtual int appStartup();
      81              : 
      82              :     /// Implementation of the FSM for the Siglent SDG
      83              :     virtual int appLogic();
      84              : 
      85              :     /// Implementation of the on-power-off FSM logic
      86              :     virtual int onPowerOff();
      87              : 
      88              :     /// Implementation of the while-powered-off FSM
      89              :     virtual int whilePowerOff();
      90              : 
      91              :     /// Do any needed shutdown tasks.  Currently nothing in this app.
      92              :     virtual int appShutdown();
      93              : 
      94              :     /// Get the current state of the outlets.
      95              :     /**
      96              :      * \returns 0 on success
      97              :      * \returns -1 on error
      98              :      */
      99              :     int getState();
     100              : 
     101              :     // INDI:
     102              :   protected:
     103              :     // declare our properties
     104              :     pcf::IndiProperty m_indiP_ch00;
     105              :     pcf::IndiProperty m_indiP_ch01;
     106              :     pcf::IndiProperty m_indiP_ch02;
     107              :     pcf::IndiProperty m_indiP_ch03;
     108              :     pcf::IndiProperty m_indiP_ch04;
     109              :     pcf::IndiProperty m_indiP_ch05;
     110              :     pcf::IndiProperty m_indiP_ch06;
     111              :     pcf::IndiProperty m_indiP_ch07;
     112              :     pcf::IndiProperty m_indiP_ch08;
     113              :     pcf::IndiProperty m_indiP_ch09;
     114              :     pcf::IndiProperty m_indiP_ch10;
     115              :     pcf::IndiProperty m_indiP_ch11;
     116              :     pcf::IndiProperty m_indiP_ch12;
     117              :     pcf::IndiProperty m_indiP_ch13;
     118              :     pcf::IndiProperty m_indiP_ch14;
     119              :     pcf::IndiProperty m_indiP_ch15;
     120              : 
     121              :   public:
     122              :     /// Callback worker to actually set or clear a channel and send it to the device
     123              :     /** Contains the target/current logic, and calls the xtChannels::setRegisters
     124              :      * function, and then the modbus write_registers.
     125              :      *
     126              :      * \returns 0 on success
     127              :      * \returns -1 on error
     128              :      */
     129              :     int channelSetCallback( size_t                   chNo,    ///< [in] The channel number to set
     130              :                             pcf::IndiProperty       &ipToSet, ///< [in] The corresponding local INDI property
     131              :                             const pcf::IndiProperty &ipRecv   ///< [in] The received INDI property
     132              :     );
     133              : 
     134            0 :     INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch00 );
     135            0 :     INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch01 );
     136            0 :     INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch02 );
     137            0 :     INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch03 );
     138            0 :     INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch04 );
     139            0 :     INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch05 );
     140            0 :     INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch06 );
     141            0 :     INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch07 );
     142            0 :     INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch08 );
     143            0 :     INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch09 );
     144            0 :     INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch10 );
     145            0 :     INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch11 );
     146            0 :     INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch12 );
     147            0 :     INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch13 );
     148            0 :     INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch14 );
     149            0 :     INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch15 );
     150              : };
     151              : 
     152            3 : inline xt1121Ctrl::xt1121Ctrl() : MagAOXApp( MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED )
     153              : {
     154            1 :     m_powerMgtEnabled = true;
     155            1 :     m_powerOnWait     = 2; // set default.
     156            1 :     return;
     157            0 : }
     158              : 
     159            1 : inline xt1121Ctrl::~xt1121Ctrl() noexcept
     160              : {
     161            1 :     m_callbacksEnabled = false;
     162            1 :     closeModbus();
     163              : 
     164            1 :     return;
     165            1 : }
     166              : 
     167            0 : inline void xt1121Ctrl::setupConfig()
     168              : {
     169            0 :     config.add( "device.address",
     170              :                 "",
     171              :                 "device.address",
     172              :                 argType::Required,
     173              :                 "device",
     174              :                 "address",
     175              :                 true,
     176              :                 "string",
     177              :                 "The device I.P. address." );
     178              : 
     179            0 :     config.add( "device.port",
     180              :                 "",
     181              :                 "device.port",
     182              :                 argType::Required,
     183              :                 "device",
     184              :                 "port",
     185              :                 true,
     186              :                 "int",
     187              :                 "The device port.  Default is 502." );
     188              : 
     189            0 :     config.add( "device.inputOnly",
     190              :                 "",
     191              :                 "device.inputOnly",
     192              :                 argType::Required,
     193              :                 "device",
     194              :                 "inputOnly",
     195              :                 false,
     196              :                 "vector<int>",
     197              :                 "List of channels which are input-only." );
     198            0 : }
     199              : 
     200            0 : inline void xt1121Ctrl::loadConfig()
     201              : {
     202            0 :     config( m_address, "device.address" );
     203            0 :     config( m_port, "device.port" );
     204              : 
     205            0 :     std::vector<int> ino;
     206            0 :     config( ino, "device.inputOnly" );
     207              : 
     208            0 :     for( size_t i = 0; i < ino.size(); ++i )
     209              :     {
     210            0 :         if( setInputOnly( ino[i] ) != 0 )
     211              :         {
     212            0 :             log<text_log>( "Error setting channel " + std::to_string( i ) + " to input only.", logPrio::LOG_ERROR );
     213              :         }
     214              :     }
     215            0 : }
     216              : 
     217            0 : inline int xt1121Ctrl::appStartup()
     218              : {
     219              :     // set up the  INDI properties
     220            0 :     REG_INDI_NEWPROP( m_indiP_ch00, "ch00", pcf::IndiProperty::Number );
     221            0 :     m_indiP_ch00.add( pcf::IndiElement( "current" ) );
     222            0 :     m_indiP_ch00["current"].set( -1 );
     223            0 :     m_indiP_ch00.add( pcf::IndiElement( "target" ) );
     224              : 
     225            0 :     REG_INDI_NEWPROP( m_indiP_ch01, "ch01", pcf::IndiProperty::Number );
     226            0 :     m_indiP_ch01.add( pcf::IndiElement( "current" ) );
     227            0 :     m_indiP_ch01["current"].set( -1 );
     228            0 :     m_indiP_ch01.add( pcf::IndiElement( "target" ) );
     229              : 
     230            0 :     REG_INDI_NEWPROP( m_indiP_ch02, "ch02", pcf::IndiProperty::Number );
     231            0 :     m_indiP_ch02.add( pcf::IndiElement( "current" ) );
     232            0 :     m_indiP_ch02["current"].set( -1 );
     233            0 :     m_indiP_ch02.add( pcf::IndiElement( "target" ) );
     234              : 
     235            0 :     REG_INDI_NEWPROP( m_indiP_ch03, "ch03", pcf::IndiProperty::Number );
     236            0 :     m_indiP_ch03.add( pcf::IndiElement( "current" ) );
     237            0 :     m_indiP_ch03["current"].set( -1 );
     238            0 :     m_indiP_ch03.add( pcf::IndiElement( "target" ) );
     239              : 
     240            0 :     REG_INDI_NEWPROP( m_indiP_ch04, "ch04", pcf::IndiProperty::Number );
     241            0 :     m_indiP_ch04.add( pcf::IndiElement( "current" ) );
     242            0 :     m_indiP_ch04["current"].set( -1 );
     243            0 :     m_indiP_ch04.add( pcf::IndiElement( "target" ) );
     244              : 
     245            0 :     REG_INDI_NEWPROP( m_indiP_ch05, "ch05", pcf::IndiProperty::Number );
     246            0 :     m_indiP_ch05.add( pcf::IndiElement( "current" ) );
     247            0 :     m_indiP_ch05["current"].set( -1 );
     248            0 :     m_indiP_ch05.add( pcf::IndiElement( "target" ) );
     249              : 
     250            0 :     REG_INDI_NEWPROP( m_indiP_ch06, "ch06", pcf::IndiProperty::Number );
     251            0 :     m_indiP_ch06.add( pcf::IndiElement( "current" ) );
     252            0 :     m_indiP_ch06["current"].set( -1 );
     253            0 :     m_indiP_ch06.add( pcf::IndiElement( "target" ) );
     254              : 
     255            0 :     REG_INDI_NEWPROP( m_indiP_ch07, "ch07", pcf::IndiProperty::Number );
     256            0 :     m_indiP_ch07.add( pcf::IndiElement( "current" ) );
     257            0 :     m_indiP_ch07["current"].set( -1 );
     258            0 :     m_indiP_ch07.add( pcf::IndiElement( "target" ) );
     259              : 
     260            0 :     REG_INDI_NEWPROP( m_indiP_ch08, "ch08", pcf::IndiProperty::Number );
     261            0 :     m_indiP_ch08.add( pcf::IndiElement( "current" ) );
     262            0 :     m_indiP_ch08["current"].set( -1 );
     263            0 :     m_indiP_ch08.add( pcf::IndiElement( "target" ) );
     264              : 
     265            0 :     REG_INDI_NEWPROP( m_indiP_ch09, "ch09", pcf::IndiProperty::Number );
     266            0 :     m_indiP_ch09.add( pcf::IndiElement( "current" ) );
     267            0 :     m_indiP_ch09["current"].set( -1 );
     268            0 :     m_indiP_ch09.add( pcf::IndiElement( "target" ) );
     269              : 
     270            0 :     REG_INDI_NEWPROP( m_indiP_ch10, "ch10", pcf::IndiProperty::Number );
     271            0 :     m_indiP_ch10.add( pcf::IndiElement( "current" ) );
     272            0 :     m_indiP_ch10["current"].set( -1 );
     273            0 :     m_indiP_ch10.add( pcf::IndiElement( "target" ) );
     274              : 
     275            0 :     REG_INDI_NEWPROP( m_indiP_ch11, "ch11", pcf::IndiProperty::Number );
     276            0 :     m_indiP_ch11.add( pcf::IndiElement( "current" ) );
     277            0 :     m_indiP_ch11["current"].set( -1 );
     278            0 :     m_indiP_ch11.add( pcf::IndiElement( "target" ) );
     279              : 
     280            0 :     REG_INDI_NEWPROP( m_indiP_ch12, "ch12", pcf::IndiProperty::Number );
     281            0 :     m_indiP_ch12.add( pcf::IndiElement( "current" ) );
     282            0 :     m_indiP_ch12["current"].set( -1 );
     283            0 :     m_indiP_ch12.add( pcf::IndiElement( "target" ) );
     284              : 
     285            0 :     REG_INDI_NEWPROP( m_indiP_ch13, "ch13", pcf::IndiProperty::Number );
     286            0 :     m_indiP_ch13.add( pcf::IndiElement( "current" ) );
     287            0 :     m_indiP_ch13["current"].set( -1 );
     288            0 :     m_indiP_ch13.add( pcf::IndiElement( "target" ) );
     289              : 
     290            0 :     REG_INDI_NEWPROP( m_indiP_ch14, "ch14", pcf::IndiProperty::Number );
     291            0 :     m_indiP_ch14.add( pcf::IndiElement( "current" ) );
     292            0 :     m_indiP_ch14["current"].set( -1 );
     293            0 :     m_indiP_ch14.add( pcf::IndiElement( "target" ) );
     294              : 
     295            0 :     REG_INDI_NEWPROP( m_indiP_ch15, "ch15", pcf::IndiProperty::Number );
     296            0 :     m_indiP_ch15.add( pcf::IndiElement( "current" ) );
     297            0 :     m_indiP_ch15["current"].set( -1 );
     298            0 :     m_indiP_ch15.add( pcf::IndiElement( "target" ) );
     299              : 
     300            0 :     return 0;
     301              : }
     302              : 
     303            0 : inline int xt1121Ctrl::appLogic()
     304              : {
     305            0 :     if( state() == stateCodes::POWERON )
     306              :     {
     307            0 :         if( !powerOnWaitElapsed() )
     308              :         {
     309            0 :             return 0;
     310              :         }
     311              : 
     312            0 :         state( stateCodes::NOTCONNECTED );
     313              :     }
     314              : 
     315            0 :     if( state() == stateCodes::NOTCONNECTED || state() == stateCodes::ERROR )
     316              :     {
     317              :         // Might have gotten here because of a power off.
     318            0 :         if( m_powerState == 0 )
     319              :         {
     320            0 :             return 0;
     321              :         }
     322              : 
     323            0 :         closeModbus();
     324              : 
     325            0 :         modbus *newMb = new( std::nothrow ) modbus( m_address, m_port );
     326              : 
     327            0 :         if( newMb == nullptr )
     328              :         {
     329            0 :             return log<software_critical, -1>( { __FILE__, __LINE__, "allocation failure" } );
     330              :         }
     331              : 
     332            0 :         newMb->modbus_set_slave_id( 1 );
     333              : 
     334            0 :         if( newMb->modbus_connect() == false )
     335              :         {
     336            0 :             if( !stateLogged() )
     337              :             {
     338            0 :                 log<text_log>( "connect failed at " + m_address + ":" + std::to_string( m_port ) );
     339              :             }
     340            0 :             delete newMb;
     341            0 :             return 0;
     342              :         }
     343              : 
     344            0 :         if( !newMb->modbus_set_timeouts( 2, 0 ) )
     345              :         {
     346            0 :             log<text_log>( "failed setting modbus socket timeouts", logPrio::LOG_WARNING );
     347              :         }
     348              : 
     349              :         { // mutex scope
     350            0 :             std::lock_guard<std::mutex> lock( m_modbusMutex );
     351            0 :             m_mb = newMb;
     352            0 :         }
     353              : 
     354            0 :         state( stateCodes::CONNECTED );
     355            0 :         log<text_log>( "connected to " + m_address + ":" + std::to_string( m_port ) );
     356              :     }
     357              : 
     358            0 :     if( state() == stateCodes::CONNECTED )
     359              :     {
     360            0 :         if( getState() == 0 )
     361              :         {
     362            0 :             state( stateCodes::READY );
     363            0 :             return 0;
     364              :         }
     365              :         else
     366              :         {
     367            0 :             state( stateCodes::ERROR );
     368            0 :             return log<software_error, 0>( { __FILE__, __LINE__ } );
     369              :         }
     370              :     }
     371              : 
     372            0 :     if( state() == stateCodes::READY || state() == stateCodes::OPERATING )
     373              :     {
     374            0 :         if( getState() < 0 )
     375              :         {
     376            0 :             if( m_powerState == 0 )
     377              :             {
     378            0 :                 return 0;
     379              :             }
     380              : 
     381            0 :             state( stateCodes::ERROR );
     382            0 :             return 0;
     383              :         }
     384              : 
     385            0 :         return 0;
     386              :     }
     387              : 
     388              :     // Fall through check?
     389              : 
     390            0 :     return 0;
     391              : }
     392              : 
     393            0 : inline int xt1121Ctrl::onPowerOff()
     394              : {
     395            0 :     std::lock_guard<std::mutex> lock( m_indiMutex );
     396              : 
     397            0 :     updateIfChanged( m_indiP_ch00, "current", -1 );
     398            0 :     updateIfChanged( m_indiP_ch00, "target", -1 );
     399              : 
     400            0 :     updateIfChanged( m_indiP_ch01, "current", -1 );
     401            0 :     updateIfChanged( m_indiP_ch01, "target", -1 );
     402              : 
     403            0 :     updateIfChanged( m_indiP_ch02, "current", -1 );
     404            0 :     updateIfChanged( m_indiP_ch02, "target", -1 );
     405              : 
     406            0 :     updateIfChanged( m_indiP_ch03, "current", -1 );
     407            0 :     updateIfChanged( m_indiP_ch03, "target", -1 );
     408              : 
     409            0 :     updateIfChanged( m_indiP_ch04, "current", -1 );
     410            0 :     updateIfChanged( m_indiP_ch04, "target", -1 );
     411              : 
     412            0 :     updateIfChanged( m_indiP_ch05, "current", -1 );
     413            0 :     updateIfChanged( m_indiP_ch05, "target", -1 );
     414              : 
     415            0 :     updateIfChanged( m_indiP_ch06, "current", -1 );
     416            0 :     updateIfChanged( m_indiP_ch06, "target", -1 );
     417              : 
     418            0 :     updateIfChanged( m_indiP_ch07, "current", -1 );
     419            0 :     updateIfChanged( m_indiP_ch07, "target", -1 );
     420              : 
     421            0 :     updateIfChanged( m_indiP_ch08, "current", -1 );
     422            0 :     updateIfChanged( m_indiP_ch08, "target", -1 );
     423              : 
     424            0 :     updateIfChanged( m_indiP_ch09, "current", -1 );
     425            0 :     updateIfChanged( m_indiP_ch09, "target", -1 );
     426              : 
     427            0 :     updateIfChanged( m_indiP_ch10, "current", -1 );
     428            0 :     updateIfChanged( m_indiP_ch10, "target", -1 );
     429              : 
     430            0 :     updateIfChanged( m_indiP_ch11, "current", -1 );
     431            0 :     updateIfChanged( m_indiP_ch11, "target", -1 );
     432              : 
     433            0 :     updateIfChanged( m_indiP_ch12, "current", -1 );
     434            0 :     updateIfChanged( m_indiP_ch12, "target", -1 );
     435              : 
     436            0 :     updateIfChanged( m_indiP_ch13, "current", -1 );
     437            0 :     updateIfChanged( m_indiP_ch13, "target", -1 );
     438              : 
     439            0 :     updateIfChanged( m_indiP_ch14, "current", -1 );
     440            0 :     updateIfChanged( m_indiP_ch14, "target", -1 );
     441              : 
     442            0 :     updateIfChanged( m_indiP_ch15, "current", -1 );
     443            0 :     updateIfChanged( m_indiP_ch15, "target", -1 );
     444              : 
     445            0 :     return 0;
     446            0 : }
     447              : 
     448            0 : inline int xt1121Ctrl::whilePowerOff()
     449              : {
     450            0 :     return 0;
     451              : }
     452              : 
     453            0 : inline int xt1121Ctrl::appShutdown()
     454              : {
     455            0 :     m_callbacksEnabled = false;
     456            0 :     closeModbus();
     457            0 :     return 0;
     458              : }
     459              : 
     460            1 : inline void xt1121Ctrl::closeModbus()
     461              : {
     462            1 :     std::lock_guard<std::mutex> lock( m_modbusMutex );
     463              : 
     464            1 :     if( !m_mb )
     465              :     {
     466            1 :         return;
     467              :     }
     468              : 
     469              :     try
     470              :     {
     471            0 :         m_mb->modbus_close();
     472              :     }
     473            0 :     catch( ... )
     474              :     {
     475            0 :     }
     476              : 
     477            0 :     delete m_mb;
     478            0 :     m_mb = nullptr;
     479            1 : }
     480              : 
     481            0 : inline int xt1121Ctrl::getState()
     482              : {
     483            0 :     if( shutdown() != 0 )
     484              :     {
     485            0 :         return 0;
     486              :     }
     487              : 
     488              :     uint16_t input_regs[numRegisters];
     489              : 
     490              :     { // mutex scope
     491            0 :         std::lock_guard<std::mutex> lock( m_modbusMutex );
     492              : 
     493            0 :         if( m_mb == nullptr )
     494              :         {
     495            0 :             return -1;
     496              :         }
     497              : 
     498              :         try
     499              :         {
     500            0 :             m_mb->modbus_read_input_registers( 0, numRegisters, input_regs );
     501              :         }
     502            0 :         catch( std::exception &e )
     503              :         {
     504            0 :             if( m_powerState == 0 )
     505              :             {
     506            0 :                 return 0; // due to power off
     507              :             }
     508              : 
     509            0 :             return log<software_error, -1>( { __FILE__, __LINE__, std::string( "Exception caught: " ) + e.what() } );
     510            0 :         }
     511            0 :     }
     512              : 
     513            0 :     std::lock_guard<std::mutex> lock( m_indiMutex );
     514            0 :     if( readRegisters( input_regs ) != 0 )
     515              :     {
     516            0 :         return log<software_error, -1>( { __FILE__, __LINE__ } );
     517              :     }
     518              : 
     519            0 :     updateIfChanged( m_indiP_ch00, "current", channel( 0 ) );
     520            0 :     updateIfChanged( m_indiP_ch01, "current", channel( 1 ) );
     521            0 :     updateIfChanged( m_indiP_ch02, "current", channel( 2 ) );
     522            0 :     updateIfChanged( m_indiP_ch03, "current", channel( 3 ) );
     523            0 :     updateIfChanged( m_indiP_ch04, "current", channel( 4 ) );
     524            0 :     updateIfChanged( m_indiP_ch05, "current", channel( 5 ) );
     525            0 :     updateIfChanged( m_indiP_ch06, "current", channel( 6 ) );
     526            0 :     updateIfChanged( m_indiP_ch07, "current", channel( 7 ) );
     527            0 :     updateIfChanged( m_indiP_ch08, "current", channel( 8 ) );
     528            0 :     updateIfChanged( m_indiP_ch09, "current", channel( 9 ) );
     529            0 :     updateIfChanged( m_indiP_ch10, "current", channel( 10 ) );
     530            0 :     updateIfChanged( m_indiP_ch11, "current", channel( 11 ) );
     531            0 :     updateIfChanged( m_indiP_ch12, "current", channel( 12 ) );
     532            0 :     updateIfChanged( m_indiP_ch13, "current", channel( 13 ) );
     533            0 :     updateIfChanged( m_indiP_ch14, "current", channel( 14 ) );
     534            0 :     updateIfChanged( m_indiP_ch15, "current", channel( 15 ) );
     535              : 
     536            0 :     return 0;
     537            0 : }
     538              : 
     539            0 : int xt1121Ctrl::channelSetCallback( size_t chNo, pcf::IndiProperty &ipToSet, const pcf::IndiProperty &ipRecv )
     540              : {
     541            0 :     if( !m_callbacksEnabled || shutdown() != 0 )
     542              :     {
     543            0 :         return 0;
     544              :     }
     545              : 
     546            0 :     int current = -1, target = -1;
     547              : 
     548            0 :     if( ipRecv.find( "current" ) )
     549              :     {
     550            0 :         current = ipRecv["current"].get<unsigned>();
     551              :     }
     552              : 
     553            0 :     if( ipRecv.find( "target" ) )
     554              :     {
     555            0 :         target = ipRecv["target"].get<unsigned>();
     556              :     }
     557              : 
     558            0 :     if( target == -1 )
     559              :     {
     560            0 :         target = current;
     561              :     }
     562              : 
     563            0 :     if( target < 0 )
     564              :     {
     565            0 :         return 0;
     566              :     }
     567              : 
     568              :     uint16_t input_regs[numRegisters];
     569              : 
     570              :     { // mutex scope
     571            0 :         std::lock_guard<std::mutex> lock( m_indiMutex );
     572              : 
     573            0 :         if( target == 0 )
     574              :         {
     575            0 :             clearChannel( chNo );
     576              :         }
     577              :         else
     578              :         {
     579            0 :             setChannel( chNo );
     580              :         }
     581              : 
     582            0 :         target = channel( chNo ); // This checks for inputOnly
     583              : 
     584            0 :         updateIfChanged( ipToSet, "target", target );
     585              : 
     586            0 :         if( setRegisters( input_regs ) != 0 )
     587              :         {
     588            0 :             return log<software_error, -1>( { __FILE__, __LINE__ } );
     589              :         }
     590            0 :     }
     591              : 
     592              :     { // mutex scope
     593            0 :         std::lock_guard<std::mutex> lock( m_modbusMutex );
     594              : 
     595            0 :         if( m_mb == nullptr )
     596              :         {
     597            0 :             return 0;
     598              :         }
     599              : 
     600              :         try
     601              :         {
     602            0 :             m_mb->modbus_write_registers( 0, numRegisters, input_regs );
     603              :         }
     604            0 :         catch( std::exception &e )
     605              :         {
     606            0 :             if( m_powerState == 0 )
     607              :             {
     608            0 :                 return 0; // due to power off
     609              :             }
     610              : 
     611            0 :             return log<software_error, -1>( { __FILE__, __LINE__, std::string( "Exception caught: " ) + e.what() } );
     612            0 :         }
     613            0 :     }
     614              : 
     615            0 :     log<text_log>( "Set channel " + std::to_string( chNo ) + " to " + std::to_string( target ) );
     616              : 
     617            0 :     return 0;
     618              : }
     619              : 
     620            0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch00 )( const pcf::IndiProperty &ipRecv )
     621              : {
     622            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch00, ipRecv );
     623              : 
     624            0 :     return channelSetCallback( 0, m_indiP_ch00, ipRecv );
     625              : 
     626              :     return -1;
     627              : }
     628              : 
     629            0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch01 )( const pcf::IndiProperty &ipRecv )
     630              : {
     631            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch01, ipRecv );
     632              : 
     633            0 :     return channelSetCallback( 1, m_indiP_ch01, ipRecv );
     634              : 
     635              :     return -1;
     636              : }
     637              : 
     638            0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch02 )( const pcf::IndiProperty &ipRecv )
     639              : {
     640            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch02, ipRecv );
     641              : 
     642            0 :     return channelSetCallback( 2, m_indiP_ch02, ipRecv );
     643              : 
     644              :     return -1;
     645              : }
     646              : 
     647            0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch03 )( const pcf::IndiProperty &ipRecv )
     648              : {
     649            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch03, ipRecv );
     650              : 
     651            0 :     return channelSetCallback( 3, m_indiP_ch03, ipRecv );
     652              : 
     653              :     return -1;
     654              : }
     655              : 
     656            0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch04 )( const pcf::IndiProperty &ipRecv )
     657              : {
     658            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch04, ipRecv );
     659              : 
     660            0 :     return channelSetCallback( 4, m_indiP_ch04, ipRecv );
     661              : 
     662              :     return -1;
     663              : }
     664              : 
     665            0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch05 )( const pcf::IndiProperty &ipRecv )
     666              : {
     667            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch05, ipRecv );
     668              : 
     669            0 :     return channelSetCallback( 5, m_indiP_ch05, ipRecv );
     670              : 
     671              :     return -1;
     672              : }
     673              : 
     674            0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch06 )( const pcf::IndiProperty &ipRecv )
     675              : {
     676            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch06, ipRecv );
     677              : 
     678            0 :     return channelSetCallback( 6, m_indiP_ch06, ipRecv );
     679              : 
     680              :     return -1;
     681              : }
     682              : 
     683            0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch07 )( const pcf::IndiProperty &ipRecv )
     684              : {
     685            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch07, ipRecv );
     686              : 
     687            0 :     return channelSetCallback( 7, m_indiP_ch07, ipRecv );
     688              : 
     689              :     return -1;
     690              : }
     691              : 
     692            0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch08 )( const pcf::IndiProperty &ipRecv )
     693              : {
     694            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch08, ipRecv );
     695              : 
     696            0 :     return channelSetCallback( 8, m_indiP_ch08, ipRecv );
     697              : 
     698              :     return -1;
     699              : }
     700              : 
     701            0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch09 )( const pcf::IndiProperty &ipRecv )
     702              : {
     703            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch09, ipRecv );
     704              : 
     705            0 :     return channelSetCallback( 9, m_indiP_ch09, ipRecv );
     706              : 
     707              :     return -1;
     708              : }
     709              : 
     710            0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch10 )( const pcf::IndiProperty &ipRecv )
     711              : {
     712            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch10, ipRecv );
     713              : 
     714            0 :     return channelSetCallback( 10, m_indiP_ch10, ipRecv );
     715              : 
     716              :     return -1;
     717              : }
     718              : 
     719            0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch11 )( const pcf::IndiProperty &ipRecv )
     720              : {
     721            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch11, ipRecv );
     722              : 
     723            0 :     return channelSetCallback( 11, m_indiP_ch11, ipRecv );
     724              : 
     725              :     return -1;
     726              : }
     727              : 
     728            0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch12 )( const pcf::IndiProperty &ipRecv )
     729              : {
     730            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch12, ipRecv );
     731              : 
     732            0 :     return channelSetCallback( 12, m_indiP_ch12, ipRecv );
     733              : 
     734              :     return -1;
     735              : }
     736              : 
     737            0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch13 )( const pcf::IndiProperty &ipRecv )
     738              : {
     739            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch13, ipRecv );
     740              : 
     741            0 :     return channelSetCallback( 13, m_indiP_ch13, ipRecv );
     742              : 
     743              :     return -1;
     744              : }
     745              : 
     746            0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch14 )( const pcf::IndiProperty &ipRecv )
     747              : {
     748            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch14, ipRecv );
     749              : 
     750            0 :     return channelSetCallback( 14, m_indiP_ch14, ipRecv );
     751              : 
     752              :     return -1;
     753              : }
     754              : 
     755            0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch15 )( const pcf::IndiProperty &ipRecv )
     756              : {
     757            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch15, ipRecv );
     758              : 
     759            0 :     return channelSetCallback( 15, m_indiP_ch15, ipRecv );
     760              : 
     761              :     return -1;
     762              : }
     763              : 
     764              : } // namespace app
     765              : } // namespace MagAOX
     766              : #endif
        

Generated by: LCOV version 2.0-1