LCOV - code coverage report
Current view: top level - apps/siglentSDG - siglentSDG.hpp (source / functions) Coverage Total Hit
Test: MagAOX Lines: 4.0 % 953 38
Test Date: 2026-01-03 21:03:39 Functions: 28.1 % 64 18

            Line data    Source code
       1              : 
       2              : 
       3              : #ifndef siglentSDG_hpp
       4              : #define siglentSDG_hpp
       5              : 
       6              : 
       7              : #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
       8              : #include "../../magaox_git_version.h"
       9              : 
      10              : #include "siglentSDG_parsers.hpp"
      11              : 
      12              : namespace MagAOX
      13              : {
      14              : namespace app
      15              : {
      16              : 
      17              : /** MagAO-X application to control a Siglent SDG series function generator
      18              :   *
      19              :   * \todo need to recognize signals in tty polls and not return errors, etc.
      20              :   * \todo need to implement an onDisconnect() to update values to unknown indicators.
      21              :   * \todo need a frequency-dependent max amp facility.
      22              :   * \todo convert to ioDevice
      23              :   * \todo need telnet device, with optional username/password.
      24              :   *
      25              :   */
      26              : class siglentSDG : public MagAOXApp<>, public dev::telemeter<siglentSDG>
      27              : {
      28              : 
      29              :     friend class siglentSDG_test;
      30              : 
      31              :    friend class dev::telemeter<siglentSDG>;
      32              : 
      33              :    //constexpr static double cs_MaxAmp = 0.87;//2.1;//0.87;
      34              :    constexpr static double cs_MaxOfst = 10.0;
      35              :    constexpr static double cs_MaxVolts = 10.0;
      36              :    //constexpr static double cs_MaxFreq = 3622.0;//101;//3622.0;
      37              : 
      38              : private:
      39              :    std::vector<double> m_ampMax = {1.2801,   1.2801,  1.0201};//0.71,  0.83, 0.88, 1.05, 1.15, 3.45}; //1.5,     1.2,     1.1     };
      40              :    std::vector<double> m_maxFreq = {0.0,   2000,      3000};//100.0,   150,  200,  250,  300, 1000}; //2999.99, 3499.99, 3500.01};
      41              :    //todo: do we need to add max and min pulse variables?
      42              : protected:
      43              : 
      44              :    /** \name Configurable Parameters
      45              :      * @{
      46              :      */
      47              : 
      48              :    std::string m_deviceAddr; ///< The device address
      49              :    std::string m_devicePort; ///< The device port
      50              : 
      51              :    double m_bootDelay {10}; ///< Time in seconds it takes the device to boot.
      52              : 
      53              :    int m_writeTimeOut {10000};  ///< The timeout for writing to the device [msec].
      54              :    int m_readTimeOut {10000}; ///< The timeout for reading from the device [msec].
      55              : 
      56              :    double m_C1setVoltage {5.0}; ///< the set position voltage of Ch. 1.
      57              :    double m_C2setVoltage {5.0}; ///< the set position voltage of Ch. 2.
      58              : 
      59              :    bool m_C1outpOn {false}; /**< Flag controlling if C1 output is on after normalization. */
      60              :    bool m_C2outpOn {false}; /**< Flag controlling if C2 output is on after normalization.
      61              :                                  This will only have an effect if m_C1wvtp is "pulse" */
      62              : 
      63              :    ///@}
      64              : 
      65              :    tty::telnetConn m_telnetConn; ///< The telnet connection manager
      66              : 
      67              :    std::string m_waveform; ///< The chosen funciton to generate
      68              :    /// std::string m_clock; ///<INTernal or EXTernal
      69              : 
      70              :    uint8_t m_C1outp {0}; ///< The output status channel 1
      71              :    double m_C1frequency {0}; ///< The output frequency of channel 1
      72              :    double m_C1vpp {0}; ///< The peak-2-peak voltage of channel 1
      73              :    double m_C1vppDefault {0}; ///< default value for vpp of channel 1
      74              :    double m_C1ofst {0}; ///< The offset voltage of channel 1
      75              :    double m_C1phse {0}; ///< The phase of channel 1 (SINE only)
      76              :    double m_C1wdth {0}; ///< The width of channel 1 (PULSE only)
      77              :    std::string m_C1wvtp; ///< The wave type of channel 1
      78              :    double m_C1ampMax {10.0}; ///< The maximum voltage output for channel 1
      79              : 
      80              :    uint8_t m_C2outp {0}; ///<  The output status channel 2
      81              :    double m_C2frequency {0}; ///< The output frequency of channel 2
      82              :    double m_C2vpp {0}; ///< The peak-2-peak voltage of channel 2
      83              :    double m_C2vppDefault {0}; ///< default value for vpp of channel 2
      84              :    double m_C2ofst {0}; ///< The offset voltage of channel 2
      85              :    double m_C2phse {0}; ///< The phase of channel 2 (SINE only)
      86              :    double m_C2wdth {0}; ///< The width of channel 2 (PULSE only)
      87              :    std::string m_C2wvtp; ///< The wave type of channel 2
      88              :    double m_C2ampMax {10.0}; ///< The maximum voltage output for channel 2
      89              : 
      90              :    double m_C1frequency_tgt {-1};
      91              :    double m_C1vpp_tgt {-1};
      92              : 
      93              :    double m_C2frequency_tgt {-1};
      94              :    double m_C2vpp_tgt {-1};
      95              : 
      96              :    bool m_C1sync {false};
      97              :    bool m_C2sync {false};
      98              : 
      99              : private:
     100              : 
     101              :    bool m_poweredOn {false};
     102              : 
     103              :    double m_powerOnCounter {0}; ///< Counts the number of loops since power-on, used to control logging of connect failures.
     104              : 
     105              : public:
     106              : 
     107              :    /// Default c'tor.
     108              :    siglentSDG();
     109              : 
     110              :    /// D'tor, declared and defined for noexcept.
     111           48 :    ~siglentSDG() noexcept
     112           48 :    {}
     113              : 
     114              :    /// Setup the configuration system (called by MagAOXApp::setup())
     115              :    virtual void setupConfig();
     116              : 
     117              :    /// load the configuration system results (called by MagAOXApp::setup())
     118              :    virtual void loadConfig();
     119              : 
     120              :    /// Startup functions
     121              :    /** Setsup the INDI vars.
     122              :      *
     123              :      */
     124              :    virtual int appStartup();
     125              : 
     126              :    /// Implementation of the FSM for the Siglent SDG
     127              :    virtual int appLogic();
     128              : 
     129              :    /// Implementation of the on-power-off FSM logic
     130              :    virtual int onPowerOff();
     131              : 
     132              :    /// Implementation of the while-powered-off FSM
     133              :    virtual int whilePowerOff();
     134              : 
     135              :    /// Do any needed shutdown tasks.  Currently nothing in this app.
     136              :    virtual int appShutdown();
     137              : 
     138              :    /// Write a command to the device and get the response.  Not mutex-ed.
     139              :    /** We assume this is called after the m_indiMutex is locked.
     140              :      *
     141              :      * \returns 0 on success
     142              :      * \returns -1 on an error.  May set DISCONNECTED.
     143              :      */
     144              :    int writeRead( std::string & strRead,  ///< [out] The string responseread in
     145              :                   const std::string & command ///< [in] The command to send.
     146              :                 );
     147              : 
     148              :     /// Write a command to the device.
     149              :    /**
     150              :      * \returns 0 on success
     151              :      * \returns -1 on error
     152              :      */
     153              :    int writeCommand( const std::string & commmand /**< [in] the complete command string to send to the device */);
     154              : 
     155              :    /// Send the MDWV? query and get the response state.
     156              :    /** This does not update internal state.
     157              :      *
     158              :      * \returns 0 on success
     159              :      * \returns -1 on an error.
     160              :      */
     161              :    int queryMDWV( std::string & state, ///< [out] the MDWV state, ON or OFF
     162              :                   int channel ///< [in] the channel to query
     163              :                 );
     164              : 
     165              :    /// Send the SWWV? query and get the response state.
     166              :    /** This does not update internal state.
     167              :      *
     168              :      * \returns 0 on success
     169              :      * \returns -1 on an error.
     170              :      */
     171              :    int querySWWV( std::string & state, ///< [out] the SWWV state, ON or OFF
     172              :                   int channel ///< [in] the channel to query
     173              :                 );
     174              : 
     175              :    /// Send the BTWV? query and get the response state.
     176              :    /** This does not update internal state.
     177              :      *
     178              :      * \returns 0 on success
     179              :      * \returns -1 on an error.
     180              :      */
     181              :    int queryBTWV( std::string & state,  ///< [out] the BTWV state, ON or OFF
     182              :                   int channel ///< [in] the channel to query
     183              :                 );
     184              : 
     185              :    /// Send the ARWV? query and get the response index.
     186              :    /** This does not update internal state.
     187              :      *
     188              :      * \returns 0 on success
     189              :      * \returns -1 on an error.
     190              :      */
     191              :    int queryARWV( int & index,  ///< [out] the ARWV index
     192              :                   int channel ///< [in] the channel to query
     193              :                 );
     194              : 
     195              :    /// Send the BSWV? query for a channel.
     196              :    /** This updates member variables and INDI.
     197              :      *
     198              :      * \returns 0 on success
     199              :      * \returns -1 on an error.
     200              :      */
     201              :    int queryBSWV( int channel  /** < [in] the channel to query */ );
     202              : 
     203              :    /// Send the SYNC? query for a channel.
     204              :    /** This updates member variables and INDI.
     205              :      *
     206              :      * \returns 0 on success
     207              :      * \returns -1 on an error.
     208              :      */
     209              :    int querySYNC( bool & sync, /// < [in] the sync state for this channel
     210              :                   int channel  /// < [in] the channel to query
     211              :                 );
     212              : 
     213              :    /// Check the setup is correct and safe for PI TTM control.
     214              :    /**
     215              :      * \returns 0 if the fxn gen is setup for safe operation
     216              :      * \returns 1 if a non-normal setup is detected.
     217              :      * \returns -1 on an error, e.g. comms or parsing.
     218              :      */
     219              :    int checkSetup();
     220              : 
     221              :    /// Normalize the setup, called during connection if checkSetup shows a problem, or on power-up.
     222              :    int normalizeSetup();
     223              : 
     224              :    /// Send the OUTP? query for a channel.
     225              :    /**
     226              :      * \returns 0 on success
     227              :      * \returns -1 on an error.
     228              :      */
     229              :    int queryOUTP( int channel /**< [in] the channel to query */);
     230              : 
     231              :    /// Change the output status (on/off) of one channel.
     232              :    /**
     233              :      * \returns 0 on success
     234              :      * \returns -1 on error.
     235              :      */
     236              :    int changeOutp( int channel,                ///< [in] the channel to send the command to.
     237              :                    const std::string & newOutp ///< [in] The requested output state [On/Off]
     238              :                  );
     239              : 
     240              :    /// Change the output status (on/off) of one channel in response to an INDI property. This locks the mutex.
     241              :    /**
     242              :      * \returns 0 on success
     243              :      * \returns -1 on error.
     244              :      */
     245              :    int changeOutp( int channel,                    ///< [in] the channel to send the command to.
     246              :                    const pcf::IndiProperty &ipRecv ///< [in] INDI property containing the requested output state [On/Off]
     247              :                  );
     248              : 
     249              :    /// Send a change frequency command to the device.
     250              :    /**
     251              :      * \returns 0 on success
     252              :      * \returns -1 on error
     253              :      */
     254              :    int changeFreq( int channel,   ///< [in] the channel to send the command to.
     255              :                    double newFreq ///< [in] The requested new frequency [Hz]
     256              :                  );
     257              : 
     258              :    /// Send a change frequency command to the device in response to an INDI property.  This locks the mutex.
     259              :    /**
     260              :      * \returns 0 on success
     261              :      * \returns -1 on error
     262              :      */
     263              :    int changeFreq( int channel,                    ///< [in] the channel to send the command to.
     264              :                    const pcf::IndiProperty &ipRecv ///< [in] INDI property containing the requested new frequency [Hz]
     265              :                  );
     266              : 
     267              :    /// Send a change amplitude command to the device.
     268              :    /**
     269              :      * \returns 0 on success
     270              :      * \returns -1 on error
     271              :      */
     272              :    int changeAmp( int channel,  ///< [in] the channel to send the command to.
     273              :                   double newAmp ///< [in] The requested new amplitude [V p2p]
     274              :                 );
     275              : 
     276              :    /// Send a change amplitude command to the device in response to an INDI property.
     277              :    /**
     278              :      * \returns 0 on success
     279              :      * \returns -1 on error
     280              :      */
     281              :    int changeAmp( int channel,                    ///< [in] the channel to send the command to.
     282              :                   const pcf::IndiProperty &ipRecv ///< [in] INDI property containing the requested new amplitude [V p2p]
     283              :                 );
     284              : 
     285              :    /// Send a change offset command to the device.
     286              :    /**
     287              :      * \returns 0 on success
     288              :      * \returns -1 on error
     289              :      */
     290              :    int changeOfst( int channel,  ///< [in] the channel to send the command to.
     291              :                   double newOfst ///< [in] The requested new offset [V p2p]
     292              :                 );
     293              : 
     294              :    /// Send a change offset command to the device in response to an INDI property.
     295              :    /**
     296              :      * \returns 0 on success
     297              :      * \returns -1 on error
     298              :      */
     299              :    int changeOfst( int channel,                    ///< [in] the channel to send the command to.
     300              :                    const pcf::IndiProperty &ipRecv ///< [in] INDI property containing the requested new offset [V p2p]
     301              :                  );
     302              : 
     303              :    /// Send a change phase command to the device.
     304              :    /**
     305              :      * \returns 0 on success
     306              :      * \returns -1 on error
     307              :      */
     308              :    int changePhse( int channel,  ///< [in] the channel to send the command to.
     309              :                    double newPhse ///< [in] The requested new phase [deg]
     310              :                  );
     311              : 
     312              :    /// Send a change phase command to the device in response to an INDI property.
     313              :    /**
     314              :      * \returns 0 on success
     315              :      * \returns -1 on error
     316              :      */
     317              :    int changePhse( int channel,                    ///< [in] the channel to send the command to.
     318              :                    const pcf::IndiProperty &ipRecv ///< [in] INDI property containing the requested new phase [deg]
     319              :                  );
     320              : 
     321              :    /// Send a width command to the device.
     322              :    /**
     323              :      * \returns 0 on success
     324              :      * \returns -1 on error
     325              :      */
     326              :    int changeWdth( int channel,  ///< [in] the channel to send the command to.
     327              :                    double newWdth ///< [in] The requested new width [s]
     328              :                  );
     329              : 
     330              :    /// Send a change phase command to the device in response to an INDI property.
     331              :    /**
     332              :      * \returns 0 on success
     333              :      * \returns -1 on error
     334              :      */
     335              :    int changeWdth( int channel,                    ///< [in] the channel to send the command to.
     336              :                    const pcf::IndiProperty &ipRecv ///< [in] INDI property containing the requested new width [s]
     337              :                  );
     338              : 
     339              : 
     340              :    /// Send a change wavetype command to the device.
     341              :    /**
     342              :      * \returns 0 on success
     343              :      * \returns -1 on error
     344              :      */
     345              :    int changeWvtp( int channel,  ///< [in] the channel to send the command to.
     346              :                    const std::string & newWvtp ///< [in] The requested new wavetype
     347              :                  );
     348              : 
     349              :    /// Send a change wavetype command to the device in response to an INDI property.
     350              :    /**
     351              :      * \returns 0 on success
     352              :      * \returns -1 on error
     353              :      */
     354              :    int changeWvtp( int channel,                    ///< [in] the channel to send the command to.
     355              :                    const pcf::IndiProperty &ipRecv ///< [in] INDI property containing the requested new wavetype
     356              :                  );
     357              : 
     358              :    /// Send a change sync command to the device.
     359              :    /**
     360              :      * \returns 0 on success
     361              :      * \returns -1 on error
     362              :      */
     363              :    int changeSync( int channel,  ///< [in] the channel to send the command to.
     364              :                    bool newSync ///< [in] The requested new sync state
     365              :                  );
     366              : 
     367              :    /// Send a change sync command to the device in response to an INDI property.
     368              :    /**
     369              :      * \returns 0 on success
     370              :      * \returns -1 on error
     371              :      */
     372              :    int changeSync( int channel,                    ///< [in] the channel to send the command to.
     373              :                    const pcf::IndiProperty &ipRecv ///< [in] INDI property containing the requested new sync state
     374              :                  );
     375              : 
     376              :    /** \name INDI
     377              :      * @{
     378              :      */
     379              : protected:
     380              : 
     381              :    //declare our properties
     382              :    pcf::IndiProperty m_indiP_status;
     383              : 
     384              :    pcf::IndiProperty m_indiP_C1outp;
     385              :    pcf::IndiProperty m_indiP_C1wvtp;
     386              :    pcf::IndiProperty m_indiP_C1freq;
     387              :    pcf::IndiProperty m_indiP_C1peri;
     388              :    pcf::IndiProperty m_indiP_C1amp;
     389              :    pcf::IndiProperty m_indiP_C1ampvrms;
     390              :    pcf::IndiProperty m_indiP_C1ofst;
     391              :    pcf::IndiProperty m_indiP_C1hlev;
     392              :    pcf::IndiProperty m_indiP_C1llev;
     393              :    pcf::IndiProperty m_indiP_C1phse;
     394              :    pcf::IndiProperty m_indiP_C1wdth;
     395              :    pcf::IndiProperty m_indiP_C1sync;
     396              : 
     397              :    pcf::IndiProperty m_indiP_C2outp;
     398              :    pcf::IndiProperty m_indiP_C2wvtp;
     399              :    pcf::IndiProperty m_indiP_C2freq;
     400              :    pcf::IndiProperty m_indiP_C2peri;
     401              :    pcf::IndiProperty m_indiP_C2amp;
     402              :    pcf::IndiProperty m_indiP_C2ampvrms;
     403              :    pcf::IndiProperty m_indiP_C2ofst;
     404              :    pcf::IndiProperty m_indiP_C2hlev;
     405              :    pcf::IndiProperty m_indiP_C2llev;
     406              :    pcf::IndiProperty m_indiP_C2phse;
     407              :    pcf::IndiProperty m_indiP_C2wdth;
     408              :    pcf::IndiProperty m_indiP_C2sync;
     409              : 
     410              : public:
     411            0 :    INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C1outp);
     412            0 :    INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C1freq);
     413            0 :    INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C1amp);
     414            0 :    INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C1ofst);
     415            0 :    INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C1phse);
     416            0 :    INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C1wdth);
     417            0 :    INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C1wvtp);
     418            0 :    INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C1sync);
     419              : 
     420            0 :    INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C2outp);
     421            0 :    INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C2freq);
     422            0 :    INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C2amp);
     423            0 :    INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C2ofst);
     424            0 :    INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C2phse);
     425            0 :    INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C2wdth);
     426            0 :    INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C2wvtp);
     427            0 :    INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C2sync);
     428              :    ///@}
     429              : 
     430              : 
     431              :    /** \name Telemeter Interface
     432              :      *
     433              :      * @{
     434              :      */
     435              : 
     436              :    int checkRecordTimes();
     437              : 
     438              :    int recordTelem( const telem_fxngen * );
     439              : 
     440              :    int recordParams(bool force = false);
     441              : 
     442              :    /// @}
     443              : 
     444              : };
     445              : 
     446              : inline
     447          336 : siglentSDG::siglentSDG() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
     448              : {
     449           48 :    m_powerMgtEnabled = true;
     450           48 :    m_telnetConn.m_prompt = "\n";
     451           48 :    return;
     452            0 : }
     453              : 
     454              : inline
     455            0 : void siglentSDG::setupConfig()
     456              : {
     457            0 :    config.add("device.address", "a", "device.address", argType::Required, "device", "address", false, "string", "The device address.");
     458            0 :    config.add("device.port", "p", "device.port", argType::Required, "device", "port", false, "string", "The device port.");
     459              : 
     460            0 :    config.add("timeouts.write", "", "timeouts.write", argType::Required, "timeouts", "write", false, "int", "The timeout for writing to the device [msec]. Default = 1000");
     461            0 :    config.add("timeouts.read", "", "timeouts.read", argType::Required, "timeouts", "read", false, "int", "The timeout for reading the device [msec]. Default = 2000");
     462              : 
     463            0 :    config.add("fxngen.waveform", "w", "fxngen.waveform", argType::Required, "fxngen", "waveform", false, "string", "The waveform to populate function.");
     464              : 
     465            0 :    config.add("fxngen.C1outpOn", "", "fxngen.C1outpOn", argType::Required, "fxngen", "C1outpOn", false, "bool", "Whether (true) or not (false) C1 output is enabled at startup. Only effective wavefrom is pulse. Default is false.");
     466            0 :    config.add("fxngen.C2outpOn", "", "fxngen.C2outpOn", argType::Required, "fxngen", "C2outpOn", false, "bool", "Whether (true) or not (false) C2 output is enabled at startup. Only effective wavefrom is pulse. Default is false.");
     467              : 
     468            0 :    config.add("fxngen.C1ampDefault", "", "fxngen.C1ampDefault", argType::Required, "fxngen", "C1ampDefault", false, "float", "C1 Default P2V Amplitude of waveform. Default = 0.0");
     469            0 :    config.add("fxngen.C2ampDefault", "", "fxngen.C2ampDefault", argType::Required, "fxngen", "C2ampDefault", false, "float", "C2 Default P2V Amplitude of waveform. Default = 0.0");
     470              : 
     471            0 :    config.add("fxngen.C1ofstDefault", "", "fxngen.C1ofstDefault", argType::Required, "fxngen", "C1ofstDefault", false, "float", "C1 Default Offset Amplitude of waveform. Default = 0.0");
     472            0 :    config.add("fxngen.C2ofstDefault", "", "fxngen.C2ofstDefault", argType::Required, "fxngen", "C2ofstDefault", false, "float", "C2 Default Offset Amplitude of waveform. Default = 0.0");
     473              : 
     474            0 :    config.add("fxngen.C1ampMax", "", "fxngen.C1ampMax", argType::Required, "fxngen", "C1ampMax", false, "float", "C1 Maximum amplitude");
     475            0 :    config.add("fxngen.C2ampMax", "", "fxngen.C2ampMax", argType::Required, "fxngen", "C2ampMax", false, "float", "C2 Maximum amplitude");
     476              : 
     477            0 :    dev::telemeter<siglentSDG>::setupConfig(config);
     478            0 : }
     479              : 
     480              : inline
     481            0 : void siglentSDG::loadConfig()
     482              : {
     483            0 :    config(m_deviceAddr, "device.address");
     484            0 :    config(m_devicePort, "device.port");
     485              : 
     486            0 :    config(m_writeTimeOut, "timeouts.write");
     487            0 :    config(m_readTimeOut, "timeouts.read");
     488              : 
     489            0 :    config(m_waveform, "fxngen.waveform"); // todo: check if this is a valid waveform?
     490            0 :    config(m_C1outpOn, "fxngen.C1outpOn");
     491            0 :    config(m_C2outpOn, "fxngen.C2outpOn");
     492              : 
     493            0 :    config(m_C1vppDefault, "fxngen.C1ampDefault");
     494            0 :    config(m_C2vppDefault, "fxngen.C2ampDefault");
     495              : 
     496            0 :    config(m_C1ofst, "fxngen.C1ofstDefault");
     497            0 :    config(m_C2ofst, "fxngen.C2ofstDefault");
     498              : 
     499            0 :    config(m_C1ampMax, "fxngen.C1ampMax");
     500            0 :    config(m_C2ampMax, "fxngen.C2ampMax");
     501              :    /// config(m_clock, "fxngen.clock");
     502              : 
     503            0 :    dev::telemeter<siglentSDG>::loadConfig(config);
     504            0 : }
     505              : 
     506              : inline
     507            0 : int siglentSDG::appStartup()
     508              : {
     509              :     // set up the  INDI properties
     510            0 :     REG_INDI_NEWPROP_NOCB(m_indiP_status, "status", pcf::IndiProperty::Text);
     511            0 :     m_indiP_status.add (pcf::IndiElement("value"));
     512            0 :     m_indiP_status["value"].set(0);
     513              : 
     514            0 :     REG_INDI_NEWPROP(m_indiP_C1outp, "C1outp", pcf::IndiProperty::Text);
     515            0 :     m_indiP_C1outp.add (pcf::IndiElement("value"));
     516            0 :     m_indiP_C1outp["value"].set("");
     517              : 
     518              :     //REG_INDI_NEWPROP(m_indiP_C1freq, "C1freq", pcf::IndiProperty::Number);
     519            0 :     CREATE_REG_INDI_NEW_NUMBERF( m_indiP_C1freq, "C1freq", -1e15, 1e15, 1, "%g", "C1freq", "C1freq");
     520              :     //m_indiP_C1freq.add (pcf::IndiElement("value"));
     521            0 :     m_indiP_C1freq["current"].set(0);
     522            0 :     m_indiP_C1freq["target"].set(0);
     523              : 
     524              :     //REG_INDI_NEWPROP(m_indiP_C1amp, "C1amp", pcf::IndiProperty::Number);
     525            0 :     CREATE_REG_INDI_NEW_NUMBERF( m_indiP_C1amp, "C1amp", -1e15, 1e15, 1, "%g", "C1amp", "C1amp");
     526              :     //m_indiP_C1amp.add (pcf::IndiElement("value"));
     527            0 :     m_indiP_C1amp["current"].set(0);
     528            0 :     m_indiP_C1amp["target"].set(0);
     529              : 
     530            0 :    REG_INDI_NEWPROP(m_indiP_C1ofst, "C1ofst", pcf::IndiProperty::Number);
     531            0 :    m_indiP_C1ofst.add (pcf::IndiElement("value"));
     532            0 :    m_indiP_C1ofst["value"].set(0);
     533              : 
     534            0 :    if(m_waveform == "SINE"){
     535            0 :       REG_INDI_NEWPROP(m_indiP_C1phse, "C1phse", pcf::IndiProperty::Number);
     536            0 :       m_indiP_C1phse.add (pcf::IndiElement("value"));
     537            0 :       m_indiP_C1phse["value"].set(0);
     538              :    }
     539              : 
     540            0 :    if(m_waveform == "PULSE"){
     541            0 :       REG_INDI_NEWPROP(m_indiP_C1wdth, "C1wdth", pcf::IndiProperty::Number);
     542            0 :       m_indiP_C1wdth.add (pcf::IndiElement("value"));
     543            0 :       m_indiP_C1wdth["value"].set(0);
     544              :    }
     545              : 
     546            0 :    REG_INDI_NEWPROP(m_indiP_C1wvtp, "C1wvtp", pcf::IndiProperty::Text);
     547            0 :    m_indiP_C1wvtp.add (pcf::IndiElement("value"));
     548            0 :    m_indiP_C1wvtp["value"].set("");
     549              : 
     550            0 :    REG_INDI_NEWPROP_NOCB(m_indiP_C1peri, "C1peri", pcf::IndiProperty::Number);
     551            0 :    m_indiP_C1peri.add (pcf::IndiElement("value"));
     552            0 :    m_indiP_C1peri["value"].set(0);
     553              : 
     554            0 :    REG_INDI_NEWPROP_NOCB(m_indiP_C1ampvrms, "C1ampvrms", pcf::IndiProperty::Number);
     555            0 :    m_indiP_C1ampvrms.add (pcf::IndiElement("value"));
     556            0 :    m_indiP_C1ampvrms["value"].set(0);
     557              : 
     558            0 :    REG_INDI_NEWPROP_NOCB(m_indiP_C1hlev, "C1hlev", pcf::IndiProperty::Number);
     559            0 :    m_indiP_C1hlev.add (pcf::IndiElement("value"));
     560            0 :    m_indiP_C1hlev["value"].set(0);
     561              : 
     562            0 :    REG_INDI_NEWPROP_NOCB(m_indiP_C1llev, "C1llev", pcf::IndiProperty::Number);
     563            0 :    m_indiP_C1llev.add (pcf::IndiElement("value"));
     564            0 :    m_indiP_C1llev["value"].set(0);
     565              : 
     566            0 :    createStandardIndiToggleSw( m_indiP_C1sync, "C1synchro", "C1 Sync Output", "C1 Sync Output");
     567            0 :    if(registerIndiPropertyNew( m_indiP_C1sync, st_newCallBack_m_indiP_C1sync) < 0)
     568              :    {
     569            0 :       log<software_error>({__FILE__,__LINE__});
     570            0 :       return -1;
     571              :    }
     572              : 
     573            0 :    REG_INDI_NEWPROP(m_indiP_C2outp, "C2outp", pcf::IndiProperty::Text);
     574            0 :    m_indiP_C2outp.add (pcf::IndiElement("value"));
     575            0 :    m_indiP_C2outp["value"].set("");
     576              : 
     577            0 :    CREATE_REG_INDI_NEW_NUMBERF( m_indiP_C2freq, "C2freq", -1e15, 1e15, 1, "%g", "C2freq", "C2freq");
     578            0 :    m_indiP_C2freq["current"].set(0);
     579            0 :    m_indiP_C2freq["target"].set(0);
     580              : 
     581            0 :    CREATE_REG_INDI_NEW_NUMBERF( m_indiP_C2amp, "C2amp", -1e15, 1e15, 1, "%g", "C2amp", "C2amp");
     582            0 :    m_indiP_C2amp["current"].set(0);
     583            0 :    m_indiP_C2amp["target"].set(0);
     584              : 
     585            0 :    REG_INDI_NEWPROP(m_indiP_C2ofst, "C2ofst", pcf::IndiProperty::Number);
     586            0 :    m_indiP_C2ofst.add (pcf::IndiElement("value"));
     587            0 :    m_indiP_C2ofst["value"].set(0);
     588              : 
     589            0 :    if(m_waveform == "SINE")
     590              :    {
     591            0 :       REG_INDI_NEWPROP(m_indiP_C2phse, "C2phse", pcf::IndiProperty::Number);
     592            0 :       m_indiP_C2phse.add (pcf::IndiElement("value"));
     593            0 :       m_indiP_C2phse["value"].set(0);
     594              :    }
     595              : 
     596            0 :    if(m_waveform == "PULSE")
     597              :    {
     598            0 :       REG_INDI_NEWPROP(m_indiP_C2wdth, "C2wdth", pcf::IndiProperty::Number);
     599            0 :       m_indiP_C2wdth.add (pcf::IndiElement("value"));
     600            0 :       m_indiP_C2wdth["value"].set(0);
     601              :    }
     602              : 
     603            0 :    REG_INDI_NEWPROP(m_indiP_C2wvtp, "C2wvtp", pcf::IndiProperty::Text);
     604            0 :    m_indiP_C2wvtp.add (pcf::IndiElement("value"));
     605            0 :    m_indiP_C2wvtp["value"].set("");
     606              : 
     607            0 :    REG_INDI_NEWPROP_NOCB(m_indiP_C2peri, "C2peri", pcf::IndiProperty::Number);
     608            0 :    m_indiP_C2peri.add (pcf::IndiElement("value"));
     609            0 :    m_indiP_C2peri["value"].set(0);
     610              : 
     611            0 :    REG_INDI_NEWPROP_NOCB(m_indiP_C2ampvrms, "C2ampvrms", pcf::IndiProperty::Number);
     612            0 :    m_indiP_C2ampvrms.add (pcf::IndiElement("value"));
     613            0 :    m_indiP_C2ampvrms["value"].set(0);
     614              : 
     615            0 :    REG_INDI_NEWPROP_NOCB(m_indiP_C2hlev, "C2hlev", pcf::IndiProperty::Number);
     616            0 :    m_indiP_C2hlev.add (pcf::IndiElement("value"));
     617            0 :    m_indiP_C2hlev["value"].set(0);
     618              : 
     619            0 :    REG_INDI_NEWPROP_NOCB(m_indiP_C2llev, "C2llev", pcf::IndiProperty::Number);
     620            0 :    m_indiP_C2llev.add (pcf::IndiElement("value"));
     621            0 :    m_indiP_C2llev["value"].set(0);
     622              : 
     623            0 :    createStandardIndiToggleSw( m_indiP_C2sync, "C2synchro", "C2 Sync Output", "C2 Sync Output");
     624            0 :    if(registerIndiPropertyNew( m_indiP_C2sync, st_newCallBack_m_indiP_C2sync) < 0)
     625              :    {
     626            0 :       log<software_error>({__FILE__,__LINE__});
     627            0 :       return -1;
     628              :    }
     629              : 
     630            0 :    if(dev::telemeter<siglentSDG>::appStartup() < 0)
     631              :    {
     632            0 :       return log<software_error,-1>({__FILE__,__LINE__});
     633              :    }
     634              : 
     635            0 :    return 0;
     636              : }
     637              : 
     638              : inline
     639            0 : int siglentSDG::appLogic()
     640              : {
     641              : 
     642            0 :    if( state() == stateCodes::POWERON )
     643              :    {
     644            0 :       m_poweredOn = true; //So we reset the device.
     645              : 
     646            0 :       state(stateCodes::NOTCONNECTED);
     647            0 :       m_powerOnCounter = 0;
     648              :    }
     649              : 
     650              :    //If we enter this loop in state ERROR, we wait 1 sec and then check power state.
     651            0 :    if( state() == stateCodes::ERROR )
     652              :    {
     653            0 :       sleep(1);
     654              : 
     655              :       //This allows for the case where the device powers off causing a comm error
     656              :       //But we haven't gotten the update from the power controller before going through
     657              :       //the main loop after the error.
     658            0 :       if( (m_powerState != 1 || m_powerTargetState != 1) == true)
     659              :       {
     660            0 :          return 0;
     661              :       }
     662              :    }
     663              : 
     664            0 :    if( state() == stateCodes::NOTCONNECTED || state() == stateCodes::ERROR )
     665              :    {
     666            0 :       int rv = m_telnetConn.connect(m_deviceAddr, m_devicePort);
     667              : 
     668            0 :       if(rv == 0)
     669              :       {
     670              :          ///\todo the connection process in siglentSDG is a total hack.  Figure out why this is needed to clear the channel, especially on a post-poweroff/on reconnect.
     671              : 
     672              :          //The sleeps here seem to be necessary to make sure there is a good
     673              :          //comm with device.  Probably a more graceful way.
     674            0 :          state(stateCodes::CONNECTED);
     675            0 :          m_telnetConn.noLogin();
     676              :          //sleep(1);//Wait for the connection to take.
     677              : 
     678            0 :          m_telnetConn.read(">>", m_readTimeOut);
     679              : 
     680            0 :          m_telnetConn.m_strRead.clear();
     681            0 :          m_telnetConn.write("\n", m_writeTimeOut);
     682              : 
     683            0 :          m_telnetConn.read(">>", m_readTimeOut);
     684              : 
     685            0 :          int n = 0;
     686            0 :          while( m_telnetConn.m_strRead != ">>")
     687              :          {
     688            0 :             if(n>9)
     689              :             {
     690            0 :                log<software_critical>({__FILE__, __LINE__, "No response from device.  Time to power cycle."});
     691            0 :                return -1;
     692              :             }
     693            0 :             m_telnetConn.write("\n", m_writeTimeOut);
     694            0 :             sleep(1);
     695            0 :             m_telnetConn.read(">>", m_readTimeOut);
     696            0 :             ++n;
     697              :          }
     698              : 
     699            0 :          if(!stateLogged())
     700              :          {
     701            0 :             std::stringstream logs;
     702            0 :             logs << "Connected to " << m_deviceAddr << ":" << m_devicePort;
     703            0 :             log<text_log>(logs.str());
     704            0 :          }
     705            0 :          return 0;//We cycle out to give connection time to settle.
     706              :       }
     707              :       else
     708              :       {
     709              : 
     710            0 :          if(m_powerOnCounter > m_bootDelay && !stateLogged())
     711              :          {
     712            0 :             std::stringstream logs;
     713            0 :             logs << "Failed to connect to " << m_deviceAddr << ":" << m_devicePort;
     714            0 :             log<text_log>(logs.str());
     715            0 :          }
     716              : 
     717            0 :          m_powerOnCounter += 1 + m_loopPause/1e9;
     718              : 
     719            0 :          return 0;
     720              :       }
     721              :    }
     722              : 
     723            0 :    if(state() == stateCodes::CONNECTED )
     724              :    {
     725              :       //Do Initial Checks Here.
     726            0 :       std::unique_lock<std::mutex> lock(m_indiMutex, std::try_to_lock);
     727            0 :       if(lock.owns_lock())
     728              :       {
     729            0 :          if(m_poweredOn)
     730              :          {
     731              :             //This means we need to do the power-on setup.
     732            0 :             if(normalizeSetup() < 0 )
     733              :             {
     734            0 :                log<software_critical>({__FILE__, __LINE__});
     735            0 :                return -1;
     736              :             }
     737              : 
     738            0 :             m_poweredOn = false;
     739              :          }
     740              : 
     741            0 :          int cs = checkSetup();
     742              : 
     743            0 :          if(cs < 0) return 0; //This means we aren't really connected yet.
     744              : 
     745              :          int rv;
     746              : 
     747            0 :          rv = queryBSWV(1);
     748              : 
     749            0 :          if( rv < 0 )
     750              :          {
     751            0 :             if(rv != SDG_PARSEERR_WVTP ) return 0; //This means we aren't really connected yet.
     752              : 
     753            0 :             cs = 1; //Trigger normalizeSetup
     754              :          }
     755              : 
     756            0 :          rv = queryBSWV(2);
     757              : 
     758            0 :          if( rv < 0 )
     759              :          {
     760            0 :             if(rv != SDG_PARSEERR_WVTP ) return 0; //This means we aren't really connected yet.
     761              : 
     762            0 :             cs = 1; //Trigger normalizeSetup
     763              :          }
     764              : 
     765            0 :          if(cs > 0)
     766              :          {
     767            0 :             log<text_log>("Failed setup check, normalizing setup.", logPrio::LOG_NOTICE);
     768            0 :             if(normalizeSetup() < 0)
     769              :             {
     770            0 :                log<software_critical>({__FILE__, __LINE__});
     771            0 :                return -1;
     772              :             }
     773              : 
     774            0 :             return 0;
     775              :          }
     776              : 
     777            0 :          if( queryOUTP(1) < 0 ) return 0; //This means we aren't really connected yet.
     778            0 :          if( queryOUTP(2) < 0 ) return 0; //This means we aren't really connected yet.
     779              : 
     780              : 
     781              : 
     782            0 :          if( m_C1outp == 1 || m_C2outp == 1)
     783              :          {
     784            0 :             state(stateCodes::OPERATING);
     785              :          }
     786              :          else
     787              :          {
     788            0 :             state(stateCodes::READY);
     789              :          }
     790              : 
     791            0 :          recordParams(true);
     792              : 
     793              :       }
     794              :       else
     795              :       {
     796            0 :          log<text_log>("Could not get mutex after connecting.", logPrio::LOG_CRITICAL);
     797            0 :          return -1;
     798              :       }
     799            0 :    }
     800              : 
     801            0 :    if(state() == stateCodes::READY || state() == stateCodes::OPERATING)
     802              :    {
     803              :       // Do this right away to avoid a different thread updating something after we get it.
     804            0 :       std::unique_lock<std::mutex> lock(m_indiMutex, std::try_to_lock);
     805            0 :       if(lock.owns_lock())
     806              :       {
     807            0 :          int cs = checkSetup();
     808              : 
     809            0 :          if(cs < 0)
     810              :          {
     811            0 :             if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown)
     812              :             {
     813            0 :                log<software_error>({__FILE__, __LINE__});
     814            0 :                state(stateCodes::ERROR);
     815              :             }
     816            0 :             return 0;
     817              :          }
     818              : 
     819              :          int rv;
     820              : 
     821            0 :          rv = queryBSWV(1);
     822              : 
     823            0 :          if( rv < 0 )
     824              :          {
     825            0 :             if(rv != SDG_PARSEERR_WVTP )
     826              :             {
     827            0 :                if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown)
     828              :                {
     829            0 :                   log<software_error>({__FILE__, __LINE__});
     830            0 :                   state(stateCodes::ERROR);
     831              :                }
     832            0 :                return 0;
     833              :             }
     834              : 
     835            0 :             cs = 1; //Trigger normalizeSetup
     836              :          }
     837              : 
     838            0 :          if(m_C1sync)
     839              :          {
     840            0 :             updateSwitchIfChanged(m_indiP_C1sync, "toggle", pcf::IndiElement::On, INDI_OK);
     841              :          }
     842              :          else
     843              :          {
     844            0 :             updateSwitchIfChanged(m_indiP_C1sync, "toggle", pcf::IndiElement::Off, INDI_IDLE);
     845              :          }
     846              : 
     847            0 :          rv = queryBSWV(2);
     848              : 
     849            0 :          if( rv < 0 )
     850              :          {
     851            0 :             if(rv != SDG_PARSEERR_WVTP )
     852              :             {
     853            0 :                if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown)
     854              :                {
     855            0 :                   log<software_error>({__FILE__, __LINE__});
     856            0 :                   state(stateCodes::ERROR);
     857              :                }
     858            0 :                return 0;
     859              :             }
     860              : 
     861            0 :             cs = 1; //Trigger normalizeSetup
     862              :          }
     863              : 
     864            0 :          if(m_C2sync)
     865              :          {
     866            0 :             updateSwitchIfChanged(m_indiP_C2sync, "toggle", pcf::IndiElement::On, INDI_OK);
     867              :          }
     868              :          else
     869              :          {
     870            0 :             updateSwitchIfChanged(m_indiP_C2sync, "toggle", pcf::IndiElement::Off, INDI_IDLE);
     871              :          }
     872              : 
     873            0 :          if(cs > 0)
     874              :          {
     875            0 :             log<text_log>("Failed setup check, normalizing setup.", logPrio::LOG_NOTICE);
     876            0 :             normalizeSetup();
     877              : 
     878            0 :             return 0;
     879              :          }
     880              : 
     881              : 
     882            0 :          if( queryOUTP(1) < 0 )
     883              :          {
     884            0 :             if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown)
     885              :             {
     886            0 :                log<software_error>({__FILE__, __LINE__});
     887            0 :                state(stateCodes::ERROR);
     888              :             }
     889            0 :             return 0;
     890              :          }
     891              : 
     892            0 :          if( queryOUTP(2) < 0 )
     893              :          {
     894            0 :             if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown)
     895              :             {
     896            0 :                log<software_error>({__FILE__, __LINE__});
     897            0 :                state(stateCodes::ERROR);
     898              :             }
     899            0 :             return 0;
     900              :          }
     901              : 
     902            0 :          if( m_C1outp == 1 || m_C2outp == 1)
     903              :          {
     904            0 :             state(stateCodes::OPERATING);
     905              :          }
     906              :          else
     907              :          {
     908            0 :             state(stateCodes::READY);
     909              :          }
     910              : 
     911            0 :          recordParams(); //This will check if anything changed.
     912              :       }
     913              : 
     914            0 :       if(telemeter<siglentSDG>::appLogic() < 0)
     915              :       {
     916            0 :          log<software_error>({__FILE__, __LINE__});
     917            0 :          return 0;
     918              :       }
     919              : 
     920            0 :       return 0;
     921              : 
     922            0 :    }
     923              : 
     924            0 :    if( state() == stateCodes::CONFIGURING )
     925              :    {
     926            0 :       return 0;
     927              :    }
     928              : 
     929              :    //It's possible to get here because other threads are changing states.
     930              :    //These are the only valid states for this APP at this point.  Anything else and we'll log it.
     931            0 :    if( state() == stateCodes::READY || state() == stateCodes::OPERATING || state() == stateCodes::CONFIGURING )
     932              :    {
     933            0 :       return 0;
     934              :    }
     935              : 
     936              : 
     937            0 :    log<software_error>({__FILE__, __LINE__, "appLogic fell through in state " + stateCodes::codeText(state())});
     938            0 :    return 0;
     939              : 
     940              : }
     941              : 
     942              : inline
     943            0 : int siglentSDG::onPowerOff()
     944              : {
     945            0 :    std::lock_guard<std::mutex> lock(m_indiMutex);
     946              : 
     947            0 :    m_C1wvtp = "NONE";
     948            0 :    m_C1frequency = 0.0;
     949            0 :    m_C1vpp = 0.0;
     950            0 :    m_C1ofst = 0.0;
     951            0 :    m_C1outp = 0;
     952              : 
     953            0 :    m_C1frequency_tgt = -1;
     954            0 :    m_C1vpp_tgt = -1;
     955              : 
     956            0 :    updateIfChanged(m_indiP_C1wvtp, "value", m_C1wvtp);
     957              : 
     958            0 :    updateIfChanged(m_indiP_C1freq, "current", 0.0);
     959            0 :    updateIfChanged(m_indiP_C1freq, "target", 0.0);
     960              : 
     961            0 :    updateIfChanged(m_indiP_C1peri, "value", 0.0);
     962              : 
     963            0 :    updateIfChanged(m_indiP_C1amp, "current", 0.0);
     964            0 :    updateIfChanged(m_indiP_C1amp, "target", 0.0);
     965              : 
     966            0 :    updateIfChanged(m_indiP_C1ampvrms, "value", 0.0);
     967            0 :    updateIfChanged(m_indiP_C1ofst, "value", 0.0);
     968            0 :    updateIfChanged(m_indiP_C1hlev, "value", 0.0);
     969            0 :    updateIfChanged(m_indiP_C1llev, "value", 0.0);
     970            0 :    if(m_waveform == "SINE"){updateIfChanged(m_indiP_C1phse, "value", 0.0);}
     971            0 :    if(m_waveform == "PULSE"){updateIfChanged(m_indiP_C1wdth, "value", 0.0);}
     972            0 :    updateIfChanged(m_indiP_C1outp, "value", std::string("Off"));
     973            0 :    updateSwitchIfChanged(m_indiP_C1sync, "toggle", pcf::IndiElement::Off, INDI_IDLE);
     974              : 
     975              : 
     976            0 :    m_C2wvtp = "NONE";
     977            0 :    m_C2frequency = 0.0;
     978            0 :    m_C2vpp = 0.0;
     979            0 :    m_C2ofst = 0.0;
     980            0 :    m_C2outp = 0;
     981              : 
     982            0 :    m_C2frequency_tgt = -1;
     983            0 :    m_C2vpp_tgt = -1;
     984              : 
     985            0 :    updateIfChanged(m_indiP_C2wvtp, "value", m_C2wvtp);
     986              : 
     987            0 :    updateIfChanged(m_indiP_C2freq, "current", 0.0);
     988            0 :    updateIfChanged(m_indiP_C2freq, "target", 0.0);
     989              : 
     990            0 :    updateIfChanged(m_indiP_C2peri, "value", 0.0);
     991              : 
     992            0 :    updateIfChanged(m_indiP_C2amp, "current", 0.0);
     993            0 :    updateIfChanged(m_indiP_C2amp, "target", 0.0);
     994              : 
     995            0 :    updateIfChanged(m_indiP_C2ampvrms, "value", 0.0);
     996            0 :    updateIfChanged(m_indiP_C2ofst, "value", 0.0);
     997            0 :    updateIfChanged(m_indiP_C2hlev, "value", 0.0);
     998            0 :    updateIfChanged(m_indiP_C2llev, "value", 0.0);
     999            0 :    if(m_waveform == "SINE"){updateIfChanged(m_indiP_C2phse, "value", 0.0);}
    1000            0 :    if(m_waveform == "PULSE"){updateIfChanged(m_indiP_C2wdth, "value", 0.0);}
    1001            0 :    updateIfChanged(m_indiP_C1outp, "value", std::string("Off"));
    1002            0 :    updateSwitchIfChanged(m_indiP_C2sync, "toggle", pcf::IndiElement::Off, INDI_IDLE);
    1003              : 
    1004            0 :    return 0;
    1005            0 : }
    1006              : 
    1007              : inline
    1008            0 : int siglentSDG::whilePowerOff()
    1009              : {
    1010            0 :    return onPowerOff();
    1011              : }
    1012              : 
    1013              : inline
    1014            0 : int siglentSDG::appShutdown()
    1015              : {
    1016            0 :    dev::telemeter<siglentSDG>::appShutdown();
    1017              : 
    1018            0 :    return 0;
    1019              : }
    1020              : 
    1021              : inline
    1022            0 : int siglentSDG::writeRead( std::string & strRead,
    1023              :                            const std::string & command
    1024              :                          )
    1025              : {
    1026              :    int rv;
    1027            0 :    rv = m_telnetConn.writeRead(command, false, m_writeTimeOut, m_readTimeOut);
    1028            0 :    strRead = m_telnetConn.m_strRead;
    1029              : 
    1030            0 :    if(rv < 0)
    1031              :    {
    1032            0 :       std::cout << command << "\n";
    1033            0 :       std::cout << "writeRead return val was " << rv << "\n";
    1034            0 :       if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<software_error>({__FILE__, __LINE__, 0, rv, tty::ttyErrorString(rv)});
    1035            0 :       state(stateCodes::NOTCONNECTED);
    1036            0 :       return -1;
    1037              :    }
    1038              : 
    1039              :    //Clear the newline
    1040            0 :    rv = m_telnetConn.write("\n", m_writeTimeOut);
    1041            0 :    if(rv < 0)
    1042              :    {
    1043            0 :       if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<software_error>({__FILE__, __LINE__, 0, rv, tty::ttyErrorString(rv)});
    1044            0 :       return -1;
    1045              :    }
    1046              : 
    1047            0 :    rv = m_telnetConn.read(">>", m_readTimeOut);
    1048            0 :    if(rv < 0)
    1049              :    {
    1050            0 :       if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<software_error>({__FILE__, __LINE__, 0, rv, tty::ttyErrorString(rv)});
    1051            0 :       return -1;
    1052              :    }
    1053            0 :    return 0;
    1054              : 
    1055              : }
    1056              : 
    1057              : inline
    1058            0 : int siglentSDG::writeCommand( const std::string & command )
    1059              : {
    1060              : 
    1061            0 :    int rv = m_telnetConn.write(command, m_writeTimeOut);
    1062            0 :    if(rv < 0)
    1063              :    {
    1064            0 :       if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<software_error>({__FILE__, __LINE__, 0, rv, tty::ttyErrorString(rv)});
    1065            0 :       return -1;
    1066              :    }
    1067              : 
    1068              :    //Clear the newline
    1069            0 :    rv = m_telnetConn.write("\n", m_writeTimeOut);
    1070            0 :    if(rv < 0)
    1071              :    {
    1072            0 :       if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<software_error>({__FILE__, __LINE__, 0, rv, tty::ttyErrorString(rv)});
    1073            0 :       return -1;
    1074              :    }
    1075              : 
    1076            0 :    rv = m_telnetConn.read(">>", m_readTimeOut);
    1077            0 :    if(rv < 0)
    1078              :    {
    1079            0 :       if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<software_error>({__FILE__, __LINE__, 0, rv, tty::ttyErrorString(rv)});
    1080            0 :       return -1;
    1081              :    }
    1082              : 
    1083            0 :    return 0;
    1084              : }
    1085              : 
    1086              : inline
    1087            0 : std::string makeCommand( int channel,
    1088              :                          const std::string & afterColon
    1089              :                        )
    1090              : {
    1091            0 :    std::string command = "C";
    1092            0 :    command += mx::ioutils::convertToString<int>(channel);
    1093            0 :    command += ":";
    1094            0 :    command += afterColon;
    1095            0 :    command += "\r\n";
    1096              : 
    1097            0 :    return command;
    1098            0 : }
    1099              : 
    1100              : inline
    1101            0 : int siglentSDG::queryMDWV( std::string & state,
    1102              :                            int channel
    1103              :                          )
    1104              : {
    1105              :    int rv;
    1106              : 
    1107            0 :    if(channel < 1 || channel > 2) return -1;
    1108              : 
    1109            0 :    std::string strRead;
    1110              : 
    1111            0 :    std::string com = makeCommand(channel, "MDWV?");
    1112              : 
    1113            0 :    rv = writeRead( strRead, com);
    1114              : 
    1115            0 :    if(rv < 0)
    1116              :    {
    1117            0 :       if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<text_log>("Error on MDWV? for channel " + mx::ioutils::convertToString<int>(channel), logPrio::LOG_ERROR);
    1118            0 :       return -1;
    1119              :    }
    1120              : 
    1121              :    int resp_channel;
    1122            0 :    std::string resp_state;
    1123              : 
    1124            0 :    rv = parseMDWV(resp_channel, resp_state, strRead );
    1125              : 
    1126            0 :    if(rv == 0)
    1127              :    {
    1128            0 :       if(resp_channel != channel)
    1129              :       {
    1130            0 :          if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<software_error>({__FILE__,__LINE__, "wrong channel returned"});
    1131            0 :          return -1;
    1132              :       }
    1133              : 
    1134            0 :       state = resp_state;
    1135              :    }
    1136              :    else
    1137              :    {
    1138            0 :       if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<software_error>({__FILE__,__LINE__, 0, rv, "parse error"});
    1139            0 :       return -1;
    1140              :    }
    1141              : 
    1142            0 :    return 0;
    1143            0 : }
    1144              : 
    1145              : inline
    1146            0 : int siglentSDG::querySWWV( std::string & state,
    1147              :                            int channel
    1148              :                          )
    1149              : {
    1150              :    int rv;
    1151              : 
    1152            0 :    if(channel < 1 || channel > 2) return -1;
    1153              : 
    1154            0 :    std::string strRead;
    1155              : 
    1156            0 :    std::string com = makeCommand(channel, "SWWV?");
    1157              : 
    1158            0 :    rv = writeRead( strRead, com);
    1159              : 
    1160            0 :    if(rv < 0)
    1161              :    {
    1162            0 :       if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<text_log>("Error on SWWV? for channel " + mx::ioutils::convertToString<int>(channel), logPrio::LOG_ERROR);
    1163            0 :       return -1;
    1164              :    }
    1165              : 
    1166              :    int resp_channel;
    1167            0 :    std::string resp_state;
    1168              : 
    1169            0 :    rv = parseSWWV(resp_channel, resp_state, strRead );
    1170              : 
    1171            0 :    if(rv == 0)
    1172              :    {
    1173            0 :       if(resp_channel != channel)
    1174              :       {
    1175            0 :          if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<software_error>({__FILE__,__LINE__, "wrong channel returned"});
    1176            0 :          return -1;
    1177              :       }
    1178              : 
    1179            0 :       state = resp_state;
    1180              :    }
    1181              :    else
    1182              :    {
    1183            0 :       if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<software_error>({__FILE__,__LINE__, 0, rv, "parse error"});
    1184            0 :       return -1;
    1185              :    }
    1186              : 
    1187            0 :    return 0;
    1188            0 : }
    1189              : 
    1190              : inline
    1191            0 : int siglentSDG::queryBTWV( std::string & state,
    1192              :                            int channel
    1193              :                          )
    1194              : {
    1195              :    int rv;
    1196              : 
    1197            0 :    if(channel < 1 || channel > 2) return -1;
    1198              : 
    1199            0 :    std::string strRead;
    1200              : 
    1201            0 :    std::string com = makeCommand(channel, "BTWV?");
    1202              : 
    1203            0 :    rv = writeRead( strRead, com);
    1204              : 
    1205            0 :    if(rv < 0)
    1206              :    {
    1207            0 :       if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<text_log>("Error on BTWV? for channel " + mx::ioutils::convertToString<int>(channel), logPrio::LOG_ERROR);
    1208            0 :       return -1;
    1209              :    }
    1210              : 
    1211              :    int resp_channel;
    1212            0 :    std::string resp_state;
    1213              : 
    1214            0 :    rv = parseBTWV(resp_channel, resp_state, strRead );
    1215              : 
    1216            0 :    if(rv == 0)
    1217              :    {
    1218            0 :       if(resp_channel != channel)
    1219              :       {
    1220            0 :          if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<software_error>({__FILE__,__LINE__, "wrong channel returned"});
    1221            0 :          return -1;
    1222              :       }
    1223              : 
    1224            0 :       state = resp_state;
    1225              :    }
    1226              :    else
    1227              :    {
    1228            0 :       if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<software_error>({__FILE__,__LINE__, 0, rv, "parse error"});
    1229            0 :       return -1;
    1230              :    }
    1231              : 
    1232            0 :    return 0;
    1233            0 : }
    1234              : 
    1235              : inline
    1236            0 : int siglentSDG::queryARWV( int & index,
    1237              :                            int channel
    1238              :                          )
    1239              : {
    1240              :    int rv;
    1241              : 
    1242            0 :    if(channel < 1 || channel > 2) return -1;
    1243              : 
    1244            0 :    std::string strRead;
    1245              : 
    1246            0 :    std::string com = makeCommand(channel, "ARWV?");
    1247              : 
    1248            0 :    rv = writeRead( strRead, com);
    1249              : 
    1250            0 :    if(rv < 0)
    1251              :    {
    1252            0 :       if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<text_log>("Error on ARWV? for channel " + mx::ioutils::convertToString<int>(channel), logPrio::LOG_ERROR);
    1253            0 :       return -1;
    1254              :    }
    1255              : 
    1256              :    int resp_channel;
    1257              :    int resp_index;
    1258              : 
    1259            0 :    rv = parseARWV(resp_channel, resp_index, strRead );
    1260              : 
    1261            0 :    if(rv == 0)
    1262              :    {
    1263            0 :       if(resp_channel != channel)
    1264              :       {
    1265            0 :          if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<software_error>({__FILE__,__LINE__, "wrong channel returned"});
    1266            0 :          return -1;
    1267              :       }
    1268              : 
    1269            0 :       index = resp_index;
    1270              :    }
    1271              :    else
    1272              :    {
    1273            0 :       if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<software_error>({__FILE__,__LINE__, 0, rv, "parse error"});
    1274            0 :       return -1;
    1275              :    }
    1276              : 
    1277            0 :    return 0;
    1278            0 : }
    1279              : 
    1280              : inline
    1281            0 : int siglentSDG::queryBSWV( int channel)
    1282              : {
    1283              :    int rv;
    1284              : 
    1285            0 :    if(channel < 1 || channel > 2) return -1;
    1286              : 
    1287            0 :    std::string strRead;
    1288              : 
    1289            0 :    std::string com = makeCommand(channel, "BSWV?");
    1290              : 
    1291            0 :    rv = writeRead( strRead, com);
    1292              : 
    1293            0 :    if(rv < 0)
    1294              :    {
    1295            0 :       if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<text_log>("Error on BSWV? for channel " + mx::ioutils::convertToString<int>(channel), logPrio::LOG_ERROR);
    1296            0 :       return -1;
    1297              :    }
    1298              : 
    1299              :    int resp_channel;
    1300            0 :    std::string resp_wvtp;
    1301              :    double resp_freq, resp_peri, resp_amp, resp_ampvrms, resp_ofst, resp_hlev, resp_llev, resp_phse, resp_wdth;
    1302              : 
    1303            0 :    rv = parseBSWV(resp_channel, resp_wvtp, resp_freq, resp_peri, resp_amp, resp_ampvrms, resp_ofst, resp_hlev, resp_llev, resp_phse, resp_wdth, strRead );
    1304              : 
    1305            0 :    if(rv == 0)
    1306              :    {
    1307            0 :       if(resp_channel != channel)
    1308              :       {
    1309            0 :          if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<software_error>({__FILE__,__LINE__, "wrong channel returned"});
    1310            0 :          return -1;
    1311              :       }
    1312              : 
    1313            0 :       if(channel == 1)
    1314              :       {
    1315            0 :          m_C1wvtp = resp_wvtp;
    1316            0 :          m_C1frequency = resp_freq;
    1317            0 :          m_C1vpp = resp_amp;
    1318            0 :          m_C1ofst = resp_ofst;
    1319            0 :          m_C1phse = resp_phse;
    1320            0 :          m_C1wdth = resp_wdth;
    1321              : 
    1322            0 :          if(m_C1frequency_tgt == -1) m_C1frequency_tgt = m_C1frequency;
    1323            0 :          if(m_C1vpp_tgt == -1) m_C1vpp_tgt = m_C1vpp;
    1324              : 
    1325            0 :          recordParams();
    1326              : 
    1327            0 :          updateIfChanged(m_indiP_C1wvtp, "value", resp_wvtp);
    1328            0 :          updateIfChanged(m_indiP_C1freq, "current", resp_freq);
    1329            0 :          updateIfChanged(m_indiP_C1peri, "value", resp_peri);
    1330              : 
    1331            0 :          updateIfChanged(m_indiP_C1amp, "current", resp_amp);
    1332              : 
    1333            0 :          updateIfChanged(m_indiP_C1ampvrms, "value", resp_ampvrms);
    1334            0 :          updateIfChanged(m_indiP_C1ofst, "value", resp_ofst);
    1335            0 :          updateIfChanged(m_indiP_C1hlev, "value", resp_hlev);
    1336            0 :          updateIfChanged(m_indiP_C1llev, "value", resp_llev);
    1337            0 :          if(m_waveform == "SINE"){updateIfChanged(m_indiP_C1phse, "value", resp_phse);}
    1338            0 :          if(m_waveform == "PULSE"){updateIfChanged(m_indiP_C1wdth, "value", resp_wdth);}
    1339              :       }
    1340            0 :       else if(channel == 2)
    1341              :       {
    1342            0 :          m_C2wvtp = resp_wvtp;
    1343            0 :          m_C2frequency = resp_freq;
    1344            0 :          m_C2vpp = resp_amp;
    1345            0 :          m_C2ofst = resp_ofst;
    1346            0 :          m_C2phse = resp_phse;
    1347            0 :          m_C2wdth = resp_wdth;
    1348              : 
    1349            0 :          if(m_C2frequency_tgt == -1) m_C2frequency_tgt = m_C2frequency;
    1350            0 :          if(m_C2vpp_tgt == -1) m_C2vpp_tgt = m_C2vpp;
    1351              : 
    1352            0 :          recordParams();
    1353              : 
    1354            0 :          updateIfChanged(m_indiP_C2wvtp, "value", resp_wvtp);
    1355            0 :          updateIfChanged(m_indiP_C2freq, "current", resp_freq);
    1356            0 :          updateIfChanged(m_indiP_C2peri, "value", resp_peri);
    1357            0 :          updateIfChanged(m_indiP_C2amp, "current", resp_amp);
    1358            0 :          updateIfChanged(m_indiP_C2ampvrms, "value", resp_ampvrms);
    1359            0 :          updateIfChanged(m_indiP_C2ofst, "value", resp_ofst);
    1360            0 :          updateIfChanged(m_indiP_C2hlev, "value", resp_hlev);
    1361            0 :          updateIfChanged(m_indiP_C2llev, "value", resp_llev);
    1362            0 :          if(m_waveform == "SINE"){updateIfChanged(m_indiP_C2phse, "value", resp_phse);}
    1363            0 :          if(m_waveform == "PULSE"){updateIfChanged(m_indiP_C2wdth, "value", resp_wdth);}
    1364              :       }
    1365              :    }
    1366              :    else
    1367              :    {
    1368            0 :       log<software_error>({__FILE__,__LINE__, 0, rv, "parse error"});
    1369            0 :       return -1;
    1370              :    }
    1371              : 
    1372            0 :    return 0;
    1373            0 : }
    1374              : 
    1375              : inline
    1376            0 : int siglentSDG::querySYNC( bool & sync,
    1377              :                            int channel
    1378              :                          )
    1379              : {
    1380              :    int rv;
    1381              : 
    1382            0 :    if(channel < 1 || channel > 2) return -1;
    1383              : 
    1384            0 :    std::string strRead;
    1385              : 
    1386            0 :    std::string com = makeCommand(channel, "SYNC?");
    1387              : 
    1388            0 :    rv = writeRead( strRead, com);
    1389              : 
    1390            0 :    if(rv < 0)
    1391              :    {
    1392            0 :       if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<text_log>("Error on SYNC? for channel " + mx::ioutils::convertToString<int>(channel), logPrio::LOG_ERROR);
    1393            0 :       return -1;
    1394              :    }
    1395              : 
    1396              :    int resp_channel;
    1397              :    bool resp_sync;
    1398              : 
    1399            0 :    rv = parseSYNC(resp_channel, resp_sync, strRead );
    1400              : 
    1401            0 :    if(rv == 0)
    1402              :    {
    1403            0 :       if(resp_channel != channel)
    1404              :       {
    1405            0 :          if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<software_error>({__FILE__,__LINE__, "wrong channel returned"});
    1406            0 :          return -1;
    1407              :       }
    1408              : 
    1409            0 :       sync = resp_sync;
    1410              :    }
    1411              :    else
    1412              :    {
    1413            0 :       if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<software_error>({__FILE__,__LINE__, 0, rv, "parse error"});
    1414            0 :       return -1;
    1415              :    }
    1416              : 
    1417            0 :    return 0;
    1418            0 : }
    1419              : 
    1420              : inline
    1421            0 : int siglentSDG::queryOUTP( int channel )
    1422              : {
    1423              :    int rv;
    1424              : 
    1425            0 :    if(channel < 1 || channel > 2) return -1;
    1426              : 
    1427            0 :    std::string strRead;
    1428              : 
    1429            0 :    std::string com = makeCommand(channel, "OUTP?");
    1430              : 
    1431            0 :    rv = writeRead( strRead, com);
    1432              : 
    1433            0 :    if(rv < 0)
    1434              :    {
    1435            0 :       if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<text_log>("Error on OUTP? for channel " + mx::ioutils::convertToString<int>(channel), logPrio::LOG_ERROR);
    1436            0 :       return -1;
    1437              :    }
    1438              : 
    1439              :    int resp_channel;
    1440              :    int resp_output;
    1441              : 
    1442            0 :    rv = parseOUTP(resp_channel, resp_output, strRead );
    1443              : 
    1444            0 :    if(rv == 0)
    1445              :    {
    1446            0 :       if(resp_channel != channel)
    1447              :       {
    1448            0 :          if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<software_error>({__FILE__,__LINE__, "wrong channel returned"});
    1449            0 :          return -1;
    1450              :       }
    1451              : 
    1452            0 :       std::string ro;
    1453            0 :       if(resp_output > 0) ro = "On";
    1454            0 :       else if(resp_output == 0 ) ro = "Off";
    1455            0 :       else ro = "UNK";
    1456              : 
    1457            0 :       if(channel == 1)
    1458              :       {
    1459            0 :          m_C1outp = resp_output;
    1460            0 :          recordParams();
    1461            0 :          updateIfChanged(m_indiP_C1outp, "value", ro);
    1462              :       }
    1463              : 
    1464            0 :       else if(channel == 2)
    1465              :       {
    1466            0 :          m_C2outp = resp_output;
    1467            0 :          recordParams();
    1468            0 :          updateIfChanged(m_indiP_C2outp, "value", ro);
    1469              :       }
    1470            0 :    }
    1471              :    else
    1472              :    {
    1473            0 :       if((m_powerState != 1 || m_powerTargetState != 1) && !m_shutdown) log<software_error>({__FILE__,__LINE__, 0, rv, "parse error"});
    1474            0 :       return -1;
    1475              :    }
    1476              : 
    1477            0 :    return 0;
    1478            0 : }
    1479              : 
    1480              : inline
    1481            0 : int siglentSDG::checkSetup()
    1482              : {
    1483            0 :    std::string state;
    1484              :    int index;
    1485              :    int rv;
    1486              : 
    1487            0 :    rv = queryMDWV(state, 1);
    1488              : 
    1489            0 :    if(rv < 0)
    1490              :    {
    1491            0 :       if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown) log<software_error>({__FILE__,__LINE__});
    1492            0 :       return rv;
    1493              :    }
    1494              : 
    1495            0 :    if(state != "OFF")
    1496              :    {
    1497            0 :       if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown) log<text_log>("Channel 1 MDWV not OFF");
    1498            0 :       return 1;
    1499              :    }
    1500              : 
    1501            0 :    rv = queryMDWV(state, 2);
    1502              : 
    1503            0 :    if(rv < 0)
    1504              :    {
    1505            0 :       if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown) log<software_error>({__FILE__,__LINE__});
    1506            0 :       return rv;
    1507              :    }
    1508              : 
    1509            0 :    if(state != "OFF")
    1510              :    {
    1511            0 :       if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown) log<text_log>("Channel 2 MDWV not OFF");
    1512            0 :       return 1;
    1513              :    }
    1514              : 
    1515            0 :    rv = querySWWV(state, 1);
    1516              : 
    1517            0 :    if(rv < 0)
    1518              :    {
    1519            0 :       if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown) log<software_error>({__FILE__,__LINE__});
    1520            0 :       return rv;
    1521              :    }
    1522              : 
    1523            0 :    if(state != "OFF")
    1524              :    {
    1525            0 :       if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown) log<text_log>("Channel 1 SWWV not OFF");
    1526            0 :       return 1;
    1527              :    }
    1528              : 
    1529            0 :    rv = querySWWV(state, 2);
    1530              : 
    1531            0 :    if(rv < 0)
    1532              :    {
    1533            0 :       if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown) log<software_error>({__FILE__,__LINE__});
    1534            0 :       return rv;
    1535              :    }
    1536              : 
    1537            0 :    if(state != "OFF")
    1538              :    {
    1539            0 :       if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown) log<text_log>("Channel 2 SWWV no OFF");
    1540            0 :       return 1;
    1541              :    }
    1542              : 
    1543            0 :    rv = queryBTWV(state, 1);
    1544              : 
    1545            0 :    if(rv < 0)
    1546              :    {
    1547            0 :       if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown) log<software_error>({__FILE__,__LINE__});
    1548            0 :       return rv;
    1549              :    }
    1550              : 
    1551            0 :    if(state != "OFF")
    1552              :    {
    1553            0 :       if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown) log<text_log>("Channel 1 BTWV not OFF");
    1554            0 :       return 1;
    1555              :    }
    1556              : 
    1557            0 :    rv = queryBTWV(state, 2);
    1558              : 
    1559            0 :    if(rv < 0)
    1560              :    {
    1561            0 :       if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown) log<software_error>({__FILE__,__LINE__});
    1562            0 :       return rv;
    1563              :    }
    1564              : 
    1565            0 :    if(state != "OFF")
    1566              :    {
    1567            0 :       if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown) log<text_log>("Channel 2 BTWV not OFF");
    1568            0 :       return 1;
    1569              :    }
    1570              : 
    1571            0 :    rv = queryARWV(index, 1);
    1572              : 
    1573            0 :    if(rv < 0)
    1574              :    {
    1575            0 :       if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown) log<software_error>({__FILE__,__LINE__});
    1576            0 :       return rv;
    1577              :    }
    1578              : 
    1579            0 :    if(index != 0)
    1580              :    {
    1581            0 :       if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown) log<text_log>("Channel 1 ARWV not 1");
    1582            0 :       return 1;
    1583              :    }
    1584              : 
    1585            0 :    rv = queryARWV(index, 2);
    1586              : 
    1587            0 :    if(rv < 0)
    1588              :    {
    1589            0 :       if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown) log<software_error>({__FILE__,__LINE__});
    1590            0 :       return rv;
    1591              :    }
    1592              : 
    1593            0 :    if(index != 0)
    1594              :    {
    1595            0 :       if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown) log<text_log>("Channel 2 ARWV not 1");
    1596            0 :       return 1;
    1597              :    }
    1598              : 
    1599            0 :    rv = querySYNC(m_C1sync, 1);
    1600              : 
    1601            0 :    if(rv < 0)
    1602              :    {
    1603            0 :       if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown) log<software_error>({__FILE__,__LINE__});
    1604            0 :       return rv;
    1605              :    }
    1606              : 
    1607            0 :    rv = querySYNC(m_C2sync, 2);
    1608              : 
    1609            0 :    if(rv < 0)
    1610              :    {
    1611            0 :       if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown) log<software_error>({__FILE__,__LINE__});
    1612            0 :       return rv;
    1613              :    }
    1614              : 
    1615              : 
    1616            0 :    return 0;
    1617            0 : }
    1618              : 
    1619              : inline
    1620            0 : int siglentSDG::normalizeSetup()
    1621              : {
    1622              : 
    1623            0 :    std::cerr << "Normalizing . . .";
    1624              : 
    1625            0 :    recordParams(true);
    1626              : 
    1627            0 :    changeOutp(1, "OFF");
    1628            0 :    changeOutp(2, "OFF");
    1629              : 
    1630            0 :    std::string afterColon;
    1631            0 :    std::string command;
    1632              : 
    1633            0 :    afterColon = "MDWV STATE,OFF";
    1634            0 :    command = makeCommand(1, afterColon);
    1635            0 :    writeCommand(command);
    1636              : 
    1637            0 :    command = makeCommand(2, afterColon);
    1638            0 :    writeCommand(command);
    1639              : 
    1640            0 :    afterColon = "SWWV STATE,OFF";
    1641            0 :    command = makeCommand(1, afterColon);
    1642            0 :    writeCommand(command);
    1643              : 
    1644            0 :    command = makeCommand(2, afterColon);
    1645            0 :    writeCommand(command);
    1646              : 
    1647            0 :    afterColon = "BTWV STATE,OFF";
    1648            0 :    command = makeCommand(1, afterColon);
    1649            0 :    writeCommand(command);
    1650              : 
    1651            0 :    command = makeCommand(2, afterColon);
    1652            0 :    writeCommand(command);
    1653              : 
    1654            0 :    afterColon = "ARWV INDEX,0";
    1655            0 :    command = makeCommand(1, afterColon);
    1656            0 :    writeCommand(command);
    1657              : 
    1658            0 :    command = makeCommand(2, afterColon);
    1659            0 :    writeCommand(command);
    1660              : 
    1661            0 :    changeWvtp(1, m_waveform);
    1662            0 :    changeWvtp(2, m_waveform);
    1663              : 
    1664            0 :    changeFreq(1, 0);
    1665            0 :    changeFreq(2, 0);
    1666              : 
    1667            0 :    changeAmp(1, m_C1vppDefault);
    1668            0 :    changeAmp(2, m_C2vppDefault);
    1669              : 
    1670            0 :    if(m_waveform == "SINE")
    1671              :    {
    1672            0 :       changePhse(1, 0);
    1673            0 :       changePhse(2, 0);
    1674              :    }
    1675            0 :    else if(m_waveform == "PULSE")
    1676              :    {
    1677            0 :       changeWdth(1, 0);
    1678            0 :       changeWdth(2, 0);
    1679              :    }
    1680              : 
    1681            0 :    changeOfst(1, m_C1ofst);
    1682            0 :    changeOfst(2, m_C2ofst);
    1683              : 
    1684            0 :    changeWvtp(1, "DC");
    1685            0 :    changeWvtp(2, "DC");
    1686              : 
    1687              : 
    1688            0 :    if(m_C1outpOn && m_waveform == "PULSE")
    1689              :    {
    1690            0 :       changeOutp(1, "ON");
    1691              :    }
    1692              :    else
    1693              :    {
    1694            0 :       changeOutp(1, "OFF");
    1695              :    }
    1696            0 :    if(m_C2outpOn && m_waveform == "PULSE")
    1697              :    {
    1698            0 :       changeOutp(2, "ON");
    1699              :    }
    1700              :    else
    1701              :    {
    1702            0 :       changeOutp(2, "OFF");
    1703              :    }
    1704              : 
    1705            0 :    changeWvtp(1, m_waveform);
    1706            0 :    changeWvtp(2, m_waveform);
    1707              : 
    1708            0 :    recordParams(true);
    1709              : 
    1710            0 :    std::cerr << "Done\n";
    1711            0 :    return 0;
    1712            0 : }
    1713              : 
    1714              : inline
    1715            0 : int siglentSDG::changeOutp( int channel,
    1716              :                             const std::string & newOutp
    1717              :                           )
    1718              : {
    1719            0 :    if(channel < 1 || channel > 2) return -1;
    1720              : 
    1721            0 :    std::string no;
    1722              : 
    1723            0 :    if(newOutp == "Off" || newOutp == "OFF" || newOutp == "off") no = "OFF";
    1724            0 :    else if(newOutp == "On" || newOutp == "ON" || newOutp == "on") no = "ON";
    1725              :    else
    1726              :    {
    1727            0 :       log<software_error>({__FILE__, __LINE__, "Invalid OUTP spec: " + newOutp});
    1728            0 :       return -1;
    1729              :    }
    1730              : 
    1731            0 :    std::string afterColon = "OUTP " + no;
    1732            0 :    std::string command = makeCommand(channel, afterColon);
    1733              : 
    1734            0 :    log<text_log>("Ch. " + std::to_string(channel) + " OUTP to " + newOutp, logPrio::LOG_NOTICE);
    1735              : 
    1736            0 :    recordParams(true);
    1737            0 :    int rv = writeCommand(command);
    1738            0 :    recordParams(true);
    1739              : 
    1740            0 :    if(rv < 0)
    1741              :    {
    1742            0 :       if((m_powerState != 1 || m_powerTargetState != 1)) log<software_error>({__FILE__, __LINE__});
    1743            0 :       return -1;
    1744              :    }
    1745              : 
    1746              : 
    1747            0 :    if(channel == 1 && no == "ON")
    1748              :    {
    1749            0 :       if(changeSync(1, true) < 0)
    1750              :       {
    1751            0 :          return log<software_error,-1>({__FILE__, __LINE__});
    1752              :       }
    1753              :    }
    1754            0 :    return 0;
    1755            0 : }
    1756              : 
    1757              : inline
    1758              : int siglentSDG::changeOutp( int channel,
    1759              :                             const pcf::IndiProperty &ipRecv
    1760              :                           )
    1761              : {
    1762              :    if(channel < 1 || channel > 2) return -1;
    1763              : 
    1764              :    if(state() != stateCodes::READY && state() != stateCodes::OPERATING) return 0;
    1765              : 
    1766              :    std::string newOutp;
    1767              :    try
    1768              :    {
    1769              :       newOutp = ipRecv["value"].get<std::string>();
    1770              :    }
    1771              :    catch(...)
    1772              :    {
    1773              :       log<software_error>({__FILE__, __LINE__, "Exception caught."});
    1774              :       return -1;
    1775              :    }
    1776              : 
    1777              :    //Make sure we don't change things while other things are being updated.
    1778              :    std::lock_guard<std::mutex> guard(m_indiMutex);  //Lock the mutex before conducting any communications.
    1779              : 
    1780              :    stateCodes::stateCodeT enterState = state();
    1781              :    state(stateCodes::CONFIGURING);
    1782              : 
    1783              :    int rv = changeOutp(channel, newOutp);
    1784              :    if(rv < 0) log<software_error>({__FILE__, __LINE__});
    1785              : 
    1786              :    state(enterState);
    1787              : 
    1788              :    return rv;
    1789              : }
    1790              : 
    1791              : inline
    1792            0 : int siglentSDG::changeFreq( int channel,
    1793              :                             double newFreq
    1794              :                           )
    1795              : {
    1796            0 :    if(channel < 1 || channel > 2) return -1;
    1797              : 
    1798            0 :    if(newFreq > m_maxFreq.back())
    1799              :    {
    1800            0 :       newFreq = m_maxFreq.back();
    1801              :    }
    1802              : 
    1803            0 :    if(newFreq < 0)
    1804              :    {
    1805            0 :       newFreq = 0;
    1806              :    }
    1807              : 
    1808            0 :    if(m_waveform != "PULSE"){
    1809              :       // Do not limit amp if a PULSE wave
    1810              : 
    1811            0 :       double amp = m_C1vpp_tgt;
    1812            0 :       if(channel == 2) amp = m_C2vpp_tgt;
    1813              : 
    1814            0 :       size_t i =0;
    1815            0 :       while( i < m_ampMax.size())
    1816              :       {
    1817            0 :          if(m_maxFreq[i] >= newFreq) break;
    1818            0 :          ++i;
    1819              :       }
    1820              : 
    1821            0 :       std::cerr << "Max Amp @ " << amp << " = " << m_ampMax[i] << " (freq)\n";
    1822              : 
    1823            0 :       if( amp > m_ampMax[i] )
    1824              :       {
    1825            0 :          log<text_log>("Ch. " + std::to_string(channel) + " FREQ not set due to amplitude exceeding limit for " + std::to_string(newFreq), logPrio::LOG_WARNING);
    1826            0 :          return 0;
    1827              :       }
    1828              : 
    1829              :    }
    1830              : 
    1831              :    //Now we update target
    1832            0 :    if(channel==1)
    1833              :    {
    1834            0 :       m_C1frequency_tgt = newFreq;
    1835              :    }
    1836              :    else
    1837              :    {
    1838            0 :       m_C2frequency_tgt = newFreq;
    1839              :    }
    1840              : 
    1841              : 
    1842            0 :    std::string afterColon = "BSWV FRQ," + mx::ioutils::convertToString<double>(newFreq);
    1843            0 :    std::string command = makeCommand(channel, afterColon);
    1844              : 
    1845            0 :    log<text_log>("Ch. " + std::to_string(channel) + " FREQ to " + std::to_string(newFreq), logPrio::LOG_NOTICE);
    1846              : 
    1847            0 :    recordParams(true);
    1848            0 :    int rv = writeCommand(command);
    1849            0 :    recordParams(true);
    1850              : 
    1851            0 :    if(rv < 0)
    1852              :    {
    1853            0 :       if((m_powerState != 1 || m_powerTargetState != 1)) log<software_error>({__FILE__, __LINE__});
    1854            0 :       return -1;
    1855              :    }
    1856              : 
    1857              :    // we want to automatically set the pulse width when setting a new frequency
    1858            0 :    if(m_waveform == "PULSE"){
    1859              :       // we want to auto change the pulse duration, want either 0.000250 or 0.5%
    1860            0 :       double wdthLim = 0.5 / newFreq ;         // this is the limit if we don't have long enough frequencies
    1861            0 :       double wdth250 = 0.000250;  // this is the ideal length of low dip WHACK THINGS.. it's doubling, want to be 0.00025
    1862            0 :       double newWdth = wdthLim;
    1863              : 
    1864            0 :       if(wdthLim > wdth250){
    1865            0 :          newWdth = wdth250;
    1866            0 :          log<text_log>("Ch. " + std::to_string(channel) + " WDTH auto-changing to duty cycle limit: " + std::to_string(newWdth), logPrio::LOG_NOTICE);
    1867              :       }else{
    1868            0 :          log<text_log>("Ch. " + std::to_string(channel) + " WDTH auto-changing to 250us ideal case: " + std::to_string(newWdth), logPrio::LOG_NOTICE);
    1869              :       }
    1870              : 
    1871              :       //changing pulse width
    1872            0 :       changeWdth(channel, newWdth);
    1873              :    }
    1874              : 
    1875            0 :    return 0;
    1876            0 : }
    1877              : 
    1878              : inline
    1879              : int siglentSDG::changeFreq( int channel,
    1880              :                             const pcf::IndiProperty &ipRecv
    1881              :                           )
    1882              : {
    1883              :    if(channel < 1 || channel > 2) return -1;
    1884              : 
    1885              :    if(state() != stateCodes::READY && state() != stateCodes::OPERATING) return 0;
    1886              : 
    1887              :    double newFreq;
    1888              :    try
    1889              :    {
    1890              :       newFreq = ipRecv["target"].get<double>();
    1891              :    }
    1892              :    catch(...)
    1893              :    {
    1894              :       log<software_error>({__FILE__, __LINE__, "Exception caught."});
    1895              :       return -1;
    1896              :    }
    1897              : 
    1898              :    //Make sure we don't change things while other things are being updated.
    1899              :    std::lock_guard<std::mutex> guard(m_indiMutex);  //Lock the mutex before conducting any communications.
    1900              :    stateCodes::stateCodeT enterState = state();
    1901              :    state(stateCodes::CONFIGURING);
    1902              : 
    1903              :    int rv = changeFreq(channel,newFreq);
    1904              :    if(rv < 0) log<software_error>({__FILE__, __LINE__});
    1905              : 
    1906              :    state(enterState);
    1907              : 
    1908              :    return rv;
    1909              : }
    1910              : 
    1911              : inline
    1912            0 : int siglentSDG::changeAmp( int channel,
    1913              :                            double newAmp
    1914              :                          )
    1915              : {
    1916            0 :    if(channel < 1 || channel > 2) return -1;
    1917              : 
    1918            0 :    double offst = m_C1ofst;
    1919            0 :    if(channel == 2) offst = m_C2ofst;
    1920              : 
    1921            0 :    double confAmpMax = m_C1ampMax;
    1922            0 :    if(channel == 2) confAmpMax = m_C2ampMax;
    1923              : 
    1924            0 :    if (0.5 * newAmp + offst > confAmpMax)
    1925              :    {
    1926            0 :       newAmp = 2 * (confAmpMax - offst);
    1927            0 :       log<text_log>("Ch. " + std::to_string(channel) + " AMP max-limited by config value to " + std::to_string(newAmp), logPrio::LOG_WARNING);
    1928              : 
    1929              :    }
    1930              : 
    1931              :    // Do not limit freq if a PULSE wave
    1932            0 :    if(m_waveform != "PULSE")
    1933              :    {
    1934              : 
    1935              :       //Ensure we won't excede the 0-10V range for SINE
    1936            0 :       if(offst + 0.5*newAmp > 10)
    1937              :       {
    1938            0 :          newAmp = 2.*(10.0 - offst);
    1939            0 :          log<text_log>("Ch. " + std::to_string(channel) + " AMP limited at 10 V by OFST to " + std::to_string(newAmp), logPrio::LOG_WARNING);
    1940              :       }
    1941              : 
    1942            0 :       if(offst - 0.5*newAmp < 0)
    1943              :       {
    1944            0 :          newAmp = 2*(offst);
    1945            0 :          log<text_log>("Ch. " + std::to_string(channel) + " AMP limited at 0 V by OFST to " + std::to_string(newAmp), logPrio::LOG_WARNING);
    1946              :       }
    1947              : 
    1948            0 :       double freq = m_C1frequency_tgt;
    1949            0 :       if(channel == 2) freq = m_C2frequency_tgt;
    1950              : 
    1951              :       double ampMax;
    1952            0 :       size_t i=0;
    1953            0 :       while(i < m_ampMax.size())
    1954              :       {
    1955            0 :          if( m_maxFreq[i] >= freq ) break;
    1956            0 :          ++i;
    1957              :       }
    1958              : 
    1959            0 :       std::cerr << "Max Amp @ " << freq << " = " << ampMax << "\n";
    1960              : 
    1961              :       //Ensure we don't exced safe ranges for device
    1962            0 :       if(newAmp > ampMax)
    1963              :       {
    1964            0 :          newAmp = ampMax;
    1965            0 :          log<text_log>("Ch. " + std::to_string(channel) + " AMP max-limited to " + std::to_string(newAmp), logPrio::LOG_WARNING);
    1966              :       }
    1967              : 
    1968            0 :       if(newAmp < 0)
    1969              :       {
    1970            0 :          newAmp = 0;
    1971            0 :          log<text_log>("Ch. " + std::to_string(channel) + " AMP min-limited to " + std::to_string(newAmp), logPrio::LOG_WARNING);
    1972              :       }
    1973              :    }
    1974              : 
    1975              :    //Now update target
    1976            0 :    if(channel==1)
    1977              :    {
    1978            0 :       m_C1vpp_tgt = newAmp;
    1979              :    }
    1980              :    else
    1981              :    {
    1982            0 :       m_C2vpp_tgt = newAmp;
    1983              :    }
    1984              : 
    1985              : 
    1986            0 :    std::string afterColon = "BSWV AMP," + mx::ioutils::convertToString<double>(newAmp);
    1987            0 :    std::string command = makeCommand(channel, afterColon);
    1988              : 
    1989            0 :    log<text_log>("Ch. " + std::to_string(channel) + " AMP set to " + std::to_string(newAmp), logPrio::LOG_NOTICE);
    1990              : 
    1991            0 :    recordParams(true);
    1992            0 :    int rv = writeCommand(command);
    1993            0 :    recordParams(true);
    1994              : 
    1995            0 :    if(rv < 0)
    1996              :    {
    1997            0 :       if((m_powerState != 1 || m_powerTargetState != 1)) log<software_error>({__FILE__, __LINE__});
    1998            0 :       return -1;
    1999              :    }
    2000              : 
    2001            0 :    return 0;
    2002            0 : }
    2003              : 
    2004              : inline
    2005              : int siglentSDG::changeAmp( int channel,
    2006              :                            const pcf::IndiProperty &ipRecv
    2007              :                          )
    2008              : {
    2009              :    if(channel < 1 || channel > 2) return -1;
    2010              : 
    2011              :    if(state() != stateCodes::READY && state() != stateCodes::OPERATING) return 0;
    2012              : 
    2013              :    double newAmp;
    2014              :    try
    2015              :    {
    2016              :       newAmp = ipRecv["target"].get<double>();
    2017              :    }
    2018              :    catch(...)
    2019              :    {
    2020              :       log<software_error>({__FILE__, __LINE__, "Exception caught."});
    2021              :       return -1;
    2022              :    }
    2023              : 
    2024              :    //Make sure we don't change things while other things are being updated.
    2025              :    std::lock_guard<std::mutex> guard(m_indiMutex);  //Lock the mutex before conducting any communications.
    2026              : 
    2027              :    stateCodes::stateCodeT enterState = state();
    2028              :    state(stateCodes::CONFIGURING);
    2029              : 
    2030              :    int rv = changeAmp(channel, newAmp);
    2031              :    if(rv < 0) log<software_error>({__FILE__, __LINE__});
    2032              : 
    2033              :    state(enterState);
    2034              : 
    2035              :    return rv;
    2036              : }
    2037              : 
    2038              : inline
    2039            0 : int siglentSDG::changeOfst( int channel,
    2040              :                             double newOfst
    2041              :                           )
    2042              : {
    2043            0 :    if(channel < 1 || channel > 2) return -1;
    2044              : 
    2045            0 :    double amp = m_C1vpp;
    2046            0 :    if(channel == 2) amp = m_C2vpp;
    2047              : 
    2048            0 :    double ampMax = m_C1ampMax;
    2049            0 :    if(channel == 2) ampMax = m_C2ampMax;
    2050              : 
    2051              : 
    2052            0 :    if(newOfst + 0.5*amp > ampMax)
    2053              :    {
    2054            0 :       newOfst = ampMax - 0.5*amp;
    2055            0 :       log<text_log>("Ch. " + std::to_string(channel) + " OFST limited at " + std::to_string(ampMax) + " V by AMP to " + std::to_string(newOfst), logPrio::LOG_WARNING);
    2056              :    }
    2057              : 
    2058            0 :    if(newOfst - 0.5*amp < 0)
    2059              :    {
    2060            0 :       newOfst = 0.5*amp;
    2061            0 :       log<text_log>("Ch. " + std::to_string(channel) + " OFST limited at 0 V by AMP to " + std::to_string(newOfst), logPrio::LOG_WARNING);
    2062              :    }
    2063              : 
    2064            0 :    if(newOfst > cs_MaxOfst)
    2065              :    {
    2066            0 :       newOfst = cs_MaxOfst;
    2067            0 :       log<text_log>("Ch. " + std::to_string(channel) + " OFST max-limited to " + std::to_string(newOfst), logPrio::LOG_WARNING);
    2068              :    }
    2069              : 
    2070            0 :    if(newOfst < 0.0)
    2071              :    {
    2072            0 :       newOfst = 0.0;
    2073            0 :       log<text_log>("Ch. " + std::to_string(channel) + " OFST min-limited to " + std::to_string(newOfst), logPrio::LOG_WARNING);
    2074              :    }
    2075              : 
    2076            0 :    std::string afterColon = "BSWV OFST," + mx::ioutils::convertToString<double>(newOfst);
    2077            0 :    std::string command = makeCommand(channel, afterColon);
    2078              : 
    2079            0 :    log<text_log>("Ch. " + std::to_string(channel) + " OFST set to " + std::to_string(newOfst), logPrio::LOG_NOTICE);
    2080              : 
    2081            0 :    int rv = writeCommand(command);
    2082              : 
    2083            0 :    if(rv < 0)
    2084              :    {
    2085            0 :       if((m_powerState != 1 || m_powerTargetState != 1)) log<software_error>({__FILE__, __LINE__});
    2086            0 :       return -1;
    2087              :    }
    2088              : 
    2089            0 :    return 0;
    2090            0 : }
    2091              : 
    2092              : inline
    2093              : int siglentSDG::changeOfst( int channel,
    2094              :                             const pcf::IndiProperty &ipRecv
    2095              :                           )
    2096              : {
    2097              :    if(channel < 1 || channel > 2) return -1;
    2098              : 
    2099              :    if(state() != stateCodes::READY && state() != stateCodes::OPERATING) return 0;
    2100              : 
    2101              :    double newOfst;
    2102              :    try
    2103              :    {
    2104              :       newOfst = ipRecv["value"].get<double>();
    2105              :    }
    2106              :    catch(...)
    2107              :    {
    2108              :       log<software_error>({__FILE__, __LINE__, "Exception caught."});
    2109              :       return -1;
    2110              :    }
    2111              : 
    2112              :    //Make sure we don't change things while other things are being updated.
    2113              :    std::lock_guard<std::mutex> guard(m_indiMutex);  //Lock the mutex before conducting any communications.
    2114              : 
    2115              :    stateCodes::stateCodeT enterState = state();
    2116              :    state(stateCodes::CONFIGURING);
    2117              : 
    2118              :    int rv = changeOfst(channel, newOfst);
    2119              :    if(rv < 0) log<software_error>({__FILE__, __LINE__});
    2120              : 
    2121              :    state(enterState);
    2122              : 
    2123              :    return rv;
    2124              : }
    2125              : 
    2126              : inline
    2127            0 : int siglentSDG::changePhse( int channel,
    2128              :                             double newPhse
    2129              :                           )
    2130              : {
    2131            0 :    if(channel < 1 || channel > 2) return -1;
    2132              : 
    2133            0 :    if(m_waveform == "PULSE"){
    2134            0 :       log<text_log>("Ch. " + std::to_string(channel) + " PHSE not set for PULSE waveform.", logPrio::LOG_WARNING);
    2135            0 :       return 0;
    2136              :    }
    2137              : 
    2138            0 :    std::string afterColon = "BSWV PHSE," + mx::ioutils::convertToString<double>(newPhse);
    2139            0 :    std::string command = makeCommand(channel, afterColon);
    2140              : 
    2141            0 :    log<text_log>("Ch. " + std::to_string(channel) + " PHSE to " + std::to_string(newPhse), logPrio::LOG_NOTICE);
    2142              : 
    2143            0 :    int rv = writeCommand(command);
    2144              : 
    2145            0 :    if(rv < 0)
    2146              :    {
    2147            0 :       if((m_powerState != 1 || m_powerTargetState != 1)) log<software_error>({__FILE__, __LINE__});
    2148            0 :       return -1;
    2149              :    }
    2150              : 
    2151            0 :    return 0;
    2152            0 : }
    2153              : 
    2154              : inline
    2155              : int siglentSDG::changePhse( int channel,
    2156              :                             const pcf::IndiProperty &ipRecv
    2157              :                           )
    2158              : {
    2159              :    if(channel < 1 || channel > 2) return -1;
    2160              : 
    2161              :    if(state() != stateCodes::READY && state() != stateCodes::OPERATING) return 0;
    2162              : 
    2163              :    double newPhse;
    2164              :    try
    2165              :    {
    2166              :       newPhse = ipRecv["value"].get<double>();
    2167              :    }
    2168              :    catch(...)
    2169              :    {
    2170              :       log<software_error>({__FILE__, __LINE__, "Exception caught."});
    2171              :       return -1;
    2172              :    }
    2173              : 
    2174              :    //Make sure we don't change things while other things are being updated.
    2175              :    std::lock_guard<std::mutex> guard(m_indiMutex);  //Lock the mutex before conducting any communications.
    2176              : 
    2177              :    stateCodes::stateCodeT enterState = state();
    2178              :    state(stateCodes::CONFIGURING);
    2179              : 
    2180              :    int rv = changePhse(channel, newPhse);
    2181              :    if(rv < 0) log<software_error>({__FILE__, __LINE__});
    2182              : 
    2183              :    state(enterState);
    2184              : 
    2185              :    return rv;
    2186              : }
    2187              : 
    2188              : inline
    2189            0 : int siglentSDG::changeWdth( int channel,
    2190              :                             double newWdth
    2191              :                           )
    2192              : {
    2193            0 :    if(channel < 1 || channel > 2) return -1;
    2194              : 
    2195            0 :    if(m_waveform != "PULSE"){
    2196            0 :       log<text_log>("Ch. " + std::to_string(channel) + " WDTH can not be set, waveforem not PULSE.", logPrio::LOG_WARNING);
    2197            0 :       return 0;
    2198              :    }
    2199              : 
    2200            0 :    std::string afterColon = "BSWV WIDTH," + mx::ioutils::convertToString<double>(newWdth);
    2201            0 :    std::string command = makeCommand(channel, afterColon);
    2202              : 
    2203            0 :    log<text_log>("Ch. " + std::to_string(channel) + " WDTH to " + std::to_string(newWdth), logPrio::LOG_NOTICE);
    2204              : 
    2205            0 :    int rv = writeCommand(command);
    2206              : 
    2207            0 :    if(rv < 0)
    2208              :    {
    2209            0 :       if((m_powerState != 1 || m_powerTargetState != 1)) log<software_error>({__FILE__, __LINE__});
    2210            0 :       return -1;
    2211              :    }
    2212              : 
    2213            0 :    return 0;
    2214            0 : }
    2215              : 
    2216              : inline
    2217              : int siglentSDG::changeWdth( int channel,
    2218              :                             const pcf::IndiProperty &ipRecv
    2219              :                           )
    2220              : {
    2221              :    if(channel < 1 || channel > 2) return -1;
    2222              : 
    2223              :    if(state() != stateCodes::READY && state() != stateCodes::OPERATING) return 0;
    2224              : 
    2225              :    double newWdth;
    2226              :    try
    2227              :    {
    2228              :       newWdth = ipRecv["value"].get<double>();
    2229              :    }
    2230              :    catch(...)
    2231              :    {
    2232              :       log<software_error>({__FILE__, __LINE__, "Exception caught."});
    2233              :       return -1;
    2234              :    }
    2235              : 
    2236              :    //Make sure we don't change things while other things are being updated.
    2237              :    std::lock_guard<std::mutex> guard(m_indiMutex);  //Lock the mutex before conducting any communications.
    2238              : 
    2239              :    stateCodes::stateCodeT enterState = state();
    2240              :    state(stateCodes::CONFIGURING);
    2241              : 
    2242              :    int rv = changeWdth(channel, newWdth);
    2243              :    if(rv < 0) log<software_error>({__FILE__, __LINE__});
    2244              : 
    2245              :    state(enterState);
    2246              : 
    2247              :    return rv;
    2248              : }
    2249              : 
    2250              : 
    2251              : inline
    2252            0 : int siglentSDG::changeWvtp( int channel,
    2253              :                             const std::string & newWvtp
    2254              :                           )
    2255              : {
    2256            0 :    if(channel < 1 || channel > 2) return -1;
    2257              : 
    2258            0 :    std::string afterColon = "BSWV WVTP," + newWvtp;
    2259            0 :    std::string command = makeCommand(channel, afterColon);
    2260              : 
    2261            0 :    log<text_log>("Ch. " + std::to_string(channel) + " WVTP to " + newWvtp, logPrio::LOG_NOTICE);
    2262              : 
    2263            0 :    int rv = writeCommand(command);
    2264              : 
    2265            0 :    if(rv < 0)
    2266              :    {
    2267            0 :       if((m_powerState != 1 || m_powerTargetState != 1)) log<software_error>({__FILE__, __LINE__});
    2268            0 :       return -1;
    2269              :    }
    2270              : 
    2271            0 :    return 0;
    2272            0 : }
    2273              : 
    2274              : inline
    2275              : int siglentSDG::changeWvtp( int channel,
    2276              :                             const pcf::IndiProperty &ipRecv
    2277              :                           )
    2278              : {
    2279              :    if(channel < 1 || channel > 2) return -1;
    2280              : 
    2281              :    if(state() != stateCodes::READY && state() != stateCodes::OPERATING) return 0;
    2282              : 
    2283              :    std::string newWvtp;
    2284              :    try
    2285              :    {
    2286              :       newWvtp = ipRecv["value"].get<std::string>();
    2287              :    }
    2288              :    catch(...)
    2289              :    {
    2290              :       log<software_error>({__FILE__, __LINE__, "Exception caught."});
    2291              :       return -1;
    2292              :    }
    2293              : 
    2294              :    //Make sure we don't change things while other things are being updated.
    2295              :    std::lock_guard<std::mutex> guard(m_indiMutex);  //Lock the mutex before conducting any communications.
    2296              : 
    2297              :    stateCodes::stateCodeT enterState = state();
    2298              :    state(stateCodes::CONFIGURING);
    2299              : 
    2300              :    int rv = changeWvtp(channel, newWvtp);
    2301              :    if(rv < 0) log<software_error>({__FILE__, __LINE__});
    2302              : 
    2303              :    state(enterState);
    2304              : 
    2305              :    return rv;
    2306              : }
    2307              : 
    2308              : inline
    2309            0 : int siglentSDG::changeSync( int channel,
    2310              :                             const bool newSync
    2311              :                           )
    2312              : {
    2313            0 :    if(channel < 1 || channel > 2) return -1;
    2314              : 
    2315            0 :    std::string afterColon = "SYNC ";
    2316            0 :    if(newSync) afterColon += "ON";
    2317            0 :    else afterColon += "OFF";
    2318              : 
    2319            0 :    std::string command = makeCommand(channel, afterColon);
    2320              : 
    2321            0 :    if(newSync) log<text_log>("Ch. " + std::to_string(channel) + " SYNC to ON", logPrio::LOG_NOTICE);
    2322            0 :    else log<text_log>("Ch. " + std::to_string(channel) + " SYNC to OFF", logPrio::LOG_NOTICE);
    2323              : 
    2324            0 :    recordParams(true);
    2325            0 :    int rv = writeCommand(command);
    2326            0 :    recordParams(true);
    2327              : 
    2328            0 :    if(rv < 0)
    2329              :    {
    2330            0 :       if((m_powerState != 1 || m_powerTargetState != 1)) log<software_error>({__FILE__, __LINE__});
    2331            0 :       return -1;
    2332              :    }
    2333              : 
    2334            0 :    return 0;
    2335            0 : }
    2336              : 
    2337              : inline
    2338              : int siglentSDG::changeSync( int channel,
    2339              :                             const pcf::IndiProperty &ipRecv
    2340              :                           )
    2341              : {
    2342              :    if(channel < 1 || channel > 2) return -1;
    2343              : 
    2344              :    if(state() != stateCodes::READY && state() != stateCodes::OPERATING) return 0;
    2345              : 
    2346              :    bool newSync;
    2347              : 
    2348              :    if(!ipRecv.find("toggle")) return 0;
    2349              : 
    2350              :    if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off )
    2351              :    {
    2352              :       newSync = false;
    2353              :    }
    2354              : 
    2355              :    if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On )
    2356              :    {
    2357              :       newSync = true;
    2358              :    }
    2359              : 
    2360              :    //Make sure we don't change things while other things are being updated.
    2361              :    std::lock_guard<std::mutex> guard(m_indiMutex);  //Lock the mutex before conducting any communications.
    2362              : 
    2363              :    stateCodes::stateCodeT enterState = state();
    2364              :    state(stateCodes::CONFIGURING);
    2365              : 
    2366              :    int rv = changeSync(channel, newSync);
    2367              :    if(rv < 0) log<software_error>({__FILE__, __LINE__});
    2368              : 
    2369              :    state(enterState);
    2370              : 
    2371              :    return rv;
    2372              : }
    2373              : 
    2374            3 : INDI_NEWCALLBACK_DEFN(siglentSDG, m_indiP_C1outp)(const pcf::IndiProperty &ipRecv)
    2375              : {
    2376            3 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C1outp, ipRecv);
    2377              : 
    2378              :     return changeOutp(1, ipRecv);
    2379              : 
    2380              : }
    2381              : 
    2382            3 : INDI_NEWCALLBACK_DEFN(siglentSDG, m_indiP_C1freq)(const pcf::IndiProperty &ipRecv)
    2383              : {
    2384            3 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C1freq, ipRecv);
    2385              : 
    2386              :     return changeFreq(1, ipRecv);
    2387              : }
    2388              : 
    2389            3 : INDI_NEWCALLBACK_DEFN(siglentSDG, m_indiP_C1amp)(const pcf::IndiProperty &ipRecv)
    2390              : {
    2391            3 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C1amp, ipRecv);
    2392              : 
    2393              :     return changeAmp(1, ipRecv);
    2394              : }
    2395              : 
    2396            3 : INDI_NEWCALLBACK_DEFN(siglentSDG, m_indiP_C1ofst)(const pcf::IndiProperty &ipRecv)
    2397              : {
    2398            3 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C1ofst, ipRecv);
    2399              : 
    2400              :     return changeOfst(1, ipRecv);
    2401              : }
    2402              : 
    2403            3 : INDI_NEWCALLBACK_DEFN(siglentSDG, m_indiP_C1phse)(const pcf::IndiProperty &ipRecv)
    2404              : {
    2405            3 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C1phse, ipRecv);
    2406              : 
    2407              :     return changePhse(1, ipRecv);
    2408              : }
    2409              : 
    2410            3 : INDI_NEWCALLBACK_DEFN(siglentSDG, m_indiP_C1wdth)(const pcf::IndiProperty &ipRecv)
    2411              : {
    2412            3 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C1wdth, ipRecv);
    2413              : 
    2414              :     return changeWdth(1, ipRecv);
    2415              : }
    2416              : 
    2417            3 : INDI_NEWCALLBACK_DEFN(siglentSDG, m_indiP_C1wvtp)(const pcf::IndiProperty &ipRecv)
    2418              : {
    2419            3 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C1wvtp, ipRecv);
    2420              : 
    2421              :     return changeWvtp(1, ipRecv);
    2422              : }
    2423              : 
    2424            3 : INDI_NEWCALLBACK_DEFN(siglentSDG, m_indiP_C1sync)(const pcf::IndiProperty &ipRecv)
    2425              : {
    2426            3 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C1sync, ipRecv);
    2427              : 
    2428              :     return changeSync(1, ipRecv);
    2429              : }
    2430              : 
    2431            3 : INDI_NEWCALLBACK_DEFN(siglentSDG, m_indiP_C2outp)(const pcf::IndiProperty &ipRecv)
    2432              : {
    2433            3 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C2outp, ipRecv);
    2434              : 
    2435              :     return changeOutp(2, ipRecv);
    2436              : }
    2437              : 
    2438            3 : INDI_NEWCALLBACK_DEFN(siglentSDG, m_indiP_C2freq)(const pcf::IndiProperty &ipRecv)
    2439              : {
    2440            3 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C2freq, ipRecv);
    2441              : 
    2442              :     return changeFreq(2, ipRecv);
    2443              : }
    2444              : 
    2445            3 : INDI_NEWCALLBACK_DEFN(siglentSDG, m_indiP_C2amp)(const pcf::IndiProperty &ipRecv)
    2446              : {
    2447            3 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C2amp, ipRecv);
    2448              : 
    2449              :     return changeAmp(2, ipRecv);
    2450              : }
    2451              : 
    2452            3 : INDI_NEWCALLBACK_DEFN(siglentSDG, m_indiP_C2ofst)(const pcf::IndiProperty &ipRecv)
    2453              : {
    2454            3 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C2ofst, ipRecv);
    2455              : 
    2456              :     return changeOfst(2, ipRecv);
    2457              : }
    2458              : 
    2459            3 : INDI_NEWCALLBACK_DEFN(siglentSDG, m_indiP_C2phse)(const pcf::IndiProperty &ipRecv)
    2460              : {
    2461            3 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C2phse, ipRecv);
    2462              : 
    2463              :     return changePhse(2, ipRecv);
    2464              : }
    2465              : 
    2466            3 : INDI_NEWCALLBACK_DEFN(siglentSDG, m_indiP_C2wdth)(const pcf::IndiProperty &ipRecv)
    2467              : {
    2468            3 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C2wdth, ipRecv);
    2469              : 
    2470              :     return changeWdth(2, ipRecv);
    2471              : }
    2472              : 
    2473            3 : INDI_NEWCALLBACK_DEFN(siglentSDG, m_indiP_C2wvtp)(const pcf::IndiProperty &ipRecv)
    2474              : {
    2475            3 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C2wvtp, ipRecv);
    2476              : 
    2477              :     return changeWvtp(2, ipRecv);
    2478              : }
    2479              : 
    2480            3 : INDI_NEWCALLBACK_DEFN(siglentSDG, m_indiP_C2sync)(const pcf::IndiProperty &ipRecv)
    2481              : {
    2482            3 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C2sync, ipRecv);
    2483              : 
    2484              :     return changeSync(2, ipRecv);
    2485              : }
    2486              : 
    2487              : // todo: add change width INDI
    2488              : 
    2489              : // todo: add change edge INDI
    2490              : 
    2491              : inline
    2492            0 : int siglentSDG::checkRecordTimes()
    2493              : {
    2494            0 :    return telemeter<siglentSDG>::checkRecordTimes(telem_fxngen());
    2495              : }
    2496              : 
    2497              : inline
    2498            0 : int siglentSDG::recordTelem( const telem_fxngen * )
    2499              : {
    2500            0 :    return recordParams(true);
    2501              : }
    2502              : 
    2503              : inline
    2504            0 : int siglentSDG::recordParams(bool force)
    2505              : {
    2506              :    static double old_C1outp = -1e30; //Ensure first time writes
    2507            0 :    static double old_C1frequency = m_C1frequency;
    2508            0 :    static double old_C1vpp = m_C1vpp;
    2509            0 :    static double old_C1ofst = m_C1ofst;
    2510            0 :    static double old_C1phse = m_C1phse;
    2511            0 :    static double old_C1wdth = m_C1wdth;
    2512            0 :    static std::string old_C1wvtp = m_C1wvtp;
    2513            0 :    static bool old_C1sync = m_C1sync;
    2514            0 :    static double old_C2outp = m_C2outp;
    2515            0 :    static double old_C2frequency = m_C2frequency;
    2516            0 :    static double old_C2vpp = m_C2vpp;
    2517            0 :    static double old_C2ofst = m_C2ofst;
    2518            0 :    static double old_C2phse = m_C2phse;
    2519            0 :    static double old_C2wdth = m_C2wdth;
    2520            0 :    static std::string old_C2wvtp = m_C2wvtp;
    2521            0 :    static bool old_C2sync = m_C2sync;
    2522              : 
    2523            0 :    bool write = false;
    2524              : 
    2525            0 :    if(!force)
    2526              :    {
    2527            0 :       if( old_C1outp != m_C1outp ) write = true;
    2528            0 :       else if( old_C1frequency != m_C1frequency ) write = true;
    2529            0 :       else if( old_C1vpp != m_C1vpp ) write = true;
    2530            0 :       else if( old_C1ofst != m_C1ofst ) write = true;
    2531            0 :       else if( old_C1phse != m_C1phse ) write = true;
    2532            0 :       else if( old_C1wdth != m_C1wdth ) write = true;
    2533            0 :       else if( old_C1wvtp != m_C1wvtp ) write = true;
    2534            0 :       else if( old_C1sync != m_C1sync ) write = true;
    2535            0 :       else if( old_C2outp != m_C2outp ) write = true;
    2536            0 :       else if( old_C2frequency != m_C2frequency ) write = true;
    2537            0 :       else if( old_C2vpp != m_C2vpp ) write = true;
    2538            0 :       else if( old_C2ofst != m_C2ofst ) write = true;
    2539            0 :       else if( old_C2phse != m_C2phse ) write = true;
    2540            0 :       else if( old_C2wdth != m_C2wdth ) write = true;
    2541            0 :       else if( old_C2wvtp != m_C2wvtp ) write = true;
    2542            0 :       else if( old_C2sync != m_C2sync ) write = true;
    2543              :    }
    2544              : 
    2545              :    // todo: add if statement for all of the write??
    2546              : 
    2547            0 :    if(force || write)
    2548              :    {
    2549            0 :       uint8_t C1wvtp = 3;
    2550            0 :       if(m_C1wvtp == "DC") C1wvtp = TELEM_FXNGEN_WVTP_DC;
    2551            0 :       else if(m_C1wvtp == "SINE") C1wvtp = TELEM_FXNGEN_WVTP_SINE;
    2552            0 :       else if(m_C1wvtp == "PULSE") C1wvtp = TELEM_FXNGEN_WVTP_PULSE;
    2553              : 
    2554            0 :       uint8_t C2wvtp = 3;
    2555            0 :       if(m_C2wvtp == "DC") C2wvtp = TELEM_FXNGEN_WVTP_DC;
    2556            0 :       else if(m_C2wvtp == "SINE") C2wvtp = TELEM_FXNGEN_WVTP_SINE;
    2557            0 :       else if(m_C2wvtp == "PULSE") C2wvtp = TELEM_FXNGEN_WVTP_PULSE;
    2558              : 
    2559            0 :       telem<telem_fxngen>({m_C1outp, m_C1frequency, m_C1vpp, m_C1ofst, m_C1phse, C1wvtp,
    2560            0 :                              m_C2outp, m_C2frequency, m_C2vpp, m_C2ofst, m_C2phse, C2wvtp,
    2561            0 :                                 m_C1sync, m_C2sync, m_C1wdth, m_C2wdth});
    2562              : 
    2563            0 :       old_C1outp = m_C1outp;
    2564            0 :       old_C1frequency = m_C1frequency;
    2565            0 :       old_C1vpp = m_C1vpp;
    2566            0 :       old_C1ofst = m_C1ofst;
    2567            0 :       old_C1phse = m_C1phse;
    2568            0 :       old_C1wdth = m_C1wdth;
    2569            0 :       old_C1wvtp = m_C1wvtp;
    2570            0 :       old_C1sync = m_C1sync;
    2571              : 
    2572            0 :       old_C2outp = m_C2outp;
    2573            0 :       old_C2frequency = m_C2frequency;
    2574            0 :       old_C2vpp = m_C2vpp;
    2575            0 :       old_C2ofst = m_C2ofst;
    2576            0 :       old_C2phse = m_C2phse;
    2577            0 :       old_C2wdth = m_C2wdth;
    2578            0 :       old_C2wvtp = m_C2wvtp;
    2579            0 :       old_C2sync = m_C2sync;
    2580              :    }
    2581              : 
    2582            0 :    return 0;
    2583              : }
    2584              : 
    2585              : } //namespace app
    2586              : } //namespace MagAOX
    2587              : 
    2588              : #endif //siglentSDG_hpp
        

Generated by: LCOV version 2.0-1