LCOV - code coverage report
Current view: top level - apps/closedLoopIndi - closedLoopIndi.hpp (source / functions) Coverage Total Hit
Test: MagAOX Lines: 14.4 % 181 26
Test Date: 2026-01-03 21:03:39 Functions: 41.9 % 31 13

            Line data    Source code
       1              : /** \file closedLoopIndi.hpp
       2              :   * \brief The MagAO-X INDI Closed Loop header file
       3              :   *
       4              :   * \ingroup closedLoopIndi_files
       5              :   */
       6              : 
       7              : #ifndef closedLoopIndi_hpp
       8              : #define closedLoopIndi_hpp
       9              : 
      10              : 
      11              : #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
      12              : #include "../../magaox_git_version.h"
      13              : 
      14              : /** \defgroup closedLoopIndi
      15              :   * \brief The MagAO-X application to do closed-loop control using INDI properties
      16              :   *
      17              :   * <a href="../handbook/operating/software/apps/closedLoopIndi.html">Application Documentation</a>
      18              :   *
      19              :   * \ingroup apps
      20              :   *
      21              :   */
      22              : 
      23              : /** \defgroup closedLoopIndi_files
      24              :   * \ingroup closedLoopIndi
      25              :   */
      26              : 
      27              : namespace MagAOX
      28              : {
      29              : namespace app
      30              : {
      31              : 
      32              : /// The MagAO-X application to do closed-loop control using INDI properties
      33              : /**
      34              :   * \ingroup closedLoopIndi
      35              :   */
      36              : class closedLoopIndi : public MagAOXApp<true>
      37              : {
      38              :    //Give the test harness access.
      39              :    friend class closedLoopIndi_test;
      40              : 
      41              : protected:
      42              : 
      43              :     /** \name Configurable Parameters
      44              :       *@{
      45              :       */
      46              : 
      47              :     std::string m_inputDevice;                           ///< The device with the input disturbances and frame counter.
      48              :     std::string m_inputProperty;                         ///< The property with the input disturbances and frame counter.
      49              :     std::vector<std::string> m_inputElements {"x", "y"}; ///< The elements with the input disturbances.  Must be two, defaults are "x" and "y".
      50              :     std::string m_inputCounterElement {"counter"};       ///< The element with the frame counter, a monotonically increasing integer. Default is "counter".
      51              : 
      52              :     std::vector<std::string> m_ctrlDevices;                         ///< Device names of the controller(s). If only one, it's used for both properties.  Max two.
      53              :     std::vector<std::string> m_ctrlProperties;                      ///< Properties of the ctrl device(s) to which to give the commands. Must specify two.
      54              :     std::vector<std::string> m_ctrlCurrents {"current", "current"}; ///< current elements of the properties on which to base the commands. Must specify 0 or 2. Default is 'current'.
      55              :     std::vector<std::string> m_ctrlTargets {"target", "target"};    ///< target elements of the properties to which to send the commands. Must specify 0 or 2. Default is 'target'.
      56              : 
      57              :     mx::improc::eigenImage<float> m_references; ///< The reference values of the disturbances
      58              : 
      59              :     bool m_operatingOK {false}; ///< If true then it's ok for the ctrl device to be OPERATING when a command is sent
      60              : 
      61              :     std::unordered_map<std::string, std::string> m_fsmStates; ///< The FSM states of the control devices.
      62              : 
      63              :     std::vector<float> m_currents; ///< The current commands
      64              : 
      65              :     mx::improc::eigenImage<float> m_intMat; ///< The interaction matrix.  Default is [1 0][0 1].
      66              : 
      67              :     std::vector<float> m_defaultGains; ///< The default gains, per-axis
      68              : 
      69              :     std::string m_upstreamDevice;                  ///< The upstream device to monitor to automatically open this loop if it's loop opens
      70              :     std::string m_upstreamProperty {"loop_state"}; ///< The name of the toggle switch to monitor
      71              : 
      72              :     ///@}
      73              : 
      74              :     int64_t m_counter = -1; ///< The latest value of the loop counter
      75              :     mx::improc::eigenImage<float> m_measurements; ///< The latest value of the measurements
      76              :     float m_delta0 {0};
      77              :     float m_delta1 {0};
      78              : 
      79              :     mx::improc::eigenImage<float> m_commands; ///< The latest commands
      80              : 
      81              :     float m_ggain {0}; ///< The global gain
      82              : 
      83              :     std::vector<float> m_gains; ///< The axis gains
      84              : 
      85              :     bool m_loopClosed {false}; ///< Whether or not the loop is closed
      86              : 
      87              : public:
      88              :     /// Default c'tor.
      89              :     closedLoopIndi();
      90              : 
      91              :     /// D'tor, declared and defined for noexcept.
      92           33 :     ~closedLoopIndi() noexcept
      93           33 :     {}
      94              : 
      95              :     virtual void setupConfig();
      96              : 
      97              :     /// Implementation of loadConfig logic, separated for testing.
      98              :     /** This is called by loadConfig().
      99              :       */
     100              :     int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
     101              : 
     102              :     virtual void loadConfig();
     103              : 
     104              :     /// Startup function
     105              :     /**
     106              :       *
     107              :       */
     108              :     virtual int appStartup();
     109              : 
     110              :     /// Implementation of the FSM for closedLoopIndi.
     111              :     /**
     112              :       * \returns 0 on no critical error
     113              :       * \returns -1 on an error requiring shutdown
     114              :       */
     115              :     virtual int appLogic();
     116              : 
     117              :     /// Shutdown the app.
     118              :     /**
     119              :       *
     120              :       */
     121              :     virtual int appShutdown();
     122              : 
     123              :     /// Change the loop state
     124              :     int toggleLoop( bool onoff );
     125              : 
     126              :     /// Update the loop with a new command
     127              :     int updateLoop();
     128              : 
     129              :     /// Send commands to the control devices
     130              :     int sendCommands(std::vector<float> & commands);
     131              : 
     132              :     //INDI
     133              : 
     134              :     pcf::IndiProperty m_indiP_deltas;
     135              : 
     136              :     pcf::IndiProperty m_indiP_reference0;
     137            0 :     INDI_NEWCALLBACK_DECL(closedLoopIndi, m_indiP_reference0);
     138              : 
     139              :     pcf::IndiProperty m_indiP_reference1;
     140            0 :     INDI_NEWCALLBACK_DECL(closedLoopIndi, m_indiP_reference1);
     141              : 
     142              :     pcf::IndiProperty m_indiP_inputs;
     143            0 :     INDI_SETCALLBACK_DECL(closedLoopIndi, m_indiP_inputs);
     144              : 
     145              :     pcf::IndiProperty m_indiP_ggain;
     146            0 :     INDI_NEWCALLBACK_DECL(closedLoopIndi, m_indiP_ggain);
     147              : 
     148              :     pcf::IndiProperty m_indiP_ctrlEnabled;
     149            0 :     INDI_NEWCALLBACK_DECL(closedLoopIndi, m_indiP_ctrlEnabled);
     150              : 
     151              :     pcf::IndiProperty m_indiP_counterReset;
     152            0 :     INDI_NEWCALLBACK_DECL(closedLoopIndi, m_indiP_counterReset);
     153              : 
     154              :     pcf::IndiProperty m_indiP_ctrl0_fsm; ///< The INDI property for fsm state of axis 0
     155            0 :     INDI_SETCALLBACK_DECL(closedLoopIndi, m_indiP_ctrl0_fsm);
     156              : 
     157              :     pcf::IndiProperty m_indiP_ctrl0; ///< The INDI property used for control of axis 0
     158            0 :     INDI_SETCALLBACK_DECL(closedLoopIndi, m_indiP_ctrl0);
     159              : 
     160              :     pcf::IndiProperty m_indiP_ctrl1_fsm; ///< The INDI property for fsm state of axis 1
     161            0 :     INDI_SETCALLBACK_DECL(closedLoopIndi, m_indiP_ctrl1_fsm);
     162              : 
     163              :     pcf::IndiProperty m_indiP_ctrl1; ///< The INDI property used for control of axis 1
     164            0 :     INDI_SETCALLBACK_DECL(closedLoopIndi, m_indiP_ctrl1);
     165              : 
     166              :     pcf::IndiProperty m_indiP_upstream; ///< Property used to report the upstream loop state
     167            0 :     INDI_SETCALLBACK_DECL(closedLoopIndi, m_indiP_upstream);
     168              : };
     169              : 
     170          429 : closedLoopIndi::closedLoopIndi() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
     171              : {
     172           33 :     return;
     173            0 : }
     174              : 
     175            0 : void closedLoopIndi::setupConfig()
     176              : {
     177            0 :     config.add("input.device", "", "input.device", argType::Required, "input", "device", false, "string", "The device with the input disturbances and frame counter.");
     178            0 :     config.add("input.property", "", "input.property", argType::Required, "input", "property", false, "string", "The property with the input disturbances and counter.");
     179            0 :     config.add("input.elements", "", "input.elements", argType::Required, "input", "elements", false, "vector<string>", " The elements with the input disturbances.  Must be two, defaults are 'x' and 'y'.");
     180            0 :     config.add("input.counterElement", "", "input.counterElement", argType::Required, "input", "counterElement", false, "string", "The element with the frame counter, a monotonically increasing integer. Default is 'counter'.");
     181              : 
     182            0 :     config.add("input.references", "", "input.references", argType::Required, "input", "references", false, "vector<float>", "The reference values for the input disturbances.");
     183              : 
     184            0 :     config.add("ctrl.devices", "", "ctrl.devices", argType::Required, "ctrl", "devices", false, "string", "Device names of the controller(s). If only one, it's used for both properties.  Max two.");
     185            0 :     config.add("ctrl.properties", "", "ctrl.properties", argType::Required, "ctrl", "properties", false, "string", "Properties of the ctrl device(s) to which to give the commands. Must specify two.");
     186            0 :     config.add("ctrl.currents", "", "ctrl.currents", argType::Required, "ctrl", "currents", false, "vector<string>", "current elements of the properties on which to base the commands. Must specify 0 or 2. Default is 'current'");
     187            0 :     config.add("ctrl.targets", "", "ctrl.targets", argType::Required, "ctrl", "targets", false, "vector<string>", "target elements of the properties to which to send the commands. Must specify 0 or 2. Default is 'target'.");
     188            0 :     config.add("ctrl.operatingOK", "", "ctrl.operatingOK", argType::Required, "ctrl", "operatingOK", false, "bool", "If true then it's ok for the ctrl device to be OPERATING when a command is sent. Default is false.");
     189              : 
     190              : 
     191            0 :     config.add("loop.intMat00", "", "loop.intMat00", argType::Required, "loop", "intMat00", false, "float", "element (0,0) of the interaction matrix. Default is 1.");
     192            0 :     config.add("loop.intMat01", "", "loop.intMat01", argType::Required, "loop", "intMat01", false, "float", "element (0,1) of the interaction matrix. Default is 0.");
     193            0 :     config.add("loop.intMat10", "", "loop.intMat10", argType::Required, "loop", "intMat10", false, "float", "element (1,0) of the interaction matrix. Default is 0.");
     194            0 :     config.add("loop.intMat11", "", "loop.intMat11", argType::Required, "loop", "intMat11", false, "float", "element (1,1) of the interaction matrix. Default is 1.");
     195              : 
     196            0 :     config.add("loop.gain", "", "loop.gain", argType::Required, "loop", "gain", false, "float", "default global loop gain.");
     197            0 :     config.add("loop.gains", "", "loop.gains", argType::Required, "loop", "gains", false, "vector<float>", "default loop gains.  If single number, it is applied to all axes.");
     198            0 :     config.add("loop.upstream", "", "loop.upstream", argType::Required, "loop", "upstream", false, "string", "Upstream loop device name.  This loop will open, and optionally close, with the upstream loop.  Default none.");
     199            0 :     config.add("loop.upstreamProperty", "", "loop.upstreamProperty", argType::Required, "loop", "upstreamProperty", false, "string", "Property of upstream loop device to follow.  Must be a toggle.  Default is loop_state.");
     200              : 
     201            0 : }
     202              : 
     203            0 : int closedLoopIndi::loadConfigImpl( mx::app::appConfigurator & _config )
     204              : {
     205            0 :     _config(m_inputDevice, "input.device");
     206            0 :     _config(m_inputProperty, "input.property");
     207            0 :     _config(m_inputElements, "input.elements");
     208            0 :     _config(m_inputCounterElement, "input.counterElement");
     209              : 
     210            0 :     if(m_inputDevice == "")
     211              :     {
     212            0 :         m_shutdown = 1;
     213            0 :         return log<software_error, -1>({__FILE__, __LINE__, "no input device specified"});
     214              :     }
     215              : 
     216            0 :     if(m_inputProperty == "")
     217              :     {
     218            0 :         m_shutdown = 1;
     219            0 :         return log<software_error, -1>({__FILE__, __LINE__, "no input property specified"});
     220              :     }
     221              : 
     222            0 :     if(m_inputElements.size() != 2)
     223              :     {
     224            0 :         m_shutdown = 1;
     225            0 :         return log<software_error, -1>({__FILE__, __LINE__, "must specify only two input.elements"});
     226              :     }
     227              : 
     228            0 :     std::vector<float> refs({0,0});
     229            0 :     _config(refs, "input.references");
     230            0 :     if(refs.size() != 2)
     231              :     {
     232            0 :         m_shutdown = 1;
     233            0 :         return log<software_error, -1>({__FILE__, __LINE__, "input.references must have 2 elements"});
     234              :     }
     235              : 
     236            0 :     m_references.resize(2,1);
     237            0 :     m_references(0,0) = refs[0];
     238            0 :     m_references(1,0) = refs[1];
     239              : 
     240            0 :     _config(m_ctrlDevices, "ctrl.devices");
     241            0 :     _config(m_ctrlProperties, "ctrl.properties");
     242            0 :     _config(m_ctrlCurrents, "ctrl.currents");
     243            0 :     _config(m_ctrlTargets, "ctrl.targets");
     244            0 :     _config(m_operatingOK, "ctrl.operatingOK");
     245              : 
     246            0 :     if(m_ctrlDevices.size() == 1)
     247              :     {
     248            0 :         m_ctrlDevices.push_back(m_ctrlDevices[0]);
     249              :     }
     250            0 :     else if(m_ctrlDevices.size() != 2)
     251              :     {
     252            0 :         m_shutdown = 1;
     253            0 :         return log<software_error, -1>({__FILE__, __LINE__, "must specify two ctrl.devices"});
     254              :     }
     255              : 
     256            0 :     if(m_ctrlProperties.size() != 2)
     257              :     {
     258            0 :         m_shutdown = 1;
     259            0 :         return log<software_error, -1>({__FILE__, __LINE__, "must specify two ctrl.properties"});
     260              :     }
     261              : 
     262            0 :     if(m_ctrlTargets.size() != 2)
     263              :     {
     264            0 :         m_shutdown = 1;
     265            0 :         return log<software_error, -1>({__FILE__, __LINE__, "must specify two ctrl.targets"});
     266              :     }
     267              : 
     268            0 :     if(m_ctrlCurrents.size() != 2)
     269              :     {
     270            0 :         m_shutdown = 1;
     271            0 :         return log<software_error, -1>({__FILE__, __LINE__, "must specify two ctrl.currents"});
     272              :     }
     273              : 
     274            0 :     if(m_ctrlTargets.size() != 2)
     275              :     {
     276            0 :         m_shutdown = 1;
     277            0 :         return log<software_error, -1>({__FILE__, __LINE__, "must specify two ctrl.targets"});
     278              :     }
     279              : 
     280            0 :     float im00 = 1;
     281            0 :     float im01 = 0;
     282            0 :     float im10 = 0;
     283            0 :     float im11 = 1;
     284              : 
     285            0 :     _config(im00, "loop.intMat00");
     286            0 :     _config(im01, "loop.intMat01");
     287            0 :     _config(im10, "loop.intMat10");
     288            0 :     _config(im11, "loop.intMat11");
     289              : 
     290            0 :     m_intMat.resize(2, 2);
     291            0 :     m_intMat(0,0) = im00;
     292            0 :     m_intMat(0,1) = im01;
     293            0 :     m_intMat(1,0) = im10;
     294            0 :     m_intMat(1,1) = im11;
     295              : 
     296            0 :     _config(m_ggain, "loop.gain");
     297              : 
     298            0 :     _config(m_defaultGains, "loop.gains");
     299            0 :     _config(m_upstreamDevice, "loop.upstream");
     300            0 :     _config(m_upstreamProperty, "loop.upstreamProperty");
     301              : 
     302            0 :     return 0;
     303            0 : }
     304              : 
     305            0 : void closedLoopIndi::loadConfig()
     306              : {
     307            0 :    loadConfigImpl(config);
     308            0 : }
     309              : 
     310            0 : int closedLoopIndi::appStartup()
     311              : {
     312            0 :     REG_INDI_SETPROP(m_indiP_inputs, m_inputDevice, m_inputProperty);
     313              : 
     314            0 :     CREATE_REG_INDI_RO_NUMBER( m_indiP_deltas, "deltas", "Deltas", "Deltas");
     315            0 :     m_indiP_deltas.add(pcf::IndiElement("delta0"));
     316            0 :     m_indiP_deltas["delta0"] = 0;
     317            0 :     m_indiP_deltas.add(pcf::IndiElement("delta1"));
     318            0 :     m_indiP_deltas["delta1"] = 0;
     319              : 
     320            0 :     CREATE_REG_INDI_NEW_NUMBERF( m_indiP_reference0, "reference0", -1e15, 1e15, 1, "%g", "reference0", "references");
     321            0 :     m_indiP_reference0["current"] = m_references(0,0);
     322            0 :     m_indiP_reference0["target"] = m_references(0,0);
     323              : 
     324            0 :     CREATE_REG_INDI_NEW_NUMBERF( m_indiP_reference1, "reference1", -1e15, 1e15, 1, "%g", "reference1", "references");
     325            0 :     m_indiP_reference1["current"] = m_references(1,0);
     326            0 :     m_indiP_reference1["target"] = m_references(1,0);
     327              : 
     328            0 :     if(m_ctrlTargets.size() != m_defaultGains.size())
     329              :     {
     330            0 :         if(m_defaultGains.size()==1)
     331              :         {
     332            0 :             m_defaultGains.push_back(m_defaultGains[0]);
     333            0 :            log<text_log>("Setting loop.gains gains to be same size as ctrl.Targets", logPrio::LOG_NOTICE);
     334              :         }
     335              :         else
     336              :         {
     337            0 :            return log<software_error, -1>({__FILE__, __LINE__, "ctrl.Targets and loop.gains are not the same size"});
     338              :         }
     339              :     }
     340              : 
     341            0 :     m_gains.resize(m_defaultGains.size());
     342            0 :     for(size_t n=0; n < m_defaultGains.size(); ++n) m_gains[n] = m_defaultGains[n];
     343              : 
     344            0 :     CREATE_REG_INDI_NEW_NUMBERU( m_indiP_ggain, "loop_gain", 0, 1, 0, "%0.2f", "gain", "loop");
     345            0 :     m_indiP_ggain["current"] = m_ggain;
     346            0 :     m_indiP_ggain["target"] = m_ggain;
     347              : 
     348              : 
     349            0 :     CREATE_REG_INDI_NEW_TOGGLESWITCH( m_indiP_ctrlEnabled, "loop_state");
     350              : 
     351            0 :     CREATE_REG_INDI_NEW_REQUESTSWITCH( m_indiP_counterReset, "counter_reset");
     352              : 
     353            0 :     m_measurements.resize(2,1);
     354            0 :     m_measurements.setZero();
     355              : 
     356            0 :     m_currents.resize(m_ctrlDevices.size(), -1e15);
     357              : 
     358            0 :     REG_INDI_SETPROP(m_indiP_ctrl0_fsm, m_ctrlDevices[0], "fsm");
     359              : 
     360            0 :     REG_INDI_SETPROP(m_indiP_ctrl0, m_ctrlDevices[0], m_ctrlProperties[0]);
     361              : 
     362            0 :     if(m_ctrlDevices[1] != m_ctrlDevices[0])
     363              :     {
     364            0 :         REG_INDI_SETPROP(m_indiP_ctrl1_fsm, m_ctrlDevices[1], "fsm");
     365              :     }
     366              : 
     367            0 :     REG_INDI_SETPROP(m_indiP_ctrl1, m_ctrlDevices[1], m_ctrlProperties[1]);
     368              : 
     369            0 :     m_commands.resize(2, 2);
     370            0 :     m_commands.setZero();
     371              : 
     372              :     //Get the loop state for managing offloading
     373            0 :     if(m_upstreamDevice != "")
     374              :     {
     375            0 :         REG_INDI_SETPROP(m_indiP_upstream, m_upstreamDevice, m_upstreamProperty);
     376              :     }
     377              : 
     378            0 :     return 0;
     379              : }
     380              : 
     381            0 : int closedLoopIndi::appLogic()
     382              : {
     383            0 :     if(m_loopClosed)
     384              :     {
     385            0 :         state(stateCodes::OPERATING);
     386              :     }
     387              :     else
     388              :     {
     389            0 :         state(stateCodes::READY);
     390              :     }
     391              : 
     392            0 :     return 0;
     393              : }
     394              : 
     395            0 : int closedLoopIndi::appShutdown()
     396              : {
     397            0 :     return 0;
     398              : }
     399              : 
     400            0 : int closedLoopIndi::toggleLoop(bool onoff)
     401              : {
     402            0 :    if(!m_loopClosed && onoff) //not enabled so change
     403              :    {
     404            0 :       m_loopClosed = true;
     405            0 :       log<loop_closed>();
     406            0 :       updateSwitchIfChanged(m_indiP_ctrlEnabled, "toggle", pcf::IndiElement::On, INDI_OK);
     407            0 :       return 0;
     408              :    }
     409              : 
     410            0 :    if(m_loopClosed && !onoff)
     411              :    {
     412            0 :       m_loopClosed = false;
     413            0 :       log<loop_open>();
     414            0 :       updateSwitchIfChanged(m_indiP_ctrlEnabled, "toggle", pcf::IndiElement::Off, INDI_IDLE);
     415              : 
     416            0 :       return 0;
     417              :    }
     418              : 
     419            0 :    return 0;
     420              : }
     421              : 
     422              : 
     423              : inline
     424              : int closedLoopIndi::updateLoop()
     425              : {
     426              :     bool ready = false;
     427              : 
     428              :     //This should only give ready == true if all devices exist and are ready
     429              :     for(size_t n = 0; n < m_ctrlDevices.size(); ++n)
     430              :     {
     431              :         if(m_fsmStates.count(m_ctrlDevices[n]) > 0)
     432              :         {
     433              :             if(m_fsmStates[m_ctrlDevices[n]] == "READY" || (m_operatingOK && m_fsmStates[m_ctrlDevices[n]] == "OPERATING")  )
     434              :             {
     435              :                 ready = true;
     436              :             }
     437              :             else
     438              :             {
     439              :                 ready = false;
     440              :                 break;
     441              :             }
     442              :         }
     443              :         else
     444              :         {
     445              :             ready = false;
     446              :             break;
     447              :         }
     448              :     }
     449              : 
     450              :     if(ready != true)
     451              :     {
     452              :         return 0;
     453              :     }
     454              : 
     455              :     m_delta0 = m_measurements(0,0) - m_references(0,0);
     456              :     m_delta1 = m_measurements(1,0) - m_references(1,0);
     457              : 
     458              :     m_commands.matrix() = m_intMat.matrix() * (m_measurements - m_references).matrix();
     459              : 
     460              :     std::vector<float> commands;
     461              :     commands.resize(m_measurements.rows());
     462              : 
     463              :     for(int cc = 0; cc < m_measurements.rows(); ++cc)
     464              :     {
     465              :         commands[cc] = m_currents[cc] - m_ggain*m_gains[cc]*m_commands(cc,0);
     466              :     }
     467              : 
     468              :     //And send commands.
     469              :     int rv;
     470              :     if(m_loopClosed)
     471              :     {
     472              :         rv = sendCommands(commands);
     473              :     }
     474              :     else
     475              :     {
     476              :         rv = 0;
     477              :     }
     478              : 
     479              :     updateIfChanged(m_indiP_deltas, std::vector<std::string>({"delta0", "delta1"}), std::vector<float>({m_delta0, m_delta1}));
     480              :     return rv;
     481              : }
     482              : 
     483              : inline
     484              : int closedLoopIndi::sendCommands(std::vector<float> & commands)
     485              : {
     486              :     for(size_t n=0; n < m_ctrlDevices.size(); ++n)
     487              :     {
     488              :        pcf::IndiProperty ip(pcf::IndiProperty::Number);
     489              : 
     490              :        ip.setDevice(m_ctrlDevices[n]);
     491              :        ip.setName(m_ctrlProperties[n]);
     492              :        ip.add(pcf::IndiElement(m_ctrlTargets[n]));
     493              :        ip[m_ctrlTargets[n]] = commands[n];
     494              : 
     495              :        sendNewProperty(ip);
     496              :     }
     497              : 
     498              :     return 0;
     499              : }
     500              : 
     501            3 : INDI_NEWCALLBACK_DEFN(closedLoopIndi, m_indiP_reference0)(const pcf::IndiProperty &ipRecv)
     502              : {
     503            3 :     INDI_VALIDATE_CALLBACK_PROPS(ipRecv, m_indiP_reference0);
     504              : 
     505              :     float target;
     506              : 
     507              :     if( indiTargetUpdate( m_indiP_reference0, target, ipRecv, true) < 0)
     508              :     {
     509              :        return log<software_error, -1>({__FILE__,__LINE__});
     510              :     }
     511              : 
     512              :     m_references(0,0) = target;
     513              : 
     514              :     updateIfChanged(m_indiP_reference0, std::vector<std::string>({"current", "target"}), std::vector<float>({m_references(0,0), m_references(0,0)}));
     515              : 
     516              :     log<text_log>("set reference0 to " + std::to_string(m_references(0,0)), logPrio::LOG_NOTICE);
     517              : 
     518              :     return 0;
     519              : }
     520              : 
     521            3 : INDI_NEWCALLBACK_DEFN(closedLoopIndi, m_indiP_reference1)(const pcf::IndiProperty &ipRecv)
     522              : {
     523            3 :     INDI_VALIDATE_CALLBACK_PROPS(ipRecv, m_indiP_reference1);
     524              : 
     525              :     float target;
     526              : 
     527              :     if( indiTargetUpdate( m_indiP_reference1, target, ipRecv, true) < 0)
     528              :     {
     529              :        return log<software_error, -1>({__FILE__,__LINE__});
     530              :     }
     531              : 
     532              :     m_references(1,0) = target;
     533              : 
     534              :     updateIfChanged(m_indiP_reference1, std::vector<std::string>({"current", "target"}), std::vector<float>({m_references(1,0), m_references(1,0)}));
     535              : 
     536              :     log<text_log>("set reference1 to " + std::to_string(m_references(1,0)), logPrio::LOG_NOTICE);
     537              : 
     538              :     return 0;
     539              : }
     540              : 
     541            3 : INDI_SETCALLBACK_DEFN(closedLoopIndi, m_indiP_inputs)(const pcf::IndiProperty &ipRecv)
     542              : {
     543            3 :     INDI_VALIDATE_CALLBACK_PROPS(ipRecv, m_indiP_inputs)
     544              : 
     545              :     if(!ipRecv.find(m_inputElements[0])) return -1;
     546              :     if(!ipRecv.find(m_inputElements[1])) return -1;
     547              :     if(!ipRecv.find(m_inputCounterElement)) return -1;
     548              : 
     549              :     int counter = ipRecv[m_inputCounterElement].get<int>();
     550              : 
     551              :     if(counter != m_counter)
     552              :     {
     553              :         m_counter = counter;
     554              :         m_measurements(0,0) = ipRecv[m_inputElements[0]].get<float>();
     555              :         m_measurements(1,0) = ipRecv[m_inputElements[1]].get<float>();
     556              : 
     557              :         return updateLoop();
     558              :     }
     559              : 
     560              :     return 0;
     561              : }
     562              : 
     563            3 : INDI_NEWCALLBACK_DEFN(closedLoopIndi, m_indiP_ggain)(const pcf::IndiProperty &ipRecv)
     564              : {
     565            3 :     INDI_VALIDATE_CALLBACK_PROPS(ipRecv, m_indiP_ggain);
     566              : 
     567              :     float target;
     568              : 
     569              :     if( indiTargetUpdate( m_indiP_ggain, target, ipRecv, true) < 0)
     570              :     {
     571              :        log<software_error>({__FILE__,__LINE__});
     572              :        return -1;
     573              :     }
     574              : 
     575              :     m_ggain = target;
     576              : 
     577              :     updateIfChanged(m_indiP_ggain, "current", m_ggain);
     578              :     updateIfChanged(m_indiP_ggain, "target", m_ggain);
     579              : 
     580              :     log<text_log>("set global gain to " + std::to_string(m_ggain), logPrio::LOG_NOTICE);
     581              : 
     582              :     return 0;
     583              : }
     584              : 
     585            3 : INDI_NEWCALLBACK_DEFN(closedLoopIndi, m_indiP_ctrlEnabled)(const pcf::IndiProperty &ipRecv)
     586              : {
     587            3 :     INDI_VALIDATE_CALLBACK_PROPS(ipRecv, m_indiP_ctrlEnabled);
     588              : 
     589              :     //switch is toggled to on
     590              :     if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On)
     591              :     {
     592              :        return toggleLoop(true);
     593              :     }
     594              : 
     595              :     //switch is toggle to off
     596              :     if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off)
     597              :     {
     598              :        return toggleLoop(false);
     599              :     }
     600              : 
     601              :     return 0;
     602              : }
     603              : 
     604            3 : INDI_NEWCALLBACK_DEFN(closedLoopIndi, m_indiP_counterReset)(const pcf::IndiProperty &ipRecv)
     605              : {
     606            3 :     INDI_VALIDATE_CALLBACK_PROPS(ipRecv, m_indiP_counterReset);
     607              : 
     608              :     //switch is toggled to on
     609              :     if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
     610              :     {
     611              :        m_counter = -1;
     612              :     }
     613              : 
     614              : 
     615              :     return 0;
     616              : }
     617              : 
     618            3 : INDI_SETCALLBACK_DEFN(closedLoopIndi, m_indiP_ctrl0_fsm)(const pcf::IndiProperty &ipRecv)
     619              : {
     620            3 :     INDI_VALIDATE_CALLBACK_PROPS(ipRecv, m_indiP_ctrl0_fsm);
     621              : 
     622              :     if(ipRecv.find("state"))
     623              :     {
     624              :         m_fsmStates[ipRecv.getDevice()] = ipRecv["state"].get();
     625              :     }
     626              : 
     627              :    return 0;
     628              : }
     629              : 
     630            3 : INDI_SETCALLBACK_DEFN(closedLoopIndi, m_indiP_ctrl0)(const pcf::IndiProperty &ipRecv)
     631              : {
     632            3 :     INDI_VALIDATE_CALLBACK_PROPS(ipRecv, m_indiP_ctrl0);
     633              : 
     634              :     if(ipRecv.find(m_ctrlCurrents[0]))
     635              :     {
     636              :         m_currents[0] = ipRecv[m_ctrlCurrents[0]].get<float>();
     637              :     }
     638              : 
     639              :    return 0;
     640              : }
     641              : 
     642            3 : INDI_SETCALLBACK_DEFN(closedLoopIndi, m_indiP_ctrl1_fsm)(const pcf::IndiProperty &ipRecv)
     643              : {
     644            3 :     INDI_VALIDATE_CALLBACK_PROPS(ipRecv, m_indiP_ctrl1_fsm);
     645              : 
     646              :     if(ipRecv.find("state"))
     647              :     {
     648              :         m_fsmStates[ipRecv.getDevice()] = ipRecv["state"].get();
     649              :     }
     650              : 
     651              :    return 0;
     652              : }
     653              : 
     654            3 : INDI_SETCALLBACK_DEFN(closedLoopIndi, m_indiP_ctrl1)(const pcf::IndiProperty &ipRecv)
     655              : {
     656            3 :     INDI_VALIDATE_CALLBACK_PROPS(ipRecv, m_indiP_ctrl1);
     657              : 
     658              :     if(ipRecv.find(m_ctrlCurrents[1]))
     659              :     {
     660              :         m_currents[1] = ipRecv[m_ctrlCurrents[1]].get<float>();
     661              :     }
     662              : 
     663              :    return 0;
     664              : }
     665              : 
     666            3 : INDI_SETCALLBACK_DEFN(closedLoopIndi, m_indiP_upstream)(const pcf::IndiProperty &ipRecv)
     667              : {
     668            3 :     INDI_VALIDATE_CALLBACK_PROPS(ipRecv, m_indiP_upstream);
     669              : 
     670              :     if(!ipRecv.find("toggle")) return 0;
     671              : 
     672              :     if(ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On)
     673              :     {
     674              :        std::cerr << "upstream on\n";
     675              :        return toggleLoop(true);
     676              :     }
     677              :     else if(ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off)
     678              :     {
     679              :        std::cerr << "upstream off\n";
     680              :        return toggleLoop(false);
     681              :     }
     682              : 
     683              :     return 0;
     684              : }
     685              : 
     686              : 
     687              : } //namespace app
     688              : } //namespace MagAOX
     689              : 
     690              : #endif //closedLoopIndi_hpp
        

Generated by: LCOV version 2.0-1