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

            Line data    Source code
       1              : /** \file alignLoop.hpp
       2              :   * \brief The MagAO-X XXXXXX header file
       3              :   *
       4              :   * \ingroup alignLoop_files
       5              :   */
       6              : 
       7              : #ifndef alignLoop_hpp
       8              : #define alignLoop_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 alignLoop
      15              :   * \brief The XXXXXX application to do YYYYYYY
      16              :   *
      17              :   * <a href="../handbook/operating/software/apps/XXXXXX.html">Application Documentation</a>
      18              :   *
      19              :   * \ingroup apps
      20              :   *
      21              :   */
      22              : 
      23              : /** \defgroup alignLoop_files
      24              :   * \ingroup alignLoop
      25              :   */
      26              : 
      27              : namespace MagAOX
      28              : {
      29              : namespace app
      30              : {
      31              : 
      32              : /// The MagAO-X xxxxxxxx
      33              : /**
      34              :   * \ingroup alignLoop
      35              :   */
      36              : class alignLoop : public MagAOXApp<true>, public dev::shmimMonitor<alignLoop>
      37              : {
      38              :    //Give the test harness access.
      39              :    friend class alignLoop_test;
      40              : 
      41              :    friend class dev::shmimMonitor<alignLoop>;
      42              : 
      43              : public:
      44              :    //The base shmimMonitor type
      45              :    typedef dev::shmimMonitor<alignLoop> shmimMonitorT;
      46              : 
      47              : protected:
      48              : 
      49              :    /** \name Configurable Parameters
      50              :      *@{
      51              :      */
      52              : 
      53              :    std::vector<std::string> m_ctrlDevices;
      54              :    std::vector<std::string> m_ctrlProperties;
      55              :    std::vector<std::string> m_ctrlCurrents;
      56              :    std::vector<std::string> m_ctrlTargets;
      57              : 
      58              :    std::vector<float> m_currents;
      59              : 
      60              :    std::vector<pcf::IndiProperty> m_indiP_ctrl;
      61              : 
      62              :    std::string m_intMatFile;
      63              : 
      64              :    std::vector<float> m_defaultGains;
      65              : 
      66              :    std::string m_upstreamDevice;
      67              :    std::string m_upstreamProperty {"loop_state"};
      68              :    bool m_upstreamFollowClosed {false};
      69              : 
      70              : 
      71              :    ///@}
      72              : 
      73              :    mx::improc::eigenImage<float> m_intMat;
      74              : 
      75              :    mx::improc::eigenImage<float> m_measurements;
      76              :    float m_delta0 {0};
      77              :    float m_delta1 {0};
      78              : 
      79              :    mx::improc::eigenImage<float> m_commands;
      80              : 
      81              :    float m_ggain {0};
      82              : 
      83              :    std::vector<float> m_gains;
      84              : 
      85              :    bool m_ctrlEnabled {false};
      86              : 
      87              : public:
      88              :    /// Default c'tor.
      89              :    alignLoop();
      90              : 
      91              :    /// D'tor, declared and defined for noexcept.
      92            0 :    ~alignLoop() noexcept
      93            0 :    {}
      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 alignLoop.
     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              :    int toggleLoop( bool onoff );
     124              : 
     125              :    // shmimMonitor interface:
     126              :    int allocate( const dev::shmimT &);
     127              : 
     128              :    int processImage( void* curr_src,
     129              :                      const dev::shmimT &
     130              :                     );
     131              : 
     132              :    int sendCommands(std::vector<float> & commands);
     133              : 
     134              :    //INDI
     135              : 
     136              :    pcf::IndiProperty m_indiP_deltas;
     137              : 
     138              :    pcf::IndiProperty m_indiP_ggain;
     139              :    pcf::IndiProperty m_indiP_ctrlEnabled;
     140              : 
     141            0 :    INDI_NEWCALLBACK_DECL(alignLoop, m_indiP_ggain);
     142            0 :    INDI_NEWCALLBACK_DECL(alignLoop, m_indiP_ctrlEnabled);
     143              : 
     144            0 :    static int st_setCallBack_ctrl( void * app, const pcf::IndiProperty &ipRecv)
     145              :    {
     146            0 :       return static_cast<alignLoop *>(app)->setCallBack_ctrl(ipRecv);
     147              :    }
     148              : 
     149              :    int setCallBack_ctrl(const pcf::IndiProperty &ipRecv);
     150              : 
     151              :    int m_upstreamState {0};
     152              :    pcf::IndiProperty m_indiP_upstream; ///< Property used to report the loop state
     153              : 
     154            0 :    INDI_SETCALLBACK_DECL(alignLoop, m_indiP_upstream);
     155              : };
     156              : 
     157            0 : alignLoop::alignLoop() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
     158              : {
     159              : 
     160            0 :    return;
     161            0 : }
     162              : 
     163            0 : void alignLoop::setupConfig()
     164              : {
     165            0 :    shmimMonitorT::setupConfig(config);
     166              : 
     167            0 :    config.add("ctrl.devices", "", "ctrl.devices", argType::Required, "ctrl", "devices", false, "string", "Device names of the controller(s) (one per element).");
     168            0 :    config.add("ctrl.properties", "", "ctrl.properties", argType::Required, "ctrl", "properties", false, "string", "Properties of the ctrl devices to which to give the commands. One per element");
     169            0 :    config.add("ctrl.currents", "", "ctrl.currents", argType::Required, "ctrl", "currents", false, "vector<string>", "current elements of the properties on which base the commands.");
     170            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.");
     171              : 
     172            0 :    config.add("loop.gain", "", "loop.gain", argType::Required, "loop", "gain", false, "float", "default global loop gain.");
     173            0 :    config.add("loop.intMat", "", "loop.intMat", argType::Required, "loop", "intMat", false, "string", "file name of the interaction matrix.");
     174            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.");
     175            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.");
     176            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.");
     177              : 
     178            0 : }
     179              : 
     180            0 : int alignLoop::loadConfigImpl( mx::app::appConfigurator & _config )
     181              : {
     182            0 :    shmimMonitorT::loadConfig(_config);
     183              : 
     184            0 :    _config(m_ctrlDevices, "ctrl.devices");
     185            0 :    _config(m_ctrlProperties, "ctrl.properties");
     186            0 :    _config(m_ctrlCurrents, "ctrl.currents");
     187            0 :    _config(m_ctrlTargets, "ctrl.targets");
     188            0 :    _config(m_ggain, "loop.gain");
     189            0 :    _config(m_intMatFile, "loop.intMat");
     190            0 :    _config(m_defaultGains, "loop.gains");
     191            0 :    _config(m_upstreamDevice, "loop.upstream");
     192            0 :    _config(m_upstreamProperty, "loop.upstreamProperty");
     193            0 :    return 0;
     194              : }
     195              : 
     196            0 : void alignLoop::loadConfig()
     197              : {
     198            0 :    loadConfigImpl(config);
     199            0 : }
     200              : 
     201            0 : int alignLoop::appStartup()
     202              : {
     203            0 :    if(shmimMonitorT::appStartup() < 0)
     204              :    {
     205            0 :       return log<software_error,-1>({__FILE__, __LINE__});
     206              :    }
     207              : 
     208            0 :    if(m_ctrlTargets.size() != m_ctrlDevices.size())
     209              :    {
     210            0 :       return log<software_error, -1>({__FILE__, __LINE__, "ctrl.Targets and ctrl.devices are not the same size"});
     211              :    }
     212              : 
     213            0 :    if(m_ctrlTargets.size() != m_ctrlProperties.size())
     214              :    {
     215            0 :       return log<software_error, -1>({__FILE__, __LINE__, "ctrl.Targets and ctrl.properties are not the same size"});
     216              :    }
     217              : 
     218            0 :    if(m_ctrlTargets.size() != m_ctrlCurrents.size())
     219              :    {
     220            0 :       return log<software_error, -1>({__FILE__, __LINE__, "ctrl.Currents and ctrl.properties are not the same size"});
     221              :    }
     222              : 
     223            0 :    if(m_ctrlTargets.size() != m_defaultGains.size())
     224              :    {
     225            0 :       if(m_defaultGains.size()==1)
     226              :       {
     227            0 :          float g = m_defaultGains[0];
     228            0 :          m_defaultGains.resize(m_ctrlTargets.size(), g);
     229            0 :          log<text_log>("Setting loop.gains gains to be same size as ctrl.Targets", logPrio::LOG_NOTICE);
     230              :       }
     231              :       else
     232              :       {
     233            0 :          return log<software_error, -1>({__FILE__, __LINE__, "ctrl.Targets and loop.gains are not the same size"});
     234              :       }
     235              :    }
     236              : 
     237            0 :    CREATE_REG_INDI_RO_NUMBER( m_indiP_deltas, "deltas", "Deltas", "Deltas");
     238            0 :    m_indiP_deltas.add(pcf::IndiElement("delta0"));
     239            0 :    m_indiP_deltas["delta0"] = 0;
     240            0 :    m_indiP_deltas.add(pcf::IndiElement("delta1"));
     241            0 :    m_indiP_deltas["delta1"] = 0;
     242              : 
     243            0 :    m_gains.resize(m_defaultGains.size());
     244            0 :    for(size_t n=0; n < m_defaultGains.size(); ++n) m_gains[n] = m_defaultGains[n];
     245              : 
     246            0 :    createStandardIndiNumber<unsigned>( m_indiP_ggain, "loop_gain", 0, 1, 0, "%0.2f");
     247            0 :    m_indiP_ggain["current"] = m_ggain;
     248            0 :    m_indiP_ggain["target"] = m_ggain;
     249            0 :    if( registerIndiPropertyNew( m_indiP_ggain, INDI_NEWCALLBACK(m_indiP_ggain)) < 0)
     250              :    {
     251            0 :       log<software_error>({__FILE__,__LINE__});
     252            0 :       return -1;
     253              :    }
     254              : 
     255            0 :    createStandardIndiToggleSw( m_indiP_ctrlEnabled, "loop_state");
     256            0 :    if( registerIndiPropertyNew( m_indiP_ctrlEnabled, INDI_NEWCALLBACK(m_indiP_ctrlEnabled)) < 0)
     257              :    {
     258            0 :       log<software_error>({__FILE__,__LINE__});
     259            0 :       return -1;
     260              :    }
     261              : 
     262            0 :    m_currents.resize(m_ctrlDevices.size(), -1e15);
     263              : 
     264            0 :    m_indiP_ctrl.resize(m_ctrlDevices.size());
     265              : 
     266            0 :    for(size_t n=0; n< m_ctrlDevices.size();++n)
     267              :    {
     268            0 :       registerIndiPropertySet( m_indiP_ctrl[n], m_ctrlDevices[n], m_ctrlProperties[n], &st_setCallBack_ctrl);
     269              :    }
     270              : 
     271            0 :    m_commands.resize(m_ctrlTargets.size(), m_ctrlTargets.size()) ;
     272            0 :    m_commands.setZero();
     273              : 
     274            0 :    m_intMat.resize(m_ctrlTargets.size(), m_ctrlTargets.size()) ;
     275            0 :    m_intMat.setZero();
     276            0 :    m_intMat(1,0) = 0.926;
     277            0 :    m_intMat(1,1) = -0.370;
     278            0 :    m_intMat(0,0) = 0.185;
     279            0 :    m_intMat(0,1) = 0.926;
     280              : 
     281              : /*
     282              :    std::string intMatPath = m_calibDir + "/" + m_intMatFile;
     283              : 
     284              :    mx::fits::fitsFile<float> ff;
     285              :    try
     286              :    {
     287              :       ff.read(m_intMat, intMatPath);
     288              :    }
     289              :    catch(...)
     290              :    {
     291              :       return log<software_error, -1>({__FILE__, __LINE__, "error reading loop.intMatFile.  Does it exist?"});
     292              :    }
     293              : 
     294              :    if(m_intMat.rows() != m_ctrlTargets.size())
     295              :    {
     296              :       return log<software_error, -1>({__FILE__, __LINE__, "interaction matrix wrong size: rows do not match sensor Targets"});
     297              :    }
     298              : 
     299              :    if(m_intMat.cols() != m_correctorTargets.size())
     300              :    {
     301              :       return log<software_error, -1>({__FILE__, __LINE__, "interaction matrix wrong size: cols do not match corrector Targets"});
     302              :    }
     303              : */
     304              : 
     305              :    //Get the loop state for managing offloading
     306            0 :    if(m_upstreamDevice != "")
     307              :    {
     308            0 :       REG_INDI_SETPROP(m_indiP_upstream, m_upstreamDevice, m_upstreamProperty);
     309              :    }
     310              : 
     311            0 :    return 0;
     312              : }
     313              : 
     314            0 : int alignLoop::appLogic()
     315              : {
     316            0 :    if( shmimMonitorT::appLogic() < 0)
     317              :    {
     318            0 :       return log<software_error,-1>({__FILE__,__LINE__});
     319              :    }
     320              : 
     321            0 :    state(stateCodes::OPERATING);
     322              : 
     323            0 :    return 0;
     324              : }
     325              : 
     326            0 : int alignLoop::appShutdown()
     327              : {
     328            0 :    shmimMonitorT::appShutdown();
     329              : 
     330            0 :    return 0;
     331              : }
     332              : 
     333            0 : int alignLoop::toggleLoop(bool onoff)
     334              : {
     335            0 :    if(!m_ctrlEnabled && onoff) //not enabled so change
     336              :    {
     337            0 :       m_ctrlEnabled = true;
     338            0 :       log<loop_closed>();
     339            0 :       updateSwitchIfChanged(m_indiP_ctrlEnabled, "toggle", pcf::IndiElement::On, INDI_OK);
     340            0 :       return 0;
     341              :    }
     342              : 
     343            0 :    if(m_ctrlEnabled && !onoff)
     344              :    {
     345            0 :       m_ctrlEnabled = false;
     346            0 :       log<loop_open>();
     347            0 :       updateSwitchIfChanged(m_indiP_ctrlEnabled, "toggle", pcf::IndiElement::Off, INDI_IDLE);
     348              : 
     349            0 :       return 0;
     350              :    }
     351              : 
     352            0 :    return 0;
     353              : }
     354              : 
     355              : inline
     356            0 : int alignLoop::allocate(const dev::shmimT & dummy)
     357              : {
     358              :    static_cast<void>(dummy);
     359              : 
     360            0 :    std::lock_guard<std::mutex> guard(m_indiMutex);
     361              : 
     362            0 :    std::cerr << shmimMonitorT::m_width << shmimMonitorT::m_height << "\n";
     363            0 :    m_measurements.resize(shmimMonitorT::m_width, shmimMonitorT::m_height);
     364              : 
     365            0 :    return 0;
     366            0 : }
     367              : 
     368              : inline
     369            0 : int alignLoop::processImage( void* curr_src,
     370              :                             const dev::shmimT & dummy
     371              :                            )
     372              : {
     373              :    static_cast<void>(dummy);
     374              : 
     375            0 :    for(unsigned nn=0; nn < shmimMonitorT::m_width*shmimMonitorT::m_height; ++nn)
     376              :    {
     377            0 :       m_measurements.data()[nn] = (static_cast<float*>(curr_src)) [nn];
     378              :    }
     379              : 
     380              : 
     381            0 :    m_delta0 = m_measurements(0,0);
     382            0 :    m_delta1 = m_measurements(1,0);
     383              : 
     384            0 :    std::cout << "measurements: ";
     385            0 :    for(int cc = 0; cc < m_measurements.rows(); ++cc)
     386              :    {
     387            0 :       std::cout << m_measurements(cc,0) << " ";
     388              :    }
     389            0 :    std::cout << "\n";
     390              : 
     391            0 :    if(m_currents[0] < -1e14) return 0;
     392              : 
     393            0 :    m_commands.matrix() = m_intMat.matrix() * m_measurements.matrix();
     394              : 
     395              : 
     396              : 
     397            0 :    std::cout << "delta commands:    ";
     398            0 :    for(int cc = 0; cc < m_measurements.rows(); ++cc)
     399              :    {
     400            0 :       std::cout << -m_commands(cc,0) << " ";
     401              :    }
     402            0 :    std::cout << "\n";
     403              : 
     404            0 :    std::vector<float> commands;
     405            0 :    commands.resize(m_measurements.rows());
     406              : 
     407            0 :    std::cout << "commands:    ";
     408            0 :    for(int cc = 0; cc < m_measurements.rows(); ++cc)
     409              :    {
     410            0 :       commands[cc] = m_currents[cc] - m_ggain*m_gains[cc]*m_commands(cc,0);
     411            0 :       std::cout << commands[cc] << " ";
     412              :    }
     413            0 :    std::cout << "\n";
     414              : 
     415              :    //And send commands.
     416              :    int rv;
     417            0 :    if(m_ctrlEnabled)
     418              :    {
     419            0 :       rv = sendCommands(commands);
     420              :    }
     421              :    else
     422              :    {
     423            0 :       rv = 0;
     424              :    }
     425              : 
     426            0 :    updateIfChanged(m_indiP_deltas, std::vector<std::string>({"delta0", "delta1"}), std::vector<float>({m_delta0, m_delta1}));
     427            0 :    return rv;
     428            0 : }
     429              : 
     430              : inline
     431            0 : int alignLoop::sendCommands(std::vector<float> & commands)
     432              : {
     433            0 :    for(size_t n=0; n < m_ctrlDevices.size(); ++n)
     434              :    {
     435            0 :       pcf::IndiProperty ip(pcf::IndiProperty::Number);
     436              : 
     437            0 :       ip.setDevice(m_ctrlDevices[n]);
     438            0 :       ip.setName(m_ctrlProperties[n]);
     439            0 :       ip.add(pcf::IndiElement(m_ctrlTargets[n]));
     440            0 :       ip[m_ctrlTargets[n]] = commands[n];
     441              : 
     442            0 :       sendNewProperty(ip);
     443            0 :    }
     444              : 
     445            0 :    return 0;
     446              : }
     447              : 
     448            0 : INDI_NEWCALLBACK_DEFN(alignLoop, m_indiP_ggain)(const pcf::IndiProperty &ipRecv)
     449              : {
     450            0 :    if(ipRecv.getName() != m_indiP_ggain.getName())
     451              :    {
     452            0 :       log<software_error>({__FILE__, __LINE__, "invalid indi property received"});
     453            0 :       return -1;
     454              :    }
     455              : 
     456              :    float target;
     457              : 
     458            0 :    if( indiTargetUpdate( m_indiP_ggain, target, ipRecv, true) < 0)
     459              :    {
     460            0 :       log<software_error>({__FILE__,__LINE__});
     461            0 :       return -1;
     462              :    }
     463              : 
     464            0 :    m_ggain = target;
     465              : 
     466            0 :    updateIfChanged(m_indiP_ggain, "current", m_ggain);
     467            0 :    updateIfChanged(m_indiP_ggain, "target", m_ggain);
     468              : 
     469            0 :    log<text_log>("set global gain to " + std::to_string(m_ggain), logPrio::LOG_NOTICE);
     470              : 
     471            0 :    return 0;
     472              : }
     473              : 
     474            0 : INDI_NEWCALLBACK_DEFN(alignLoop, m_indiP_ctrlEnabled)(const pcf::IndiProperty &ipRecv)
     475              : {
     476            0 :    if(ipRecv.getName() != m_indiP_ctrlEnabled.getName())
     477              :    {
     478            0 :       log<software_error>({__FILE__, __LINE__, "invalid indi property received"});
     479            0 :       return -1;
     480              :    }
     481              : 
     482              :    //switch is toggled to on
     483            0 :    if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On)
     484              :    {
     485            0 :       return toggleLoop(true);
     486              :    }
     487              : 
     488              :    //switch is toggle to off
     489            0 :    if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off)
     490              :    {
     491            0 :       return toggleLoop(false);
     492              :    }
     493              : 
     494            0 :    return 0;
     495              : }
     496              : 
     497              : inline
     498            0 : int alignLoop::setCallBack_ctrl(const pcf::IndiProperty &ipRecv)
     499              : {
     500            0 :    for(size_t n = 0; n < m_ctrlDevices.size(); ++n)
     501              :    {
     502            0 :       if( ipRecv.getDevice() == m_ctrlDevices[n])
     503              :       {
     504            0 :          if(ipRecv.getName() == m_ctrlProperties[n] && ipRecv.find(m_ctrlCurrents[n]))
     505              :          {
     506            0 :             m_currents[n] = ipRecv[m_ctrlCurrents[n]].get<float>();
     507              :          }
     508              :       }
     509              :    }
     510              : 
     511            0 :    return 0;
     512              : }
     513              : 
     514            0 : INDI_SETCALLBACK_DEFN(alignLoop, m_indiP_upstream)(const pcf::IndiProperty &ipRecv)
     515              : {
     516            0 :    if(ipRecv.getName() != m_indiP_upstream.getName())
     517              :    {
     518            0 :       return log<software_error>({__FILE__,__LINE__, "wrong INDI property received"});
     519              :    }
     520              : 
     521            0 :    if(!ipRecv.find("toggle")) return 0;
     522              : 
     523            0 :    if(ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On && m_upstreamFollowClosed)
     524              :    {
     525            0 :       std::cerr << "upstream on\n";
     526            0 :       return toggleLoop(true);
     527              :    }
     528            0 :    else if(ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off)
     529              :    {
     530            0 :       std::cerr << "upstream off\n";
     531            0 :       return toggleLoop(false);
     532              :    }
     533              : 
     534            0 :    return 0;
     535              : }
     536              : 
     537              : 
     538              : } //namespace app
     539              : } //namespace MagAOX
     540              : 
     541              : #endif //alignLoop_hpp
        

Generated by: LCOV version 2.0-1