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

            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            0 :     ~trippLitePDU() noexcept
     105            0 :     {}
     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            0 : trippLitePDU::trippLitePDU() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
     212              : {
     213            0 :    m_firstOne = true;
     214            0 :    setNumberOfOutlets(8);
     215            0 :    m_loopPause=2000000000;//Default to 2 sec loop pause to lessen the load on the PDUs.
     216              : 
     217            0 :    return;
     218            0 : }
     219              : 
     220            0 : void trippLitePDU::setupConfig()
     221              : {
     222            0 :    config.add("device.address", "a", "device.address", argType::Required, "device", "address", false, "string", "The device address.");
     223            0 :    config.add("device.port", "p", "device.port", argType::Required, "device", "port", false, "string", "The device port.");
     224            0 :    config.add("device.username", "u", "device.username", argType::Required, "device", "username", false, "string", "The device login username.");
     225            0 :    config.add("device.passfile", "", "device.passfile", argType::Required, "device", "passfile", false, "string", "The device login password file (relative to secrets dir).");
     226            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.");
     227              : 
     228            0 :    dev::ioDevice::setupConfig(config);
     229              : 
     230            0 :    config.add("limits.freqLowWarn", "", "limits.freqLowWarn", argType::Required, "limits", "freqLowWarn", false, "int", "The low-frequency warning threshold");
     231            0 :    config.add("limits.freqHighWarn", "", "limits.freqHighWarn", argType::Required, "limits", "freqHighWarn", false, "int", "The high-frequency warning threshold");
     232            0 :    config.add("limits.freqLowAlert", "", "limits.freqLowAlert", argType::Required, "limits", "freqLowAlert", false, "int", "The low-frequency alert threshold");
     233            0 :    config.add("limits.freqHighAlert", "", "limits.freqHighAlert", argType::Required, "limits", "freqHighAlert", false, "int", "The high-frequency alert threshold");
     234            0 :    config.add("limits.freqLowEmerg", "", "limits.freqLowEmerg", argType::Required, "limits", "freqLowEmerg", false, "int", "The low-frequency emergency threshold");
     235            0 :    config.add("limits.freqHighEmerg", "", "limits.freqHighEmerg", argType::Required, "limits", "freqHighEmerg", false, "int", "The high-frequency emergency threshold");
     236              : 
     237            0 :    config.add("limits.voltLowWarn", "", "limits.voltLowWarn", argType::Required, "limits", "voltLowWarn", false, "int", "The low-voltage warning threshold");
     238            0 :    config.add("limits.voltHighWarn", "", "limits.voltHighWarn", argType::Required, "limits", "voltHighWarn", false, "int", "The high-voltage warning threshold");
     239            0 :    config.add("limits.voltLowAlert", "", "limits.voltLowAlert", argType::Required, "limits", "voltLowAlert", false, "int", "The low-voltage alert threshold");
     240            0 :    config.add("limits.voltHighAlert", "", "limits.voltHighAlert", argType::Required, "limits", "voltHighAlert", false, "int", "The high-voltage alert threshold");
     241            0 :    config.add("limits.voltLowEmerg", "", "limits.voltLowEmerg", argType::Required, "limits", "voltLowEmerg", false, "int", "The low-voltage emergency threshold");
     242            0 :    config.add("limits.voltHighEmerg", "", "limits.voltHighEmerg", argType::Required, "limits", "voltHighEmerg", false, "int", "The high-voltage emergency threshold");
     243              : 
     244            0 :    config.add("limits.currWarn", "", "limits.currWarn", argType::Required, "limits", "currWarn", false, "int", "The high-current warning threshold");
     245            0 :    config.add("limits.currAlert", "", "limits.currAlert", argType::Required, "limits", "currAlert", false, "int", "The high-current alert threshold");
     246            0 :    config.add("limits.currEmerg", "", "limits.currEmerg", argType::Required, "limits", "currEmerg", false, "int", "The high-current emergency threshold");
     247              : 
     248            0 :    dev::outletController<trippLitePDU>::setupConfig(config);
     249              : 
     250            0 : }
     251              : 
     252              : 
     253            0 : void trippLitePDU::loadConfig()
     254              : {
     255            0 :    config(m_deviceAddr, "device.address");
     256            0 :    config(m_devicePort, "device.port");
     257            0 :    config(m_deviceUsername, "device.username");
     258            0 :    config(m_devicePassFile, "device.passfile");
     259            0 :    config(m_deviceVersion, "device.powerAlertVersion");
     260              : 
     261            0 :    dev::ioDevice::loadConfig(config);
     262              : 
     263            0 :    config(m_freqLowWarn, "limits.freqLowWarn");
     264            0 :    config(m_freqHighWarn, "limits.freqHighWarn");
     265            0 :    config(m_freqLowAlert, "limits.freqLowAlert");
     266            0 :    config(m_freqHighAlert, "limits.freqHighAlert");
     267            0 :    config(m_freqLowEmerg, "limits.freqLowEmerg");
     268            0 :    config(m_freqHighEmerg, "limits.freqHighEmerg");
     269              : 
     270            0 :    config(m_voltLowWarn, "limits.voltLowWarn");
     271            0 :    config(m_voltHighWarn, "limits.voltHighWarn");
     272            0 :    config(m_voltLowAlert, "limits.voltLowAlert");
     273            0 :    config(m_voltHighAlert, "limits.voltHighAlert");
     274            0 :    config(m_voltLowEmerg, "limits.voltLowEmerg");
     275            0 :    config(m_voltHighEmerg, "limits.voltHighEmerg");
     276              : 
     277            0 :    config(m_currWarn, "limits.currWarn");
     278            0 :    config(m_currAlert, "limits.currAlert");
     279            0 :    config(m_currEmerg, "limits.currEmerg");
     280              : 
     281            0 :    dev::outletController<trippLitePDU>::loadConfig(config);
     282              : 
     283              : 
     284            0 : }
     285              : 
     286            0 : int trippLitePDU::appStartup()
     287              : {
     288              :     #ifdef XWC_SIM_MODE
     289            0 :     log<text_log>("XWC_SIM_MODE active");
     290              :     #endif
     291              : 
     292              :     // set up the  INDI properties
     293            0 :     REG_INDI_NEWPROP_NOCB(m_indiP_status, "status", pcf::IndiProperty::Text);
     294            0 :     m_indiP_status.add (pcf::IndiElement("value"));
     295              : 
     296            0 :     REG_INDI_NEWPROP_NOCB(m_indiP_load, "load", pcf::IndiProperty::Number);
     297            0 :     m_indiP_load.add (pcf::IndiElement("frequency"));
     298            0 :     m_indiP_load.add (pcf::IndiElement("voltage"));
     299            0 :     m_indiP_load.add (pcf::IndiElement("current"));
     300              : 
     301            0 :     if(dev::outletController<trippLitePDU>::setupINDI() < 0)
     302              :     {
     303            0 :         return log<text_log,-1>("Error setting up INDI for outlet control.", logPrio::LOG_CRITICAL);
     304              :     }
     305              : 
     306            0 :     state(stateCodes::NOTCONNECTED);
     307              : 
     308            0 :     return 0;
     309              : }
     310              : 
     311            0 : int trippLitePDU::appLogic()
     312              : {
     313            0 :     if( state() == stateCodes::NOTCONNECTED )
     314              :     {
     315              :         static int lastrv = 0; //Used to handle a change in error within the same state.  Make general?
     316              :         static int lasterrno = 0;
     317              : 
     318            0 :         int rv = devConnect();
     319              : 
     320            0 :         if(rv == 0)
     321              :         {
     322            0 :             state(stateCodes::CONNECTED);
     323              : 
     324            0 :             if(!stateLogged())
     325              :             {
     326            0 :                 std::string logs = "Connected to " + m_deviceAddr + ":" + m_devicePort;
     327            0 :                 log<text_log>(logs);
     328            0 :             }
     329            0 :             lastrv = rv;
     330            0 :             lasterrno = errno;
     331              :         }
     332              :         else
     333              :         {
     334            0 :             if(!stateLogged())
     335              :             {
     336            0 :                log<text_log>({"Failed to connect to " + m_deviceAddr + ":" + m_devicePort}, logPrio::LOG_ERROR);
     337              :             }
     338            0 :             if( rv != lastrv )
     339              :             {
     340            0 :                log<software_error>( {__FILE__,__LINE__, 0, rv,  tty::ttyErrorString(rv)} );
     341            0 :                lastrv = rv;
     342              :             }
     343            0 :             if( errno != lasterrno )
     344              :             {
     345            0 :                log<software_error>( {__FILE__,__LINE__, errno});
     346            0 :                lasterrno = errno;
     347              :             }
     348            0 :             return 0;
     349              :         }
     350              :     }
     351              : 
     352            0 :     if( state() == stateCodes::CONNECTED )
     353              :     {
     354            0 :         int rv = devLogin();
     355              : 
     356            0 :         if(rv == 0)
     357              :         {
     358            0 :             state(stateCodes::LOGGEDIN);
     359              :         }
     360              :         else
     361              :         {
     362            0 :            if(rv == TELNET_E_LOGINTIMEOUT)
     363              :            {
     364            0 :                 state(stateCodes::NOTCONNECTED);
     365            0 :                 log<text_log>("login timedout", logPrio::LOG_ERROR);
     366            0 :                 return 0;
     367              :            }
     368              : 
     369            0 :            state(stateCodes::FAILURE);
     370            0 :            log<text_log>("login failure", logPrio::LOG_CRITICAL);
     371            0 :            return -1;
     372              :         }
     373              :     }
     374              : 
     375            0 :     if(state() == stateCodes::LOGGEDIN)
     376              :     {
     377            0 :         devPostLogin();
     378              : 
     379            0 :         state(stateCodes::READY);
     380              :     }
     381              : 
     382            0 :     if(state() == stateCodes::READY)
     383              :     {
     384            0 :        std::unique_lock<std::mutex> lock(m_indiMutex, std::try_to_lock);
     385              : 
     386            0 :        if( !lock.owns_lock())
     387              :        {
     388            0 :           return 0;
     389              :        }
     390              : 
     391            0 :        int rv = updateOutletStates();
     392              : 
     393            0 :        if(rv < 0) return log<software_error,-1>({__FILE__, __LINE__});
     394              : 
     395            0 :        updateAlarmsAndWarnings();
     396              : 
     397            0 :        return 0;
     398            0 :     }
     399              : 
     400            0 :     state(stateCodes::FAILURE);
     401            0 :     log<text_log>("appLogic fell through", logPrio::LOG_CRITICAL);
     402            0 :     return -1;
     403              : 
     404              : }
     405              : 
     406            0 : int trippLitePDU::appShutdown()
     407              : {
     408              :    //don't bother
     409            0 :    return 0;
     410              : }
     411              : 
     412            0 : int trippLitePDU::updateOutletState( int outletNum )
     413              : {
     414              :    static_cast<void>(outletNum);
     415              : 
     416            0 :    return updateOutletStates(); //We can't do just one.
     417              : }
     418              : 
     419              : 
     420            0 : int trippLitePDU::updateOutletStates()
     421              : {
     422              :     int rv;
     423            0 :     std::string strRead;
     424              : 
     425            0 :     rv = devStatus(strRead);
     426              : 
     427            0 :     if(rv < 0 )
     428              :     {
     429            0 :         log<software_error>({__FILE__, __LINE__, "error getting device status"});
     430            0 :         state(stateCodes::NOTCONNECTED);
     431            0 :         return 0;
     432              :     }
     433              : 
     434            0 :     if(rv > 0)
     435              :     {
     436            0 :         return 0; //this means the re-read was successful, but we don't want to parse this time.
     437              :     }
     438              : 
     439            0 :     rv = parsePDUStatus( strRead);
     440              : 
     441            0 :     if(rv == 0)
     442              :     {
     443            0 :         updateIfChanged(m_indiP_status, "value", m_status);
     444              : 
     445            0 :         updateIfChanged(m_indiP_load, "frequency", m_frequency);
     446              : 
     447            0 :         updateIfChanged(m_indiP_load, "voltage", m_voltage);
     448              : 
     449            0 :         updateIfChanged(m_indiP_load, "current", m_current);
     450              : 
     451            0 :         dev::outletController<trippLitePDU>::updateINDI();
     452              :     }
     453              :     else
     454              :     {
     455            0 :         log<software_error>({__FILE__, __LINE__, 0, rv, "parse error"});
     456              :     }
     457              : 
     458            0 :     return 0;
     459            0 : }
     460              : 
     461            0 : int trippLitePDU::turnOutletOn( int outletNum )
     462              : {
     463            0 :     std::lock_guard<std::mutex> guard(m_indiMutex);  //Lock the mutex before doing anything
     464              : 
     465              :     #ifndef XWC_SIM_MODE
     466              :     std::string cmd = "loadctl on -o ";
     467              :     cmd += mx::ioutils::convertToString<int>(outletNum+1); //Internally 0 counted, device starts at 1.
     468              :     cmd += " --force\r";
     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) return log<software_error, -1>({__FILE__, __LINE__, 0, rv, "telnet error"});
     479              : 
     480            0 :     return 0;
     481            0 : }
     482              : 
     483            0 : int trippLitePDU::turnOutletOff( int outletNum )
     484              : {
     485            0 :     std::lock_guard<std::mutex> guard(m_indiMutex);  //Lock the mutex before doing anything
     486              : 
     487              :     #ifndef XWC_SIM_MODE
     488              :     std::string cmd = "loadctl off -o ";
     489              :     cmd += mx::ioutils::convertToString<int>(outletNum+1); //Internally 0 counted, device starts at 1.
     490              :     cmd += " --force\r";
     491              : 
     492              :     int rv = m_telnetConn.writeRead( cmd, true, m_writeTimeout, m_readTimeout);
     493              : 
     494              :     #else
     495              : 
     496            0 :     int rv = m_simulator.turnOutletOff(outletNum);
     497              : 
     498              :     #endif
     499              : 
     500            0 :     if(rv < 0) return log<software_error, -1>({__FILE__, __LINE__, 0, rv, "telnet error"});
     501              : 
     502            0 :    return 0;
     503            0 : }
     504              : 
     505            0 : int trippLitePDU::devConnect()
     506              : {
     507              :     #ifndef XWC_SIM_MODE
     508              : 
     509              :     return m_telnetConn.connect(m_deviceAddr, m_devicePort);
     510              : 
     511              :     #else
     512              : 
     513            0 :     return m_simulator.connect(m_deviceAddr, m_devicePort);
     514              : 
     515              :     #endif
     516              : }
     517              : 
     518            0 : int trippLitePDU::devLogin()
     519              : {
     520              :     #ifndef XWC_SIM_MODE
     521              : 
     522              :     //Newer version of power alert changed login (at least the first one)
     523              :     if(m_deviceVersion > 0)
     524              :     {
     525              :         m_telnetConn.m_usernamePrompt = "login:";
     526              :         m_telnetConn.m_prompt = ">>";
     527              :     }
     528              : 
     529              :     return m_telnetConn.login("localadmin", "localadmin");
     530              : 
     531              :     #else
     532              : 
     533            0 :     return m_simulator.login("localadmin", "localadmin");
     534              : 
     535              :     #endif
     536              : }
     537              : 
     538            0 : void trippLitePDU::devPostLogin()
     539              : {
     540              : 
     541              :     #ifndef XWC_SIM_MODE
     542              : 
     543              :     //For newer version of power alert we need to select C.L.I.
     544              :     if(m_deviceVersion > 0)
     545              :     {
     546              :         m_telnetConn.writeRead("E\n", false, m_writeTimeout, m_readTimeout);
     547              :         m_telnetConn.m_prompt = "$> ";
     548              :     }
     549              : 
     550              :     #else
     551              : 
     552            0 :     m_simulator.postLogin();
     553              : 
     554              :     #endif
     555            0 : }
     556              : 
     557            0 : int trippLitePDU::devStatus(std::string & strRead)
     558              : {
     559              :     #ifndef XWC_SIM_MODE
     560              : 
     561              :     int rv = m_telnetConn.writeRead("devstatus\n", true, m_writeTimeout, m_readTimeout);
     562              : 
     563              :     strRead = m_telnetConn.m_strRead;
     564              : 
     565              :     if(rv == TTY_E_TIMEOUTONREAD || rv == TTY_E_TIMEOUTONREADPOLL)
     566              :     {
     567              :         rv = m_telnetConn.read(m_readTimeout, false);
     568              : 
     569              :         if( rv < 0 )
     570              :         {
     571              :             log<software_error>({__FILE__, __LINE__, 0, rv, "devstatus timeout, timed out on re-read: " + tty::ttyErrorString(rv)});
     572              :             return -1;
     573              :         }
     574              : 
     575              :         log<text_log>("devstatus timeout, re-read successful");
     576              : 
     577              :         return 1;
     578              :     }
     579              :     else if(rv < 0 )
     580              :     {
     581              :         log<software_error>({__FILE__, __LINE__, 0, rv, tty::ttyErrorString(rv)});
     582              :         return -1;
     583              :     }
     584              : 
     585              :     return 0;
     586              : 
     587              :     #else
     588              : 
     589            0 :     return m_simulator.devStatus(strRead);
     590              : 
     591              :     #endif
     592              : }
     593              : 
     594            0 : int trippLitePDU::parsePDUStatus( std::string & strRead )
     595              : {
     596            0 :     size_t curpos = 0;
     597              : 
     598            0 :     curpos = strRead.find_first_of("\r\n", curpos);
     599              : 
     600            0 :     std::string sstr;
     601              : 
     602            0 :     while(curpos < strRead.size())
     603              :     {
     604            0 :         size_t eol = strRead.find_first_of("\r\n", curpos);
     605              : 
     606            0 :         if(eol == std::string::npos) eol = strRead.size();
     607              : 
     608            0 :         if(eol == curpos)
     609              :         {
     610            0 :             curpos = eol + 1;
     611            0 :             continue;
     612              :         }
     613              : 
     614            0 :         sstr = strRead.substr(curpos, eol-curpos);
     615            0 :         curpos = eol + 1;
     616              : 
     617            0 :         if(sstr[0] == '-' || sstr[0] == '0' || sstr[0] == 'L' || sstr[0] == ' ' || sstr[0] == 'D' || sstr[0] == '$') continue;
     618              : 
     619            0 :         if(sstr[0] == 'I')
     620              :         {
     621            0 :             if(sstr[6] == 'V')
     622              :             {
     623            0 :                 size_t begin = sstr.find(' ',6);
     624            0 :                 if(begin == std::string::npos)
     625              :                 {
     626            0 :                     return -1;
     627              :                 }
     628              : 
     629            0 :                 begin = sstr.find_first_not_of(' ', begin);
     630            0 :                 if(begin == std::string::npos)
     631              :                 {
     632            0 :                     return -2;
     633              :                 }
     634              : 
     635            0 :                 size_t end = sstr.find('V', begin);
     636            0 :                 if(end == std::string::npos)
     637              :                 {
     638            0 :                     return -3;
     639              :                 }
     640              : 
     641            0 :                 float V = mx::ioutils::convertFromString<float>( sstr.substr(begin, end-begin) );
     642              : 
     643            0 :                 m_voltage = V;
     644              :             }
     645              : 
     646            0 :             else if(sstr[6] == 'F')
     647              :             {
     648            0 :                 size_t begin = sstr.find(' ',6);
     649            0 :                 if(begin == std::string::npos)
     650              :                 {
     651            0 :                     return -4;
     652              :                 }
     653              : 
     654            0 :                 begin = sstr.find_first_not_of(' ', begin);
     655            0 :                 if(begin == std::string::npos)
     656              :                 {
     657            0 :                     return -5;
     658              :                 }
     659              : 
     660            0 :                 size_t end = sstr.find('H', begin);
     661            0 :                 if(end == std::string::npos)
     662              :                 {
     663            0 :                     return -6;
     664              :                 }
     665              : 
     666            0 :                 float F = mx::ioutils::convertFromString<float>( sstr.substr(begin, end-begin) );
     667              : 
     668            0 :                 m_frequency = F;
     669              :             }
     670            0 :             else return -1;
     671              :         }
     672            0 :         else if(sstr[0] == 'O')
     673              :         {
     674            0 :             if(sstr[7] == 'C')
     675              :             {
     676            0 :                 size_t begin = sstr.find(' ',7);
     677            0 :                 if(begin == std::string::npos)
     678              :                 {
     679            0 :                     return -7;
     680              :                 }
     681              : 
     682            0 :                 begin = sstr.find_first_not_of(' ', begin);
     683            0 :                 if(begin == std::string::npos)
     684              :                 {
     685            0 :                     return -8;
     686              :                 }
     687              : 
     688            0 :                 size_t end = sstr.find('A', begin);
     689            0 :                 if(end == std::string::npos)
     690              :                 {
     691            0 :                     return -9;
     692              :                 }
     693              : 
     694            0 :                 float C = mx::ioutils::convertFromString<float>( sstr.substr(begin, end-begin) );
     695              : 
     696            0 :                 m_current = C;
     697              :             }
     698            0 :             else if(sstr[8] == 'O')
     699              :             {
     700            0 :                 std::vector<int> outletStates(m_outletStates.size(),OUTLET_STATE_OFF);
     701              : 
     702            0 :                 size_t begin = sstr.find(' ',8);
     703            0 :                 if(begin == std::string::npos)
     704              :                 {
     705            0 :                     return -10;
     706              :                 }
     707              : 
     708            0 :                 begin = sstr.find_first_not_of(' ', begin);
     709              : 
     710            0 :                 if(begin == std::string::npos)
     711              :                 {
     712            0 :                     return -11;
     713              :                 }
     714              : 
     715            0 :                 while(begin < sstr.size())
     716              :                 {
     717            0 :                     size_t end = sstr.find(' ', begin);
     718            0 :                     if(end == std::string::npos)
     719              :                     {
     720            0 :                         end = sstr.size();
     721              :                     }
     722              : 
     723            0 :                     int onum = atoi(sstr.substr(begin, end-begin).c_str());
     724              : 
     725            0 :                     if(onum > 0 && onum < 9)
     726              :                     {
     727            0 :                         outletStates[onum-1] = OUTLET_STATE_ON; //this outlet is on.
     728              :                     }
     729            0 :                     begin = sstr.find_first_not_of(' ', end+1);
     730              :                 }
     731              : 
     732            0 :                 for(size_t i=0;i<m_outletStates.size();++i)
     733              :                 {
     734            0 :                     m_outletStates[i]=outletStates[i];
     735              :                 }
     736            0 :             }
     737            0 :             else if( sstr[7] == 'V' || sstr[7] == 'F')
     738              :             {
     739            0 :                 continue;
     740              :             }
     741              :             else
     742              :             {
     743            0 :                 return -12;
     744              :             }
     745              :         }
     746              :         else
     747              :         {
     748            0 :             return -13;
     749              :         }
     750              :     }
     751              : 
     752            0 :     return 0;
     753            0 : }
     754              : 
     755            0 : void trippLitePDU::updateAlarmsAndWarnings()
     756              : {
     757            0 :     if (m_frequency <= m_freqLowEmerg)
     758              :     {
     759            0 :         log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, below " +
     760            0 :                               std::to_string(m_freqLowEmerg) + " Hz.",  logPrio::LOG_EMERGENCY);
     761              :     }
     762            0 :     else if (m_frequency >= m_freqHighEmerg)
     763              :     {
     764            0 :         log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, above " +
     765            0 :                              std::to_string(m_freqHighEmerg) + " Hz.",  logPrio::LOG_EMERGENCY);
     766              :     }
     767            0 :     else if (m_frequency <= m_freqLowAlert)
     768              :     {
     769            0 :         log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, below " +
     770            0 :                                   std::to_string(m_freqLowAlert) + " Hz.",  logPrio::LOG_ALERT);
     771              :     }
     772            0 :     else if (m_frequency >= m_freqHighAlert)
     773              :     {
     774            0 :         log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, above " +
     775            0 :                                   std::to_string(m_freqHighAlert) + " Hz.",  logPrio::LOG_ALERT);
     776              :     }
     777            0 :     else if(m_frequency <= m_freqLowWarn)
     778              :     {
     779            0 :         log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, below " +
     780            0 :                                     std::to_string(m_freqLowWarn) + " Hz.",  logPrio::LOG_WARNING);
     781              :     }
     782            0 :     else if (m_frequency >= m_freqHighWarn)
     783              :     {
     784            0 :         log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, above " +
     785            0 :                                             std::to_string(m_freqHighWarn) + " Hz.",  logPrio::LOG_WARNING);
     786              :     }
     787              : 
     788            0 :     if (m_voltage <= m_voltLowEmerg)
     789              :     {
     790            0 :         log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, below " +
     791            0 :                                             std::to_string(m_voltLowEmerg) + " V.",  logPrio::LOG_EMERGENCY);
     792              :     }
     793            0 :     else if (m_voltage >= m_voltHighEmerg)
     794              :     {
     795            0 :         log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, above " +
     796            0 :                                             std::to_string(m_voltHighEmerg) + " V.",  logPrio::LOG_EMERGENCY);
     797              :     }
     798            0 :     else if (m_voltage <= m_voltLowAlert)
     799              :     {
     800            0 :         log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, below " +
     801            0 :                                             std::to_string(m_voltLowAlert) + " V.",  logPrio::LOG_ALERT);
     802              :     }
     803            0 :     else if (m_voltage >= m_voltHighAlert)
     804              :     {
     805            0 :         log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, above " +
     806            0 :                                                         std::to_string(m_voltHighAlert) + " V.",  logPrio::LOG_ALERT);
     807              :     }
     808            0 :     else if(m_voltage <= m_voltLowWarn)
     809              :     {
     810            0 :         log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, below " +
     811            0 :                                                 std::to_string(m_voltLowWarn) + " V.",  logPrio::LOG_WARNING);
     812              :     }
     813            0 :     else if (m_voltage >= m_voltHighWarn)
     814              :     {
     815            0 :         log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, above " +
     816            0 :                                                 std::to_string(m_voltHighWarn) + " V.",  logPrio::LOG_WARNING);
     817              :     }
     818              : 
     819            0 :     if (m_current >= m_currEmerg)
     820              :     {
     821            0 :         log<text_log>("Current is " + std::to_string(m_current) + " A, above " +
     822            0 :                                                     std::to_string(m_currEmerg) + " A.",  logPrio::LOG_EMERGENCY);
     823              :     }
     824            0 :     else if (m_current >= m_currAlert)
     825              :     {
     826            0 :         log<text_log>("Current is " + std::to_string(m_current) + " A, above " +
     827            0 :                                                         std::to_string(m_currAlert) + " A.",  logPrio::LOG_ALERT);
     828              :     }
     829            0 :     else if (m_current >= m_currWarn)
     830              :     {
     831            0 :         log<text_log>("Current is " + std::to_string(m_current) + " A, above " +
     832            0 :                                                             std::to_string(m_currWarn) + " A.",  logPrio::LOG_WARNING);
     833              :     }
     834            0 : }
     835              : 
     836              : } //namespace app
     837              : } //namespace MagAOX
     838              : 
     839              : #endif //trippLitePDU_hpp
        

Generated by: LCOV version 2.0-1