LCOV - code coverage report
Current view: top level - apps/cacaoInterface - cacaoInterface.hpp (source / functions) Coverage Total Hit
Test: MagAOX Lines: 4.5 % 313 14
Test Date: 2026-01-03 21:03:39 Functions: 20.0 % 35 7

            Line data    Source code
       1              : /** \file cacaoInterface.hpp
       2              :   * \brief The MagAO-X CACAO Interface header file
       3              :   *
       4              :   * \ingroup cacaoInterface_files
       5              :   */
       6              : 
       7              : #ifndef cacaoInterface_hpp
       8              : #define cacaoInterface_hpp
       9              : 
      10              : #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
      11              : #include "../../magaox_git_version.h"
      12              : 
      13              : /** \defgroup cacaoInterface
      14              :   * \brief The CACAO Interface to provide loop status
      15              :   *
      16              :   * <a href="../handbook/apps/cacaoInterface.html">Application Documentation</a>
      17              :   *
      18              :   * \ingroup apps
      19              :   *
      20              :   */
      21              : 
      22              : /** \defgroup cacaoInterface_files
      23              :   * \ingroup cacaoInterface
      24              :   */
      25              : 
      26              : namespace MagAOX
      27              : {
      28              : namespace app
      29              : {
      30              : 
      31              : /// The MagAO-X CACAO Interface
      32              : /**
      33              :   * \ingroup cacaoInterface
      34              :   */
      35              : class cacaoInterface : public MagAOXApp<true>, public dev::telemeter<cacaoInterface>
      36              : {
      37              : 
      38              :    //Give the test harness access.
      39              :    friend class cacaoInterface_test;
      40              : 
      41              :    typedef dev::telemeter<cacaoInterface> telemeterT;
      42              : 
      43              :    friend class dev::telemeter<cacaoInterface>;
      44              : 
      45              : protected:
      46              : 
      47              :    /** \name Configurable Parameters
      48              :      *@{
      49              :      */
      50              :    std::string m_loopNumber; ///< The loop number, X in aolX.  We keep it a string because that's how it gets used.
      51              : 
      52              :    ///@}
      53              : 
      54              :    std::string m_aoCalDir;
      55              :    std::string m_aoCalArchiveTime;
      56              :    std::string m_aoCalLoadTime;
      57              : 
      58              :    std::string m_loopName; ///< the loop name
      59              : 
      60              : 
      61              :    std::string m_fpsName;
      62              :    std::string m_fpsFifo;
      63              : 
      64              : 
      65              :    int m_loopState {0}; ///< The loop state.  0 = off, 1 = paused (on, 0 gain), 2 = on
      66              : 
      67              :    bool m_loopProcesses {false}; ///< Status of the loop processes.
      68              :    bool m_loopProcesses_stat {false}; ///< What the cacao status file says the state of loop processes is.
      69              : 
      70              :    float m_gain {0.0}; ///< The current loop gain.
      71              :    float m_gain_target {0.0}; ///< The target loop gain.
      72              : 
      73              :    float m_multCoeff {0.0}; ///< The current multiplicative coefficient (1-leak)
      74              :    float m_multCoeff_target {0.0}; ///< The target multiplicative coefficient (1-leak)
      75              : 
      76              :    std::vector<int> m_modeBlockStart;
      77              :    std::vector<int> m_modeBlockN;
      78              : 
      79              :    std::vector<float> m_modeBlockGains;
      80              :    std::vector<float> m_modeBlockMCs;
      81              :    std::vector<float> m_modeBlockLims;
      82              : 
      83              :    std::mutex m_modeBlockMutex;
      84              : 
      85              : 
      86              :    float m_maxLim {0.0}; ///< The current max limit
      87              :    float m_maxLim_target {0.0}; ///< The target max limit
      88              : 
      89              : public:
      90              :    /// Default c'tor.
      91              :    cacaoInterface();
      92              : 
      93              :    /// D'tor, declared and defined for noexcept.
      94           15 :    ~cacaoInterface() noexcept
      95           15 :    {}
      96              : 
      97              :    virtual void setupConfig();
      98              : 
      99              :    /// Implementation of loadConfig logic, separated for testing.
     100              :    /** This is called by loadConfig().
     101              :      */
     102              :    int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
     103              : 
     104              :    virtual void loadConfig();
     105              : 
     106              :    /// Startup function
     107              :    /**
     108              :      *
     109              :      */
     110              :    virtual int appStartup();
     111              : 
     112              :    /// Implementation of the FSM for cacaoInterface.
     113              :    /**
     114              :      * \returns 0 on no critical error
     115              :      * \returns -1 on an error requiring shutdown
     116              :      */
     117              :    virtual int appLogic();
     118              : 
     119              :    /// Shutdown the app.
     120              :    /**
     121              :      *
     122              :      */
     123              :    virtual int appShutdown();
     124              : 
     125              : 
     126              :    /** \name CACAO Interface Functions
     127              :      * @{
     128              :      */
     129              : 
     130              :    int setFPSVal( const std::string & fps,
     131              :                   const std::string & param,
     132              :                   const std::string & val
     133              :                 );
     134              : 
     135              : 
     136              :    template<typename T>
     137              :    int setFPSVal( const std::string & fps,
     138              :                   const std::string & param,
     139              :                   const T & val
     140              :                 );
     141              : 
     142              :    std::string getFPSValStr(const std::string & fps,
     143              :                                           const std::string & param );
     144              : 
     145              :    std::string getFPSValNum(const std::string & fps,
     146              :                                           const std::string & param );
     147              : 
     148              :    /// Get the calibration details
     149              :    /** This is done each loop
     150              :      *
     151              :      * \returns 0 on success
     152              :      * \returns -1 on an error
     153              :      */
     154              :    int getAOCalib();
     155              : 
     156              :    int getModeBlocks();
     157              : 
     158              :    /// Check if the loop processes are running
     159              :    /** sets m_loopProcesses to true or false depending on what it finds out.
     160              :      *
     161              :      * \returns 0 on success
     162              :      * \returns -1 on an error
     163              :      */
     164              :    int checkLoopProcesses();
     165              : 
     166              :    /// Set loop gain to the value of m_gain_target;
     167              :    /**
     168              :      *
     169              :      * \returns 0 on success
     170              :      * \returns -1 on an error
     171              :      */
     172              :    int setGain();
     173              : 
     174              :    /// Set loop multiplication coefficient to the value of m_multCoeff_target;
     175              :    /**
     176              :      *
     177              :      * \returns 0 on success
     178              :      * \returns -1 on an error
     179              :      */
     180              :    int setMultCoeff();
     181              : 
     182              :    /// Set loop max lim to the value of m_maxLim_target;
     183              :    /**
     184              :      *
     185              :      * \returns 0 on success
     186              :      * \returns -1 on an error
     187              :      */
     188              :    int setMaxLim();
     189              : 
     190              :    /// Turn the loop on
     191              :    /**
     192              :      * \returns 0 on success
     193              :      * \returns -1 on an error
     194              :      */
     195              :    int loopOn();
     196              : 
     197              :    /// Turn the loop off
     198              :    /**
     199              :      * \returns 0 on success
     200              :      * \returns -1 on an error
     201              :      */
     202              :    int loopOff();
     203              : 
     204              :    /// Zero the loop control channel
     205              :    /**
     206              :      * \returns 0 on success
     207              :      * \returns -1 on an error
     208              :      */
     209              :    int loopZero();
     210              : 
     211              :    /// @}
     212              : 
     213              :    /** \name File Monitoring Thread
     214              :      * Handling of offloads from the average woofer shape
     215              :      * @{
     216              :      */
     217              :    int m_fmThreadPrio {0}; ///< Priority of the filemonitoring thread.
     218              : 
     219              :    std::thread m_fmThread; ///< The file monitoring thread.
     220              : 
     221              :    bool m_fmThreadInit {true}; ///< Initialization flag for the file monitoring thread.
     222              : 
     223              :    pid_t m_fmThreadID {0}; ///< File monitor thread PID.
     224              : 
     225              :    pcf::IndiProperty m_fmThreadProp; ///< The property to hold the f.m. thread details.
     226              : 
     227              :    /// File monitoring thread starter function
     228              :    static void fmThreadStart( cacaoInterface * c /**< [in] pointer to this */);
     229              : 
     230              : 
     231              :    /// File monitoring thread function
     232              :    /** Runs until m_shutdown is true.
     233              :      */
     234              :    void fmThreadExec();
     235              : 
     236              : 
     237              :    ///@}
     238              : 
     239              :    pcf::IndiProperty m_indiP_loop;
     240              :    pcf::IndiProperty m_indiP_loopProcesses;
     241              : 
     242              :    pcf::IndiProperty m_indiP_loopState;
     243              :    pcf::IndiProperty m_indiP_loopZero;
     244              :    pcf::IndiProperty m_indiP_loopGain;
     245              :    pcf::IndiProperty m_indiP_multCoeff;
     246              :    pcf::IndiProperty m_indiP_maxLim;
     247              : 
     248            0 :    INDI_NEWCALLBACK_DECL(cacaoInterface, m_indiP_loopState);
     249            0 :    INDI_NEWCALLBACK_DECL(cacaoInterface, m_indiP_loopZero);
     250            0 :    INDI_NEWCALLBACK_DECL(cacaoInterface, m_indiP_loopGain);
     251            0 :    INDI_NEWCALLBACK_DECL(cacaoInterface, m_indiP_multCoeff);
     252            0 :    INDI_NEWCALLBACK_DECL(cacaoInterface, m_indiP_maxLim);
     253              : 
     254              :    /** \name Telemeter Interface
     255              :      *
     256              :      * @{
     257              :      */
     258              :    int checkRecordTimes();
     259              : 
     260              :    int recordTelem( const telem_loopgain * );
     261              : 
     262              :    int recordLoopGain( bool force = false );
     263              : 
     264              :    ///@}
     265              : 
     266              : 
     267              : };
     268              : 
     269           45 : cacaoInterface::cacaoInterface() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
     270              : {
     271              : 
     272           15 :    return;
     273            0 : }
     274              : 
     275            0 : void cacaoInterface::setupConfig()
     276              : {
     277            0 :    config.add("loop.number", "", "loop.number", argType::Required, "loop", "number", false, "string", "the loop number");
     278              : 
     279            0 :    telemeterT::setupConfig(config);
     280            0 : }
     281              : 
     282            0 : int cacaoInterface::loadConfigImpl( mx::app::appConfigurator & _config )
     283              : {
     284            0 :    _config(m_loopNumber, "loop.number");
     285              : 
     286            0 :    if(telemeterT::loadConfig(_config) < 0)
     287              :    {
     288            0 :       log<text_log>("Error during telemeter config", logPrio::LOG_CRITICAL);
     289            0 :       m_shutdown = true;
     290              :    }
     291              : 
     292            0 :    return 0;
     293              : }
     294              : 
     295            0 : void cacaoInterface::loadConfig()
     296              : {
     297            0 :    loadConfigImpl(config);
     298            0 : }
     299              : 
     300            0 : int cacaoInterface::appStartup()
     301              : {
     302              : 
     303            0 :    if(m_loopNumber == "")
     304              :    {
     305            0 :       return log<software_critical, -1>({__FILE__, __LINE__, "loop number not set"});
     306              :    }
     307              : 
     308            0 :    createROIndiText( m_indiP_loop, "loop", "name", "Loop Description", "Loop Controls", "Name");
     309            0 :    indi::addTextElement(m_indiP_loop, "number", "Number");
     310            0 :    m_indiP_loop["number"] = m_loopNumber;
     311            0 :    m_indiP_loop["name"] = m_loopName;
     312            0 :    registerIndiPropertyReadOnly(m_indiP_loop);
     313              : 
     314            0 :    createStandardIndiToggleSw( m_indiP_loopProcesses, "loop_processes", "Loop Processes", "Loop Controls");
     315            0 :    registerIndiPropertyReadOnly( m_indiP_loopProcesses);
     316              : 
     317            0 :    createStandardIndiToggleSw( m_indiP_loopState, "loop_state", "Loop State", "Loop Controls");
     318            0 :    registerIndiPropertyNew( m_indiP_loopState, INDI_NEWCALLBACK(m_indiP_loopState) );
     319              : 
     320            0 :    createStandardIndiRequestSw( m_indiP_loopZero, "loop_zero", "Loop Zero", "Loop Controls");
     321            0 :    registerIndiPropertyNew( m_indiP_loopZero,INDI_NEWCALLBACK(m_indiP_loopZero) );
     322              : 
     323            0 :    createStandardIndiNumber<float>( m_indiP_loopGain, "loop_gain", 0.0, 10.0, 0.01, "%0.3f", "Loop Gain", "Loop Controls");
     324            0 :    registerIndiPropertyNew( m_indiP_loopGain, INDI_NEWCALLBACK(m_indiP_loopGain) );
     325              : 
     326            0 :    createStandardIndiNumber<float>( m_indiP_multCoeff, "loop_multcoeff", 0.0, 1.0, 0.001, "%0.3f", "Mult. Coefficient", "Loop Controls");
     327            0 :    registerIndiPropertyNew( m_indiP_multCoeff, INDI_NEWCALLBACK(m_indiP_multCoeff) );
     328              : 
     329            0 :    createStandardIndiNumber<float>( m_indiP_maxLim, "loop_max_limit", 0.0, 10.0, 0.001, "%0.3f", "Max. Limit", "Loop Controls");
     330            0 :    registerIndiPropertyNew( m_indiP_maxLim, INDI_NEWCALLBACK(m_indiP_maxLim) );
     331              : 
     332            0 :    if(threadStart( m_fmThread, m_fmThreadInit, m_fmThreadID, m_fmThreadProp, m_fmThreadPrio, "", "loopmon", this, fmThreadStart) < 0)
     333              :    {
     334            0 :       log<software_error>({__FILE__, __LINE__});
     335            0 :       return -1;
     336              :    }
     337              : 
     338            0 :    if(telemeterT::appStartup() < 0)
     339              :    {
     340            0 :       return log<software_error,-1>({__FILE__,__LINE__});
     341              :    }
     342              : 
     343            0 :    return 0;
     344              : }
     345              : 
     346            0 : int cacaoInterface::appLogic()
     347              : {
     348              :    //do a join check to see if other threads have exited.
     349            0 :    if(pthread_tryjoin_np(m_fmThread.native_handle(),0) == 0)
     350              :    {
     351            0 :       log<software_critical>({__FILE__, __LINE__, "cacao file monitoring thread has exited"});
     352              : 
     353            0 :       return -1;
     354              :    }
     355              : 
     356              :    //These could change if a new calibration is loaded
     357            0 :    if(getAOCalib() < 0 )
     358              :    {
     359            0 :       state(stateCodes::ERROR, true);
     360            0 :       if(!stateLogged()) log<text_log>("Could not get AO calib", logPrio::LOG_ERROR);
     361            0 :       return 0;
     362              :    }
     363              : 
     364            0 :    if(m_loopProcesses == 0 || m_loopState == 0) state(stateCodes::READY);
     365            0 :    else state(stateCodes::OPERATING);
     366              : 
     367            0 :    if(telemeterT::appLogic() < 0)
     368              :    {
     369            0 :       log<software_error>({__FILE__, __LINE__});
     370            0 :       return 0;
     371              :    }
     372              : 
     373            0 :    std::unique_lock<std::mutex> lock(m_indiMutex);
     374              : 
     375            0 :    updateIfChanged(m_indiP_loop, std::vector<std::string>({"name", "number"}), std::vector<std::string>({m_loopName, m_loopNumber}));
     376              : 
     377            0 :    if(m_loopProcesses)
     378              :    {
     379            0 :       updateSwitchIfChanged(m_indiP_loopProcesses, "toggle", pcf::IndiElement::On, INDI_OK);
     380              :    }
     381              :    else
     382              :    {
     383            0 :       updateSwitchIfChanged(m_indiP_loopProcesses, "toggle", pcf::IndiElement::Off, INDI_IDLE);
     384              :    }
     385              : 
     386            0 :    if(m_loopState == 0)
     387              :    {
     388            0 :       updateSwitchIfChanged(m_indiP_loopState, "toggle", pcf::IndiElement::Off, INDI_IDLE);
     389              :    }
     390            0 :    else if(m_loopState == 1)
     391              :    {
     392            0 :       updateSwitchIfChanged(m_indiP_loopState, "toggle", pcf::IndiElement::On, INDI_IDLE);
     393              :    }
     394            0 :    else if(m_loopState == 2)
     395              :    {
     396            0 :       updateSwitchIfChanged(m_indiP_loopState, "toggle", pcf::IndiElement::On, INDI_OK);
     397              :    }
     398              : 
     399            0 :    updateIfChanged(m_indiP_loop, "name", m_loopName);
     400            0 :    updateIfChanged(m_indiP_loop, "number", m_loopNumber);
     401              : 
     402            0 :    updateIfChanged(m_indiP_loopGain, "current", m_gain);
     403            0 :    updateIfChanged(m_indiP_multCoeff, "current", m_multCoeff);
     404            0 :    updateIfChanged(m_indiP_maxLim, "current", m_maxLim);
     405              : 
     406            0 :    return 0;
     407            0 : }
     408              : 
     409            0 : int cacaoInterface::appShutdown()
     410              : {
     411              : 
     412            0 :    if(m_fmThread.joinable())
     413              :    {
     414              :       try
     415              :       {
     416            0 :          m_fmThread.join(); //this will throw if it was already joined
     417              :       }
     418            0 :       catch(...)
     419              :       {
     420            0 :       }
     421              :    }
     422              : 
     423            0 :    telemeterT::appShutdown();
     424              : 
     425            0 :    return 0;
     426              : }
     427              : 
     428            0 : int cacaoInterface::setFPSVal( const std::string & fps,
     429              :                                const std::string & param,
     430              :                                const std::string & val
     431              :                              )
     432              : {
     433            0 :    std::string comout = "setval " + fps + "-" + m_loopNumber + "." + param +  " "  + val + "\n";
     434              : 
     435            0 :    int wfd = open( m_fpsFifo.c_str(), O_WRONLY);
     436            0 :    if(wfd < 0)
     437              :    {
     438            0 :       log<software_error>({__FILE__, __LINE__, errno, "error opening " + m_fpsFifo});
     439            0 :       return -1;
     440              :    }
     441              : 
     442            0 :    int w = write(wfd, comout.c_str(), comout.size());
     443              : 
     444            0 :    if(w != (int) comout.size())
     445              :    {
     446            0 :       log<software_error>({__FILE__, __LINE__, errno, "error on write to " + m_fpsFifo});
     447            0 :       return -1;
     448              :    }
     449              : 
     450            0 :    close(wfd);
     451              : 
     452            0 :    return 0;
     453            0 : }
     454              : 
     455              : 
     456              : template<typename T>
     457            0 : int cacaoInterface::setFPSVal( const std::string & fps,
     458              :                                const std::string & param,
     459              :                                const T & val
     460              :                              )
     461              : {
     462            0 :    return setFPSVal( fps, param, std::to_string(val));
     463              : }
     464              : 
     465            0 : std::string cacaoInterface::getFPSValStr( const std::string & fps,
     466              :                                           const std::string & param
     467              :                                         )
     468              : {
     469            0 :     std::string outfile = "/dev/shm/" + m_loopName + "_out_" + fps + "-" + m_loopNumber + "." + param;
     470              : 
     471            0 :     std::string comout = "fwrval " + fps + "-" + m_loopNumber + "." + param + " "  + outfile + "\n";
     472              : 
     473            0 :     int wfd = open( m_fpsFifo.c_str(), O_WRONLY);
     474            0 :     if(wfd < 0)
     475              :     {
     476            0 :         log<software_error>({__FILE__, __LINE__, errno, "error opening " + m_fpsFifo});
     477            0 :         return "";
     478              :     }
     479              : 
     480            0 :     int w = write(wfd, comout.c_str(), comout.size());
     481              : 
     482            0 :     if(w != (int) comout.size())
     483              :     {
     484            0 :         log<software_error>({__FILE__, __LINE__, errno, "error on write to " + m_fpsFifo});
     485            0 :         return "";
     486              :     }
     487              : 
     488            0 :     close(wfd);
     489              : 
     490              :     char inbuff [4096];
     491              : 
     492            0 :     int rfd = -1;
     493            0 :     int nr =0;
     494            0 :     while(rfd < 0 && nr < 500)
     495              :     {
     496            0 :         rfd = open(outfile.c_str(), O_RDONLY);
     497            0 :         ++nr;
     498            0 :         mx::sys::milliSleep(10);
     499              :     }
     500              : 
     501            0 :     if(rfd < 0)
     502              :     {
     503            0 :         log<software_error>({__FILE__, __LINE__, "could not get an open fd on " + m_fpsFifo});
     504            0 :         return "";
     505              :     }
     506              : 
     507            0 :     int r = read(rfd, inbuff, sizeof(inbuff));
     508              : 
     509            0 :     if(r < 0)
     510              :     {
     511            0 :         log<software_error>({__FILE__, __LINE__, errno, "error on read from " + m_fpsFifo});
     512            0 :         return "";
     513              :     }
     514              : 
     515            0 :     close(rfd);
     516              : 
     517            0 :     remove(outfile.c_str());
     518              : 
     519            0 :     inbuff[r] = '\0';
     520              : 
     521            0 :     std::string instr = inbuff;
     522              : 
     523            0 :     size_t ned = instr.find_last_not_of(" \t\r\n");
     524              : 
     525            0 :     if(ned == std::string::npos || ned == 0)
     526              :     {
     527              :         //log<software_error>({__FILE__, __LINE__, "got empty result from " + m_fpsFifo});
     528            0 :         return "";
     529              :     }
     530              : 
     531            0 :     size_t nst = instr.rfind(' ', ned);
     532              : 
     533            0 :     if(nst == 0 || nst == std::string::npos || ned <= nst)
     534              :     {
     535            0 :         log<software_error>({__FILE__, __LINE__, "bad format in result from " + m_fpsFifo});
     536            0 :         return "";
     537              :     }
     538              : 
     539            0 :     return instr.substr(nst+1);
     540            0 : }
     541              : 
     542            0 : std::string cacaoInterface::getFPSValNum( const std::string & fps,
     543              :                                           const std::string & param
     544              :                                         )
     545              : {
     546            0 :     std::string outfile = "/dev/shm/" + m_loopName + "_out_" + fps + "-" + m_loopNumber + "." + param;
     547              : 
     548            0 :     std::string comout = "fwrval " + fps + "-" + m_loopNumber + "." + param + " "  + outfile + "\n";
     549              : 
     550            0 :     int wfd = open( m_fpsFifo.c_str(), O_WRONLY);
     551            0 :     if(wfd < 0)
     552              :     {
     553            0 :         log<software_error>({__FILE__, __LINE__, errno, "error opening " + m_fpsFifo});
     554            0 :         return "";
     555              :     }
     556              : 
     557            0 :     int w = write(wfd, comout.c_str(), comout.size());
     558              : 
     559            0 :     if(w != (int) comout.size())
     560              :     {
     561            0 :         log<software_error>({__FILE__, __LINE__, errno, "error on write to " + m_fpsFifo});
     562            0 :         return "";
     563              :     }
     564            0 :     close(wfd);
     565              : 
     566              :     char inbuff [4096];
     567              : 
     568            0 :     int rfd = -1;
     569            0 :     int nr =0;
     570            0 :     while(rfd < 0 && nr < 500)
     571              :     {
     572            0 :         rfd = open(outfile.c_str(), O_RDONLY);
     573            0 :         ++nr;
     574            0 :         mx::sys::milliSleep(10);
     575              :     }
     576              : 
     577            0 :     if(rfd < 0)
     578              :     {
     579            0 :         log<software_error>({__FILE__, __LINE__, "could not get an open fd on " + m_fpsFifo});
     580            0 :         return "";
     581              :     }
     582              : 
     583            0 :     int r = read(rfd, inbuff, sizeof(inbuff));
     584              : 
     585            0 :     close(rfd);
     586              : 
     587            0 :     if(r < 0)
     588              :     {
     589            0 :         log<software_error>({__FILE__, __LINE__, errno, "error on read from " + m_fpsFifo});
     590            0 :         return "";
     591              :     }
     592              : 
     593            0 :     remove(outfile.c_str());
     594              : 
     595            0 :     inbuff[r] = '\0';
     596              : 
     597            0 :     std::string instr = inbuff;
     598              : 
     599            0 :     size_t ned = instr.find_last_not_of(" \t\r\n");
     600              : 
     601            0 :     if(ned == std::string::npos || ned == 0)
     602              :     {
     603            0 :         log<software_error>({__FILE__, __LINE__, "got empty result from " + m_fpsFifo});
     604            0 :         return "";
     605              :     }
     606              : 
     607            0 :     size_t nst = instr.rfind(' ', ned);
     608              : 
     609            0 :     if(nst == 0 || nst == std::string::npos || ned <= nst)
     610              :     {
     611            0 :         log<software_error>({__FILE__, __LINE__, "bad format in result from " + m_fpsFifo});
     612            0 :         return "";
     613              :     }
     614              : 
     615            0 :     return instr.substr(nst);
     616            0 : }
     617              : 
     618              : inline
     619            0 : int cacaoInterface::getAOCalib()
     620              : {
     621            0 :    std::string calsrc = "/milk/shm/aol" + m_loopNumber + "_calib_source.txt";
     622              : 
     623            0 :    std::ifstream fin;
     624              : 
     625              :    //First read in the milk/shm directory name, which could be to a symlinked directory
     626            0 :    fin.open(calsrc);
     627            0 :    if(!fin)
     628              :    {
     629            0 :       return 0;
     630              :    }
     631            0 :    fin >> calsrc;
     632            0 :    fin.close();
     633              : 
     634              :    //Now read in the actual directory
     635            0 :    calsrc += "/calib_dir.txt";
     636            0 :    fin.open(calsrc);
     637            0 :    if(!fin)
     638              :    {
     639            0 :       return log<software_error, -1>({__FILE__, __LINE__, errno, "cacaoInterface::getAOCalib failed to open: " + calsrc});
     640              :    }
     641            0 :    std::string aoCalDir;
     642              : 
     643            0 :    fin >> aoCalDir;
     644              : 
     645            0 :    fin.close();
     646              : 
     647            0 :    bool newcal = false;
     648            0 :    if(aoCalDir != m_aoCalDir)
     649              :    {
     650            0 :       m_aoCalDir = aoCalDir;
     651            0 :       newcal = true;
     652              :    }
     653              : 
     654            0 :    std::string nameFile = m_aoCalDir + "/LOOPNAME";
     655            0 :    fin.open(nameFile);
     656            0 :    if(!fin)
     657              :    {
     658            0 :       return log<software_error, -1>({__FILE__, __LINE__, errno, "cacaoInterface::getAOCalib failed to open: " + nameFile});
     659              :    }
     660            0 :    fin >> m_loopName;
     661            0 :    fin.close();
     662              : 
     663            0 :    m_fpsFifo = "/milk/shm/" + m_loopName + "_fpsCTRL.fifo";
     664              : 
     665            0 :    calsrc = "/milk/shm/aol" + m_loopNumber + "_calib_loaded.txt";
     666            0 :    fin.open(calsrc);
     667            0 :    if(!fin)
     668              :    {
     669            0 :       return log<software_error, -1>({__FILE__, __LINE__, errno, "cacaoInterface::getAOCalib failed to open: " + calsrc});
     670              :    }
     671            0 :    std::string aoCalLoadTime;
     672            0 :    fin >> aoCalLoadTime;
     673              : 
     674            0 :    if(aoCalLoadTime != m_aoCalLoadTime)
     675              :    {
     676            0 :       newcal = true;
     677            0 :       m_aoCalLoadTime = aoCalLoadTime;
     678              :    }
     679              : 
     680            0 :    if(newcal)
     681              :    {
     682            0 :       log<text_log>("new calibration " + m_aoCalDir + " loaded at: " + m_aoCalLoadTime, logPrio::LOG_INFO);
     683              :    }
     684              : 
     685            0 :    fin.close();
     686              : 
     687            0 :    calsrc = m_aoCalDir + "/calib_archived.txt";
     688              : 
     689            0 :    fin.open(calsrc);
     690            0 :    if(!fin)
     691              :    {
     692            0 :       return log<software_error, -1>({__FILE__, __LINE__, errno, "cacaoInterface::getAOCalib failed to open: " + calsrc});
     693              :    }
     694              : 
     695            0 :    while(!fin.eof())
     696              :    {
     697            0 :       fin >> m_aoCalArchiveTime;
     698              :    }
     699            0 :    fin.close();
     700              : 
     701              : 
     702            0 :    return 0;
     703            0 : }
     704              : 
     705            0 : int cacaoInterface::checkLoopProcesses()
     706              : {
     707              :    ///\todo look for actual evidence of processes, such as interrogating ps.
     708              : 
     709            0 :    m_loopProcesses = m_loopProcesses_stat;
     710              : 
     711            0 :    return 0;
     712              : }
     713              : 
     714            0 : int cacaoInterface::setGain()
     715              : {
     716            0 :    recordLoopGain(true);
     717            0 :    return setFPSVal("mfilt", "loopgain", m_gain_target);
     718              : }
     719              : 
     720            0 : int cacaoInterface::setMultCoeff()
     721              : {
     722            0 :    recordLoopGain(true);
     723            0 :    return setFPSVal("mfilt", "loopmult", m_multCoeff_target);
     724              : }
     725              : 
     726            0 : int cacaoInterface::setMaxLim()
     727              : {
     728            0 :    recordLoopGain(true);
     729            0 :    return setFPSVal("mfilt", "looplimit", m_maxLim_target);
     730              : }
     731              : 
     732            0 : int cacaoInterface::loopOn()
     733              : {
     734            0 :    recordLoopGain(true);
     735            0 :    if( setFPSVal("mfilt", "loopON", std::string("ON")) != 0)
     736              :    {
     737            0 :       return log<software_error,-1>({__FILE__, __LINE__, "error setting FPS val"});
     738              :    }
     739              : 
     740            0 :    log<loop_closed>();
     741              : 
     742            0 :    return 0;
     743              : 
     744              : }
     745              : 
     746            0 : int cacaoInterface::loopOff()
     747              : {
     748            0 :    recordLoopGain(true);
     749            0 :    if( setFPSVal("mfilt", "loopON", std::string("OFF")) != 0)
     750              :    {
     751            0 :       return log<software_error,-1>({__FILE__, __LINE__, "error setting FPS val"});
     752              :    }
     753              : 
     754            0 :    if(m_gain == 0)
     755              :    {
     756            0 :       log<loop_open>();
     757              :    }
     758              :    else
     759              :    {
     760            0 :       log<loop_paused>();
     761              :    }
     762              : 
     763            0 :    return 0;
     764              : 
     765              : }
     766              : 
     767            0 : int cacaoInterface::loopZero()
     768              : {
     769            0 :    if( setFPSVal("mfilt", "loopZERO", std::string("ON")) != 0)
     770              :    {
     771            0 :       return log<software_error,-1>({__FILE__, __LINE__, "error setting FPS val"});
     772              :    }
     773              : 
     774            0 :    log<text_log>("loop zeroed", logPrio::LOG_NOTICE);
     775              : 
     776            0 :    return 0;
     777              : 
     778              : }
     779              : 
     780            0 : void cacaoInterface::fmThreadStart( cacaoInterface * c )
     781              : {
     782            0 :    c->fmThreadExec();
     783            0 : }
     784              : 
     785              : 
     786            0 : void cacaoInterface::fmThreadExec( )
     787              : {
     788            0 :    m_fmThreadID = syscall(SYS_gettid);
     789              : 
     790            0 :    while( m_fmThreadInit == true && shutdown() == 0)
     791              :    {
     792            0 :       sleep(1);
     793              :    }
     794              : 
     795            0 :    while(shutdown() == 0)
     796              :    {
     797            0 :       if(m_fpsFifo == "")
     798              :       {
     799            0 :          sleep(1);
     800            0 :          continue;
     801              :       }
     802              : 
     803            0 :       std::string ans = getFPSValStr("mfilt", "loopON");
     804              : 
     805            0 :       if(ans[1] == 'F')
     806              :       {
     807            0 :          m_loopState = 0;
     808              :       }
     809            0 :       else m_loopState = 2; //closed
     810              : 
     811            0 :       ans = getFPSValNum("mfilt", "loopgain");
     812              : 
     813              :       try
     814              :       {
     815            0 :          m_gain = std::stof(ans);
     816              :       }
     817            0 :       catch(const std::exception& e)
     818              :       {
     819            0 :          m_gain = 0;
     820            0 :       }
     821              : 
     822            0 :       ans = getFPSValNum("mfilt", "loopmult");
     823              :       try
     824              :       {
     825            0 :          m_multCoeff = std::stof(ans);
     826              :       }
     827            0 :       catch(...)
     828              :       {
     829            0 :          m_multCoeff = 0;
     830            0 :       }
     831            0 :       ans = getFPSValNum("mfilt", "looplimit");
     832              :       try
     833              :       {
     834            0 :          m_maxLim = std::stof(ans);
     835              :       }
     836            0 :       catch(...)
     837              :       {
     838            0 :          m_maxLim = 0;
     839            0 :       }
     840              : 
     841            0 :       recordLoopGain();
     842              : 
     843            0 :       mx::sys::milliSleep(500);
     844              : 
     845            0 :    }
     846              : 
     847            0 :    return;
     848              : }
     849              : 
     850            3 : INDI_NEWCALLBACK_DEFN(cacaoInterface, m_indiP_loopState )(const pcf::IndiProperty &ipRecv)
     851              : {
     852            3 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_loopState, ipRecv);
     853              : 
     854              :     if(!ipRecv.find("toggle")) return 0;
     855              : 
     856              :     std::unique_lock<std::mutex> lock(m_indiMutex);
     857              : 
     858              :     if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On)
     859              :     {
     860              :         return loopOn();
     861              :     }
     862              :     else if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off)
     863              :     {
     864              :         return loopOff();
     865              :     }
     866              : 
     867              :     log<software_error>({__FILE__,__LINE__, "switch state fall through."});
     868              :     return -1;
     869              : }
     870              : 
     871            3 : INDI_NEWCALLBACK_DEFN(cacaoInterface, m_indiP_loopGain )(const pcf::IndiProperty &ipRecv)
     872              : {
     873            3 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_loopGain, ipRecv);
     874              : 
     875              :     float current = -1;
     876              :     float target = -1;
     877              : 
     878              :     if(ipRecv.find("current"))
     879              :     {
     880              :         current = ipRecv["current"].get<double>();
     881              :     }
     882              : 
     883              :     if(ipRecv.find("target"))
     884              :     {
     885              :         target = ipRecv["target"].get<double>();
     886              :     }
     887              : 
     888              :     if(target == -1) target = current;
     889              : 
     890              :     if(target == -1)
     891              :     {
     892              :         return 0;
     893              :     }
     894              : 
     895              :     std::lock_guard<std::mutex> guard(m_indiMutex);
     896              : 
     897              :     m_gain_target = target;
     898              : 
     899              :     updateIfChanged(m_indiP_loopGain, "target", m_gain_target);
     900              : 
     901              :     return setGain();
     902              : }
     903              : 
     904            3 : INDI_NEWCALLBACK_DEFN(cacaoInterface, m_indiP_loopZero )(const pcf::IndiProperty &ipRecv)
     905              : {
     906            3 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_loopZero, ipRecv);
     907              : 
     908              :     if(!ipRecv.find("request")) return 0;
     909              : 
     910              :     std::unique_lock<std::mutex> lock(m_indiMutex);
     911              : 
     912              :     if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
     913              :     {
     914              :         return loopZero();
     915              :     }
     916              : 
     917              :     return 0;
     918              : }
     919              : 
     920            3 : INDI_NEWCALLBACK_DEFN(cacaoInterface, m_indiP_multCoeff )(const pcf::IndiProperty &ipRecv)
     921              : {
     922            3 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_multCoeff, ipRecv);
     923              : 
     924              :     float current = -1;
     925              :     float target = -1;
     926              : 
     927              :     if(ipRecv.find("current"))
     928              :     {
     929              :         current = ipRecv["current"].get<double>();
     930              :     }
     931              : 
     932              :     if(ipRecv.find("target"))
     933              :     {
     934              :         target = ipRecv["target"].get<double>();
     935              :     }
     936              : 
     937              :     if(target == -1) target = current;
     938              : 
     939              :     if(target == -1)
     940              :     {
     941              :         return 0;
     942              :     }
     943              : 
     944              :     std::lock_guard<std::mutex> guard(m_indiMutex);
     945              : 
     946              :     m_multCoeff_target = target;
     947              :     updateIfChanged(m_indiP_multCoeff, "target", target);
     948              : 
     949              :     return setMultCoeff();
     950              : }
     951              : 
     952            3 : INDI_NEWCALLBACK_DEFN(cacaoInterface, m_indiP_maxLim )(const pcf::IndiProperty &ipRecv)
     953              : {
     954            3 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_maxLim, ipRecv);
     955              : 
     956              :     float current = -1;
     957              :     float target = -1;
     958              : 
     959              :     if(ipRecv.find("current"))
     960              :     {
     961              :         current = ipRecv["current"].get<double>();
     962              :     }
     963              : 
     964              :     if(ipRecv.find("target"))
     965              :     {
     966              :         target = ipRecv["target"].get<double>();
     967              :     }
     968              : 
     969              :     if(target == -1) target = current;
     970              : 
     971              :     if(target == -1)
     972              :     {
     973              :         return 0;
     974              :     }
     975              : 
     976              :     std::lock_guard<std::mutex> guard(m_indiMutex);
     977              :     m_maxLim_target = target;
     978              :     updateIfChanged(m_indiP_maxLim, "target", target);
     979              : 
     980              :     return setMaxLim();
     981              : }
     982              : 
     983              : inline
     984            0 : int cacaoInterface::checkRecordTimes()
     985              : {
     986            0 :    return telemeterT::checkRecordTimes(telem_loopgain());
     987              : }
     988              : 
     989              : inline
     990            0 : int cacaoInterface::recordTelem( const telem_loopgain * )
     991              : {
     992            0 :    return recordLoopGain(true);
     993              : }
     994              : 
     995              : inline
     996            0 : int cacaoInterface::recordLoopGain( bool force )
     997              : {
     998              :    static uint8_t state {0};
     999              :    static float gain {-1000};
    1000              :    static float multcoef {0};
    1001              :    static float limit {0};
    1002              : 
    1003            0 :    if(state != m_loopState || gain != m_gain || multcoef != m_multCoeff || limit != m_maxLim || force)
    1004              :    {
    1005            0 :       state = m_loopState;
    1006            0 :       gain = m_gain;
    1007            0 :       multcoef = m_multCoeff;
    1008            0 :       limit = m_maxLim;
    1009              : 
    1010            0 :       telem<telem_loopgain>({state, m_gain, m_multCoeff, m_maxLim});
    1011              :    }
    1012              : 
    1013            0 :    return 0;
    1014              : }
    1015              : 
    1016              : } //namespace app
    1017              : } //namespace MagAOX
    1018              : 
    1019              : #endif //cacaoInterface_hpp
        

Generated by: LCOV version 2.0-1