LCOV - code coverage report
Current view: top level - apps/trippLitePDU - trippLitePDU.hpp (source / functions) Coverage Total Hit
Test: MagAOX Lines: 2.8 % 284 8
Test Date: 2026-04-15 19:34:29 Functions: 11.8 % 17 2

            Line data    Source code
       1              : /** \file trippLitePDU.hpp
       2              :   * \brief The MagAO-X Tripp Lite Power Distribution Unit controller.
       3              :   *
       4              :   * \author Jared R. Males (jaredmales@gmail.com)
       5              :   *
       6              :   * \ingroup trippLitePDU_files
       7              :   */
       8              : 
       9              : #ifndef trippLitePDU_hpp
      10              : #define trippLitePDU_hpp
      11              : 
      12              : 
      13              : #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
      14              : #include "../../magaox_git_version.h"
      15              : 
      16              : #ifdef XWC_SIM_MODE
      17              : 
      18              : #include "trippLitePDU_simulator.hpp"
      19              : 
      20              : #endif
      21              : 
      22              : /** \defgroup trippLitePDU Tripp Lite PDU
      23              :   * \brief Control of MagAO-X Tripp Lite PDUs.
      24              :   *
      25              :   * <a href="../handbook/operating/software/apps/trippLitePDU.html">Application Documentation</a>
      26              :   *
      27              :   * \ingroup apps
      28              :   *
      29              :   */
      30              : 
      31              : /** \defgroup trippLitePDU_files Tripp Lite PDU Files
      32              :   * \ingroup trippLitePDU
      33              :   */
      34              : 
      35              : namespace MagAOX
      36              : {
      37              : namespace app
      38              : {
      39              : 
      40              : /// MagAO-X application to control a Tripp Lite power distribution unit (PDU).
      41              : /** The device outlets are organized into channels.  See \ref dev::outletController for details of configuring the channels.
      42              :   *
      43              :   * The line frequency and voltage, and the total load on the PDU, are monitored.
      44              :   *
      45              :   * \todo need username and secure password handling
      46              :   * \todo need to recognize signals in tty polls and not return errors, etc.
      47              :   * \todo begin logging freq/volt/amps telemetry
      48              :   * \todo research load warnings
      49              :   * \todo tests for parser
      50              :   * \todo test for load warnings
      51              :   * \todo load warnings/crit values can be logged on parse errors -- make this an issue
      52              :   * \todo segfaults if device can not be reached on network -- make this an issue
      53              :   *
      54              :   * \ingroup trippLitePDU
      55              :   */
      56              : class trippLitePDU : public MagAOXApp<>, public dev::outletController<trippLitePDU>, public dev::ioDevice
      57              : {
      58              : 
      59              : protected:
      60              : 
      61              :    std::string m_deviceAddr; ///< The device address
      62              :    std::string m_devicePort; ///< The device port
      63              :    std::string m_deviceUsername; ///< The login username for this device
      64              :    std::string m_devicePassFile; ///< The login password for this device
      65              :    int m_deviceVersion {0}; ///< Version 0 = the old PDUs, version 1 = new PDUMH15NET2LX, which is a new login procedure to get to the CLI.
      66              : 
      67              :    float m_freqLowWarn {59};    ///< The low-frequency warning threshold
      68              :    float m_freqHighWarn {61};   ///< The high-frequency warning threshold
      69              : 
      70              :    float m_freqLowAlert {58};   ///< The low-frequency alert threshold
      71              :    float m_freqHighAlert {62};  ///< The high-frequency alert threshold
      72              : 
      73              :    float m_freqLowEmerg {57};   ///< The low-frequency emergency threshold
      74              :    float m_freqHighEmerg {63};  ///< The high-frequency emergency threshold
      75              : 
      76              :    float m_voltLowWarn {105};   ///< The low-voltage warning threshold
      77              :    float m_voltHighWarn {125};  ///< The high-voltage warning threshold
      78              : 
      79              :    float m_voltLowAlert {101};  ///< The low-voltage alert threshold
      80              :    float m_voltHighAlert {126}; ///< The high-voltage alert threshold
      81              : 
      82              :    float m_voltLowEmerg {99};   ///< The low-voltage emergency threshold
      83              :    float m_voltHighEmerg {128}; ///< The high-voltage emergency threshold
      84              : 
      85              :    float m_currWarn {15};  ///< The high-current warning threshold
      86              :    float m_currAlert {16}; ///< The high-current alert threshold
      87              :    float m_currEmerg {20}; ///< The high-current emergency threshold
      88              : 
      89              :    #ifndef XWC_SIM_MODE
      90              :    tty::telnetConn m_telnetConn; ///< The telnet connection manager
      91              :    #endif
      92              : 
      93              :    std::string m_status; ///< The device status
      94              :    float m_frequency {0}; ///< The line frequency reported by the device.
      95              :    float m_voltage {0}; ///< The line voltage reported by the device.
      96              :    float m_current {0}; ///< The current being reported by the device.
      97              : 
      98              : public:
      99              : 
     100              :     /// Default c'tor.
     101              :     trippLitePDU();
     102              : 
     103              :     /// D'tor, declared and defined for noexcept.
     104            1 :     ~trippLitePDU() noexcept
     105            1 :     {}
     106              : 
     107              :     /** \name MagAOXApp Interface
     108              :       *
     109              :       * @{
     110              :       */
     111              : 
     112              :     /// Setup the configuration system (called by MagAOXApp::setup())
     113              :     virtual void setupConfig();
     114              : 
     115              :     /// load the configuration system results (called by MagAOXApp::setup())
     116              :     virtual void loadConfig();
     117              : 
     118              :     /// Startup functions
     119              :     /** Setsup the INDI vars.
     120              :       * Checks if the device was found during loadConfig.
     121              :       */
     122              :     virtual int appStartup();
     123              : 
     124              :     /// Implementation of the FSM for the tripp lite PDU.
     125              :     virtual int appLogic();
     126              : 
     127              :     /// Do any needed shutdown tasks.  Currently nothing in this app.
     128              :     virtual int appShutdown();
     129              : 
     130              :     ///@}
     131              : 
     132              :     /** \name outletController Interface
     133              :       *
     134              :       * @{
     135              :       */
     136              : 
     137              :     /// Update a single outlet state
     138              :     /** For the trippLitePDU this isn't possible for a single outlet, so this calls updateOutletStates.
     139              :       *
     140              :       * \returns 0 on success
     141              :       * \returns -1 on error
     142              :       */
     143              :     virtual int updateOutletState( int outletNum /**< [in] the outlet number to update */);
     144              : 
     145              :     /// Queries the device to find the state of each outlet, as well as other parameters.
     146              :     /** Sends `devstatus` to the device, and parses the result.
     147              :       *
     148              :       * \returns 0 on success
     149              :       * \returns -1 on error
     150              :       */
     151              :     virtual int updateOutletStates();
     152              : 
     153              :     /// Turn on an outlet.
     154              :     /**
     155              :       * \returns 0 on success
     156              :       * \returns -1 on error
     157              :       */
     158              :     virtual int turnOutletOn( int outletNum /**< [in] the outlet number to turn on */);
     159              : 
     160              :     /// Turn off an outlet.
     161              :     /**
     162              :       * \returns 0 on success
     163              :       * \returns -1 on error
     164              :       */
     165              :     virtual int turnOutletOff( int outletNum /**< [in] the outlet number to turn off */);
     166              : 
     167              :     ///@}
     168              : 
     169              :     /** \name Device Interface
     170              :       *
     171              :       * These functions invoke the simulator code when enabled.
     172              :       *
     173              :       * @{
     174              :       */
     175              :     int devConnect();
     176              : 
     177              :     int devLogin();
     178              : 
     179              :     void devPostLogin();
     180              : 
     181              :     int devStatus(std::string & strRead);
     182              : 
     183              :     /// Parse the PDU devstatus response.
     184              :     /**
     185              :       * \returns 0 on success
     186              :       * \returns \<0 on error, with value indicating location of error.
     187              :       */
     188              :     int parsePDUStatus( std::string & strRead );
     189              : 
     190              :     ///@}
     191              : 
     192              :     void updateAlarmsAndWarnings();
     193              : 
     194              : protected:
     195              : 
     196              :    //declare our properties
     197              :    pcf::IndiProperty m_indiP_status; ///< The device's status string
     198              :    pcf::IndiProperty m_indiP_load; ///< The line and load characteristics
     199              : 
     200              : 
     201              : #ifdef XWC_SIM_MODE
     202              : 
     203              : public:
     204              : 
     205              :     trippLitePDU_simulator m_simulator;
     206              : 
     207              : #endif
     208              : 
     209              : };
     210              : 
     211            3 : trippLitePDU::trippLitePDU() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
     212              : {
     213            1 :    m_firstOne = true;
     214            1 :    m_stateDelay = 5;
     215              : 
     216            1 :    setNumberOfOutlets(8);
     217            1 :    m_loopPause=2000000000;//Default to 2 sec loop pause to lessen the load on the PDUs.
     218              : 
     219            1 :    return;
     220            0 : }
     221              : 
     222            0 : void trippLitePDU::setupConfig()
     223              : {
     224            0 :    config.add("device.address", "a", "device.address", argType::Required, "device", "address", false, "string", "The device address.");
     225            0 :    config.add("device.port", "p", "device.port", argType::Required, "device", "port", false, "string", "The device port.");
     226            0 :    config.add("device.username", "u", "device.username", argType::Required, "device", "username", false, "string", "The device login username.");
     227            0 :    config.add("device.passfile", "", "device.passfile", argType::Required, "device", "passfile", false, "string", "The device login password file (relative to secrets dir).");
     228            0 :    config.add("device.powerAlertVersion", "", "device.powerAlertVersion", argType::Required, "device", "powerAlertVersion", false, "int", "The device network interface version.  0 is PDU..., 1 is newer LX platform.");
     229              : 
     230            0 :    dev::ioDevice::setupConfig(config);
     231              : 
     232            0 :    config.add("limits.freqLowWarn", "", "limits.freqLowWarn", argType::Required, "limits", "freqLowWarn", false, "int", "The low-frequency warning threshold");
     233            0 :    config.add("limits.freqHighWarn", "", "limits.freqHighWarn", argType::Required, "limits", "freqHighWarn", false, "int", "The high-frequency warning threshold");
     234            0 :    config.add("limits.freqLowAlert", "", "limits.freqLowAlert", argType::Required, "limits", "freqLowAlert", false, "int", "The low-frequency alert threshold");
     235            0 :    config.add("limits.freqHighAlert", "", "limits.freqHighAlert", argType::Required, "limits", "freqHighAlert", false, "int", "The high-frequency alert threshold");
     236            0 :    config.add("limits.freqLowEmerg", "", "limits.freqLowEmerg", argType::Required, "limits", "freqLowEmerg", false, "int", "The low-frequency emergency threshold");
     237            0 :    config.add("limits.freqHighEmerg", "", "limits.freqHighEmerg", argType::Required, "limits", "freqHighEmerg", false, "int", "The high-frequency emergency threshold");
     238              : 
     239            0 :    config.add("limits.voltLowWarn", "", "limits.voltLowWarn", argType::Required, "limits", "voltLowWarn", false, "int", "The low-voltage warning threshold");
     240            0 :    config.add("limits.voltHighWarn", "", "limits.voltHighWarn", argType::Required, "limits", "voltHighWarn", false, "int", "The high-voltage warning threshold");
     241            0 :    config.add("limits.voltLowAlert", "", "limits.voltLowAlert", argType::Required, "limits", "voltLowAlert", false, "int", "The low-voltage alert threshold");
     242            0 :    config.add("limits.voltHighAlert", "", "limits.voltHighAlert", argType::Required, "limits", "voltHighAlert", false, "int", "The high-voltage alert threshold");
     243            0 :    config.add("limits.voltLowEmerg", "", "limits.voltLowEmerg", argType::Required, "limits", "voltLowEmerg", false, "int", "The low-voltage emergency threshold");
     244            0 :    config.add("limits.voltHighEmerg", "", "limits.voltHighEmerg", argType::Required, "limits", "voltHighEmerg", false, "int", "The high-voltage emergency threshold");
     245              : 
     246            0 :    config.add("limits.currWarn", "", "limits.currWarn", argType::Required, "limits", "currWarn", false, "int", "The high-current warning threshold");
     247            0 :    config.add("limits.currAlert", "", "limits.currAlert", argType::Required, "limits", "currAlert", false, "int", "The high-current alert threshold");
     248            0 :    config.add("limits.currEmerg", "", "limits.currEmerg", argType::Required, "limits", "currEmerg", false, "int", "The high-current emergency threshold");
     249              : 
     250            0 :    dev::outletController<trippLitePDU>::setupConfig(config);
     251              : 
     252            0 : }
     253              : 
     254              : 
     255            0 : void trippLitePDU::loadConfig()
     256              : {
     257            0 :    config(m_deviceAddr, "device.address");
     258            0 :    config(m_devicePort, "device.port");
     259            0 :    config(m_deviceUsername, "device.username");
     260            0 :    config(m_devicePassFile, "device.passfile");
     261            0 :    config(m_deviceVersion, "device.powerAlertVersion");
     262              : 
     263            0 :    dev::ioDevice::loadConfig(config);
     264              : 
     265            0 :    config(m_freqLowWarn, "limits.freqLowWarn");
     266            0 :    config(m_freqHighWarn, "limits.freqHighWarn");
     267            0 :    config(m_freqLowAlert, "limits.freqLowAlert");
     268            0 :    config(m_freqHighAlert, "limits.freqHighAlert");
     269            0 :    config(m_freqLowEmerg, "limits.freqLowEmerg");
     270            0 :    config(m_freqHighEmerg, "limits.freqHighEmerg");
     271              : 
     272            0 :    config(m_voltLowWarn, "limits.voltLowWarn");
     273            0 :    config(m_voltHighWarn, "limits.voltHighWarn");
     274            0 :    config(m_voltLowAlert, "limits.voltLowAlert");
     275            0 :    config(m_voltHighAlert, "limits.voltHighAlert");
     276            0 :    config(m_voltLowEmerg, "limits.voltLowEmerg");
     277            0 :    config(m_voltHighEmerg, "limits.voltHighEmerg");
     278              : 
     279            0 :    config(m_currWarn, "limits.currWarn");
     280            0 :    config(m_currAlert, "limits.currAlert");
     281            0 :    config(m_currEmerg, "limits.currEmerg");
     282              : 
     283            0 :    dev::outletController<trippLitePDU>::loadConfig(config);
     284              : 
     285              : 
     286            0 : }
     287              : 
     288            0 : int trippLitePDU::appStartup()
     289              : {
     290              :     #ifdef XWC_SIM_MODE
     291            0 :     log<text_log>("XWC_SIM_MODE active");
     292              :     #endif
     293              : 
     294              :     // set up the  INDI properties
     295            0 :     REG_INDI_NEWPROP_NOCB(m_indiP_status, "status", pcf::IndiProperty::Text);
     296            0 :     m_indiP_status.add (pcf::IndiElement("value"));
     297              : 
     298            0 :     REG_INDI_NEWPROP_NOCB(m_indiP_load, "load", pcf::IndiProperty::Number);
     299            0 :     m_indiP_load.add (pcf::IndiElement("frequency"));
     300            0 :     m_indiP_load.add (pcf::IndiElement("voltage"));
     301            0 :     m_indiP_load.add (pcf::IndiElement("current"));
     302              : 
     303            0 :     if(dev::outletController<trippLitePDU>::appStartup() < 0)
     304              :     {
     305            0 :         return log<text_log,-1>("Error setting up INDI for outlet control.", logPrio::LOG_CRITICAL);
     306              :     }
     307              : 
     308            0 :     state(stateCodes::NOTCONNECTED);
     309              : 
     310            0 :     return 0;
     311              : }
     312              : 
     313            0 : int trippLitePDU::appLogic()
     314              : {
     315            0 :     if( state() == stateCodes::NOTCONNECTED )
     316              :     {
     317              :         static int lastrv = 0; //Used to handle a change in error within the same state.  Make general?
     318              :         static int lasterrno = 0;
     319              : 
     320            0 :         int rv = devConnect();
     321              : 
     322            0 :         if(rv == 0)
     323              :         {
     324            0 :             state(stateCodes::CONNECTED);
     325              : 
     326            0 :             if(!stateLogged())
     327              :             {
     328            0 :                 std::string logs = "Connected to " + m_deviceAddr + ":" + m_devicePort;
     329            0 :                 log<text_log>(logs);
     330            0 :             }
     331            0 :             lastrv = rv;
     332            0 :             lasterrno = errno;
     333              :         }
     334              :         else
     335              :         {
     336            0 :             if(!stateLogged())
     337              :             {
     338            0 :                log<text_log>({"Failed to connect to " + m_deviceAddr + ":" + m_devicePort}, logPrio::LOG_ERROR);
     339              :             }
     340            0 :             if( rv != lastrv )
     341              :             {
     342            0 :                log<software_error>( {__FILE__,__LINE__, 0, rv,  tty::ttyErrorString(rv)} );
     343            0 :                lastrv = rv;
     344              :             }
     345            0 :             if( errno != lasterrno )
     346              :             {
     347            0 :                log<software_error>( {__FILE__,__LINE__, errno});
     348            0 :                lasterrno = errno;
     349              :             }
     350            0 :             return 0;
     351              :         }
     352              :     }
     353              : 
     354            0 :     if( state() == stateCodes::CONNECTED )
     355              :     {
     356            0 :         int rv = devLogin();
     357              : 
     358            0 :         if(rv == 0)
     359              :         {
     360            0 :             state(stateCodes::LOGGEDIN);
     361              :         }
     362              :         else
     363              :         {
     364            0 :            if(rv == TELNET_E_LOGINTIMEOUT)
     365              :            {
     366            0 :                 state(stateCodes::NOTCONNECTED);
     367            0 :                 log<text_log>("login timedout", logPrio::LOG_ERROR);
     368            0 :                 return 0;
     369              :            }
     370              : 
     371            0 :            state(stateCodes::FAILURE);
     372            0 :            log<text_log>("login failure", logPrio::LOG_CRITICAL);
     373            0 :            return -1;
     374              :         }
     375              :     }
     376              : 
     377            0 :     if(state() == stateCodes::LOGGEDIN)
     378              :     {
     379            0 :         devPostLogin();
     380              : 
     381            0 :         state(stateCodes::READY);
     382              :     }
     383              : 
     384            0 :     if(state() == stateCodes::READY)
     385              :     {
     386            0 :        std::unique_lock<std::mutex> lock(m_indiMutex, std::try_to_lock);
     387              : 
     388            0 :        if( !lock.owns_lock())
     389              :        {
     390            0 :           return 0;
     391              :        }
     392              : 
     393            0 :        int rv = updateOutletStates();
     394              : 
     395            0 :        if(rv < 0) return log<software_error,-1>();
     396              : 
     397            0 :        updateAlarmsAndWarnings();
     398              : 
     399            0 :        return 0;
     400            0 :     }
     401              : 
     402            0 :     state(stateCodes::FAILURE);
     403            0 :     log<text_log>("appLogic fell through", logPrio::LOG_CRITICAL);
     404            0 :     return -1;
     405              : 
     406              : }
     407              : 
     408            0 : int trippLitePDU::appShutdown()
     409              : {
     410              :    //don't bother
     411            0 :    return 0;
     412              : }
     413              : 
     414            0 : int trippLitePDU::updateOutletState( int outletNum )
     415              : {
     416              :    static_cast<void>(outletNum);
     417              : 
     418            0 :    return updateOutletStates(); //We can't do just one.
     419              : }
     420              : 
     421              : 
     422            0 : int trippLitePDU::updateOutletStates()
     423              : {
     424              :     int rv;
     425            0 :     std::string strRead;
     426              : 
     427            0 :     rv = devStatus(strRead);
     428              : 
     429            0 :     if(rv < 0 )
     430              :     {
     431            0 :         log<software_error>("error getting device status");
     432            0 :         state(stateCodes::NOTCONNECTED);
     433            0 :         return 0;
     434              :     }
     435              : 
     436            0 :     if(rv > 0)
     437              :     {
     438            0 :         return 0; //this means the re-read was successful, but we don't want to parse this time.
     439              :     }
     440              : 
     441            0 :     rv = parsePDUStatus( strRead);
     442              : 
     443            0 :     if(rv == 0)
     444              :     {
     445            0 :         updateIfChanged(m_indiP_status, "value", m_status);
     446              : 
     447            0 :         updateIfChanged(m_indiP_load, "frequency", m_frequency);
     448              : 
     449            0 :         updateIfChanged(m_indiP_load, "voltage", m_voltage);
     450              : 
     451            0 :         updateIfChanged(m_indiP_load, "current", m_current);
     452              : 
     453            0 :         dev::outletController<trippLitePDU>::updateINDI();
     454              :     }
     455              :     else
     456              :     {
     457            0 :         log<software_error>({0, rv, "parse error"});
     458              :     }
     459              : 
     460            0 :     return 0;
     461            0 : }
     462              : 
     463            0 : int trippLitePDU::turnOutletOn( int outletNum )
     464              : {
     465            0 :     std::lock_guard<std::mutex> guard(m_indiMutex);  //Lock the mutex before doing anything
     466              : 
     467              :     #ifndef XWC_SIM_MODE
     468              :     std::string cmd = std::format("loadctl on -o {} --force\r", (outletNum+1)); //Internally 0 counted, device starts at 1.
     469              : 
     470              :     int rv = m_telnetConn.writeRead( cmd, true, m_writeTimeout, m_readTimeout);
     471              : 
     472              :     #else
     473              : 
     474            0 :     int rv = m_simulator.turnOutletOn(outletNum);
     475              : 
     476              :     #endif
     477              : 
     478            0 :     if(rv < 0) 
     479              :     {
     480            0 :         return log<software_error, -1>({0, rv, "telnet error"});
     481              :     }
     482              : 
     483            0 :     return 0;
     484            0 : }
     485              : 
     486            0 : int trippLitePDU::turnOutletOff( int outletNum )
     487              : {
     488            0 :     std::lock_guard<std::mutex> guard(m_indiMutex);  //Lock the mutex before doing anything
     489              : 
     490              :     #ifndef XWC_SIM_MODE
     491              :     std::string cmd = std::format("loadctl off -o {} --force\r", (outletNum+1)); //Internally 0 counted, device starts at 1.
     492              : 
     493              :     int rv = m_telnetConn.writeRead( cmd, true, m_writeTimeout, m_readTimeout);
     494              : 
     495              :     #else
     496              : 
     497            0 :     int rv = m_simulator.turnOutletOff(outletNum);
     498              : 
     499              :     #endif
     500              : 
     501            0 :     if(rv < 0) return log<software_error, -1>({__FILE__, __LINE__, 0, rv, "telnet error"});
     502              : 
     503            0 :    return 0;
     504            0 : }
     505              : 
     506            0 : int trippLitePDU::devConnect()
     507              : {
     508              :     #ifndef XWC_SIM_MODE
     509              : 
     510              :     return m_telnetConn.connect(m_deviceAddr, m_devicePort);
     511              : 
     512              :     #else
     513              : 
     514            0 :     return m_simulator.connect(m_deviceAddr, m_devicePort);
     515              : 
     516              :     #endif
     517              : }
     518              : 
     519            0 : int trippLitePDU::devLogin()
     520              : {
     521              :     #ifndef XWC_SIM_MODE
     522              : 
     523              :     //Newer version of power alert changed login (at least the first one)
     524              :     if(m_deviceVersion > 0)
     525              :     {
     526              :         m_telnetConn.m_usernamePrompt = "login:";
     527              :         m_telnetConn.m_prompt = ">>";
     528              :     }
     529              : 
     530              :     return m_telnetConn.login("localadmin", "localadmin");
     531              : 
     532              :     #else
     533              : 
     534            0 :     return m_simulator.login("localadmin", "localadmin");
     535              : 
     536              :     #endif
     537              : }
     538              : 
     539            0 : void trippLitePDU::devPostLogin()
     540              : {
     541              : 
     542              :     #ifndef XWC_SIM_MODE
     543              : 
     544              :     //For newer version of power alert we need to select C.L.I.
     545              :     if(m_deviceVersion > 0)
     546              :     {
     547              :         m_telnetConn.writeRead("E\n", false, m_writeTimeout, m_readTimeout);
     548              :         m_telnetConn.m_prompt = "$> ";
     549              :     }
     550              : 
     551              :     #else
     552              : 
     553            0 :     m_simulator.postLogin();
     554              : 
     555              :     #endif
     556            0 : }
     557              : 
     558            0 : int trippLitePDU::devStatus(std::string & strRead)
     559              : {
     560              :     #ifndef XWC_SIM_MODE
     561              : 
     562              :     int rv = m_telnetConn.writeRead("devstatus\n", true, m_writeTimeout, m_readTimeout);
     563              : 
     564              :     strRead = m_telnetConn.m_strRead;
     565              : 
     566              :     if(rv == TTY_E_TIMEOUTONREAD || rv == TTY_E_TIMEOUTONREADPOLL)
     567              :     {
     568              :         rv = m_telnetConn.read(m_readTimeout, false);
     569              : 
     570              :         if( rv < 0 )
     571              :         {
     572              :             log<software_error>({__FILE__, __LINE__, 0, rv, "devstatus timeout, timed out on re-read: " + tty::ttyErrorString(rv)});
     573              :             return -1;
     574              :         }
     575              : 
     576              :         log<text_log>("devstatus timeout, re-read successful");
     577              : 
     578              :         return 1;
     579              :     }
     580              :     else if(rv < 0 )
     581              :     {
     582              :         log<software_error>({__FILE__, __LINE__, 0, rv, tty::ttyErrorString(rv)});
     583              :         return -1;
     584              :     }
     585              : 
     586              :     return 0;
     587              : 
     588              :     #else
     589              : 
     590            0 :     return m_simulator.devStatus(strRead);
     591              : 
     592              :     #endif
     593              : }
     594              : 
     595            0 : int trippLitePDU::parsePDUStatus( std::string & strRead )
     596              : {
     597            0 :     size_t curpos = 0;
     598              : 
     599            0 :     curpos = strRead.find_first_of("\r\n", curpos);
     600              : 
     601            0 :     std::string sstr;
     602              : 
     603            0 :     while(curpos < strRead.size())
     604              :     {
     605            0 :         size_t eol = strRead.find_first_of("\r\n", curpos);
     606              : 
     607            0 :         if(eol == std::string::npos) eol = strRead.size();
     608              : 
     609            0 :         if(eol == curpos)
     610              :         {
     611            0 :             curpos = eol + 1;
     612            0 :             continue;
     613              :         }
     614              : 
     615            0 :         sstr = strRead.substr(curpos, eol-curpos);
     616            0 :         curpos = eol + 1;
     617              : 
     618            0 :         if(sstr[0] == '-' || sstr[0] == '0' || sstr[0] == 'L' || sstr[0] == ' ' || sstr[0] == 'D' || sstr[0] == '$') continue;
     619              : 
     620            0 :         if(sstr[0] == 'I')
     621              :         {
     622            0 :             if(sstr[6] == 'V')
     623              :             {
     624            0 :                 size_t begin = sstr.find(' ',6);
     625            0 :                 if(begin == std::string::npos)
     626              :                 {
     627            0 :                     return -1;
     628              :                 }
     629              : 
     630            0 :                 begin = sstr.find_first_not_of(' ', begin);
     631            0 :                 if(begin == std::string::npos)
     632              :                 {
     633            0 :                     return -2;
     634              :                 }
     635              : 
     636            0 :                 size_t end = sstr.find('V', begin);
     637            0 :                 if(end == std::string::npos)
     638              :                 {
     639            0 :                     return -3;
     640              :                 }
     641              : 
     642            0 :                 float V = mx::ioutils::stoT<float>( sstr.substr(begin, end-begin) );
     643              : 
     644            0 :                 m_voltage = V;
     645              :             }
     646              : 
     647            0 :             else if(sstr[6] == 'F')
     648              :             {
     649            0 :                 size_t begin = sstr.find(' ',6);
     650            0 :                 if(begin == std::string::npos)
     651              :                 {
     652            0 :                     return -4;
     653              :                 }
     654              : 
     655            0 :                 begin = sstr.find_first_not_of(' ', begin);
     656            0 :                 if(begin == std::string::npos)
     657              :                 {
     658            0 :                     return -5;
     659              :                 }
     660              : 
     661            0 :                 size_t end = sstr.find('H', begin);
     662            0 :                 if(end == std::string::npos)
     663              :                 {
     664            0 :                     return -6;
     665              :                 }
     666              : 
     667            0 :                 float F = mx::ioutils::stoT<float>( sstr.substr(begin, end-begin) );
     668              : 
     669            0 :                 m_frequency = F;
     670              :             }
     671            0 :             else return -1;
     672              :         }
     673            0 :         else if(sstr[0] == 'O')
     674              :         {
     675            0 :             if(sstr[7] == 'C')
     676              :             {
     677            0 :                 size_t begin = sstr.find(' ',7);
     678            0 :                 if(begin == std::string::npos)
     679              :                 {
     680            0 :                     return -7;
     681              :                 }
     682              : 
     683            0 :                 begin = sstr.find_first_not_of(' ', begin);
     684            0 :                 if(begin == std::string::npos)
     685              :                 {
     686            0 :                     return -8;
     687              :                 }
     688              : 
     689            0 :                 size_t end = sstr.find('A', begin);
     690            0 :                 if(end == std::string::npos)
     691              :                 {
     692            0 :                     return -9;
     693              :                 }
     694              : 
     695            0 :                 float C = mx::ioutils::stoT<float>( sstr.substr(begin, end-begin) );
     696              : 
     697            0 :                 m_current = C;
     698              :             }
     699            0 :             else if(sstr[8] == 'O')
     700              :             {
     701            0 :                 std::vector<int> outletStates(m_outletStates.size(),OUTLET_STATE_OFF);
     702              : 
     703            0 :                 size_t begin = sstr.find(' ',8);
     704            0 :                 if(begin == std::string::npos)
     705              :                 {
     706            0 :                     return -10;
     707              :                 }
     708              : 
     709            0 :                 begin = sstr.find_first_not_of(' ', begin);
     710              : 
     711            0 :                 if(begin == std::string::npos)
     712              :                 {
     713            0 :                     return -11;
     714              :                 }
     715              : 
     716            0 :                 while(begin < sstr.size())
     717              :                 {
     718            0 :                     size_t end = sstr.find(' ', begin);
     719            0 :                     if(end == std::string::npos)
     720              :                     {
     721            0 :                         end = sstr.size();
     722              :                     }
     723              : 
     724            0 :                     int onum = atoi(sstr.substr(begin, end-begin).c_str());
     725              : 
     726            0 :                     if(onum > 0 && onum < 9)
     727              :                     {
     728            0 :                         outletStates[onum-1] = OUTLET_STATE_ON; //this outlet is on.
     729              :                     }
     730            0 :                     begin = sstr.find_first_not_of(' ', end+1);
     731              :                 }
     732              : 
     733            0 :                 for(size_t i=0;i<m_outletStates.size();++i)
     734              :                 {
     735            0 :                     m_outletStates[i]=outletStates[i];
     736              :                 }
     737            0 :             }
     738            0 :             else if( sstr[7] == 'V' || sstr[7] == 'F')
     739              :             {
     740            0 :                 continue;
     741              :             }
     742              :             else
     743              :             {
     744            0 :                 return -12;
     745              :             }
     746              :         }
     747              :         else
     748              :         {
     749            0 :             return -13;
     750              :         }
     751              :     }
     752              : 
     753            0 :     return 0;
     754            0 : }
     755              : 
     756            0 : void trippLitePDU::updateAlarmsAndWarnings()
     757              : {
     758            0 :     if (m_frequency <= m_freqLowEmerg)
     759              :     {
     760            0 :         log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, below " +
     761            0 :                               std::to_string(m_freqLowEmerg) + " Hz.",  logPrio::LOG_EMERGENCY);
     762              :     }
     763            0 :     else if (m_frequency >= m_freqHighEmerg)
     764              :     {
     765            0 :         log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, above " +
     766            0 :                              std::to_string(m_freqHighEmerg) + " Hz.",  logPrio::LOG_EMERGENCY);
     767              :     }
     768            0 :     else if (m_frequency <= m_freqLowAlert)
     769              :     {
     770            0 :         log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, below " +
     771            0 :                                   std::to_string(m_freqLowAlert) + " Hz.",  logPrio::LOG_ALERT);
     772              :     }
     773            0 :     else if (m_frequency >= m_freqHighAlert)
     774              :     {
     775            0 :         log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, above " +
     776            0 :                                   std::to_string(m_freqHighAlert) + " Hz.",  logPrio::LOG_ALERT);
     777              :     }
     778            0 :     else if(m_frequency <= m_freqLowWarn)
     779              :     {
     780            0 :         log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, below " +
     781            0 :                                     std::to_string(m_freqLowWarn) + " Hz.",  logPrio::LOG_WARNING);
     782              :     }
     783            0 :     else if (m_frequency >= m_freqHighWarn)
     784              :     {
     785            0 :         log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, above " +
     786            0 :                                             std::to_string(m_freqHighWarn) + " Hz.",  logPrio::LOG_WARNING);
     787              :     }
     788              : 
     789            0 :     if (m_voltage <= m_voltLowEmerg)
     790              :     {
     791            0 :         log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, below " +
     792            0 :                                             std::to_string(m_voltLowEmerg) + " V.",  logPrio::LOG_EMERGENCY);
     793              :     }
     794            0 :     else if (m_voltage >= m_voltHighEmerg)
     795              :     {
     796            0 :         log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, above " +
     797            0 :                                             std::to_string(m_voltHighEmerg) + " V.",  logPrio::LOG_EMERGENCY);
     798              :     }
     799            0 :     else if (m_voltage <= m_voltLowAlert)
     800              :     {
     801            0 :         log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, below " +
     802            0 :                                             std::to_string(m_voltLowAlert) + " V.",  logPrio::LOG_ALERT);
     803              :     }
     804            0 :     else if (m_voltage >= m_voltHighAlert)
     805              :     {
     806            0 :         log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, above " +
     807            0 :                                                         std::to_string(m_voltHighAlert) + " V.",  logPrio::LOG_ALERT);
     808              :     }
     809            0 :     else if(m_voltage <= m_voltLowWarn)
     810              :     {
     811            0 :         log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, below " +
     812            0 :                                                 std::to_string(m_voltLowWarn) + " V.",  logPrio::LOG_WARNING);
     813              :     }
     814            0 :     else if (m_voltage >= m_voltHighWarn)
     815              :     {
     816            0 :         log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, above " +
     817            0 :                                                 std::to_string(m_voltHighWarn) + " V.",  logPrio::LOG_WARNING);
     818              :     }
     819              : 
     820            0 :     if (m_current >= m_currEmerg)
     821              :     {
     822            0 :         log<text_log>("Current is " + std::to_string(m_current) + " A, above " +
     823            0 :                                                     std::to_string(m_currEmerg) + " A.",  logPrio::LOG_EMERGENCY);
     824              :     }
     825            0 :     else if (m_current >= m_currAlert)
     826              :     {
     827            0 :         log<text_log>("Current is " + std::to_string(m_current) + " A, above " +
     828            0 :                                                         std::to_string(m_currAlert) + " A.",  logPrio::LOG_ALERT);
     829              :     }
     830            0 :     else if (m_current >= m_currWarn)
     831              :     {
     832            0 :         log<text_log>("Current is " + std::to_string(m_current) + " A, above " +
     833            0 :                                                             std::to_string(m_currWarn) + " A.",  logPrio::LOG_WARNING);
     834              :     }
     835            0 : }
     836              : 
     837              : } //namespace app
     838              : } //namespace MagAOX
     839              : 
     840              : #endif //trippLitePDU_hpp
        

Generated by: LCOV version 2.0-1