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

            Line data    Source code
       1              : 
       2              : 
       3              : #ifndef ttmModulator_hpp
       4              : #define ttmModulator_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              : 
      11              : #define MODSTATE_UNKNOWN (-1)
      12              : #define MODSTATE_OFF (0)
      13              : #define MODSTATE_REST (1)
      14              : #define MODSTATE_MIDSET (2)
      15              : #define MODSTATE_SET (3)
      16              : #define MODSTATE_MODULATING (4)
      17              : 
      18              : namespace MagAOX
      19              : {
      20              : namespace app
      21              : {
      22              : 
      23              : /** MagAO-X application to control TTM modulation
      24              :   *
      25              :   * \todo need tests fo ttmModulator
      26              :   */
      27              : class ttmModulator : public MagAOXApp<>
      28              : {
      29              : 
      30              : protected:
      31              : 
      32              :    /** \name Configurable Parameters
      33              :      * @{
      34              :      */
      35              : 
      36              :    double m_maxFreq {3000.0}; ///< The maximum modulation frequency settable by this program
      37              :    double m_maxVolt {1.2801}; ///< The maximum modulation voltage settable by this program
      38              : 
      39              :    double m_setVoltage_1 {5.0}; ///< the set position voltage of Ch. 1.
      40              :    double m_setVoltage_2 {5.0}; ///< the set position voltage of Ch. 2.
      41              : 
      42              :    double m_setDVolts {1.0}; ///< The setting ramp step size [volts].
      43              : 
      44              :    double m_modDFreq {500}; ///< The modulation ramp frequency step size [Hz].
      45              :    double m_modDVolts {0.5}; ///< The modulation ramp voltage step size [Volts].
      46              : 
      47              :    double m_rotAngle {0};
      48              :    double m_rotParity {1};
      49              : 
      50              :    ///@}
      51              : 
      52              :    int m_modState {MODSTATE_UNKNOWN}; ///< -1 = unknown, 0 = off, 1 = rest, 2 = midset, 3 = set, 4 = modulating
      53              :    int m_modStateRequested {MODSTATE_UNKNOWN};  ///< The requested TTM state
      54              :    double m_modRad {0}; ///< The current modulation radius, in lam/D.
      55              :    double m_modRadRequested {-1}; ///< The requested modulation radius, in lam/D.
      56              :    double m_modFreq {0}; ///< The current modulation frequency, in Hz.
      57              :    double m_modFreqRequested {-1}; ///< The requested modulation frequency, in Hz.
      58              : 
      59              : 
      60              :    int m_C1outp {-1};     ///< Output state of fxn gen channel 1.
      61              :    double m_C1freq {-1};  ///< Frequency of fxn gen channel 1.
      62              :    double m_C1volts {-1}; ///< Voltage p2p of fxn gen channel 1.
      63              :    double m_C1ofst {-1};  ///< DC offset of fxn gen channel 1.
      64              :    double m_C1phse {-1};  ///< Phase of fxn gen channel 1.
      65              : 
      66              :    int m_C2outp {-1};     ///< Output state of fxn gen channel 2
      67              :    double m_C2freq {-1};  ///< Frequency of fxn gen channel 2.
      68              :    double m_C2volts {-1}; ///< Voltage p2p of fxn gen channel 2.
      69              :    double m_C2ofst {-1};  ///< DC offset of fxn gen channel 2.
      70              :    double m_C2phse {-1};  ///< Phase of fxn gen channel 2.
      71              : 
      72              :    double m_calRadius {1.0};
      73              : 
      74              :    /* Old Cal:
      75              :    std::vector<double> m_calFreqs = {100,400,500,600,700,800,900,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000};
      76              :    std::vector<double> m_calC1Amps = {0.61,0.61,0.57,0.55,0.53,0.51,0.51,0.49,0.46,0.44,0.44,0.43,0.44,0.46,0.49,0.54,0.58,0.62};
      77              :    std::vector<double> m_calC2Amps = {0.6,0.6,0.6,0.57,0.55,0.53,0.51,0.49,0.49,0.49,0.49,0.5,0.52,0.54,0.59,0.64,0.70,0.77};
      78              :    std::vector<double> m_calC2Phse = { 75, 75, 75,  75,  75,  75,  75,  75,  75,  75,  75,  75,  75,  72,  72,  70,  70,  70} ;*/
      79              : 
      80              :    /* Cal on 2022-09-18:
      81              :    std::vector<double> m_calFreqs = { 250,  500,   750,  1000,  1250,  1500,  1750,  2000,  2250,  2500,  2750,  3000,  3250,  3500};
      82              :    std::vector<double> m_calC1Amps = {0.66, 0.62, 0.58,  0.49,  0.44,  0.41,  0.43,  0.41,  0.35,  0.75,  1.0,   1.03,  1.08,  1.58 };
      83              :    std::vector<double> m_calC2Amps = {0.64, 0.61, 0.56, 0.54,   0.55,  0.57,  0.65,  0.78,  0.95,  1.15,   1.15,   2.25,  2.15,  1.97};
      84              :    std::vector<double> m_calC2Phse = {  75, 75,    75,   75,    75,    75,    72,    67,    63,     35,    5,    18,    10,    -40} ; */
      85              : 
      86              :    /* Cal on 2023-12-03 (w. strain gauges ON):*/
      87              :    /*std::vector<double> m_calFreqs =  { 100,  250,  500,  750, 1000, 1250, 1500, 1750, 2000};
      88              :    std::vector<double> m_calC1Amps = {0.22, 0.28, 0.43, 0.61, 0.82, 1.06, 1.35, 1.70, 2.045};
      89              :    std::vector<double> m_calC2Amps = {0.23, 0.23, 0.56, 0.85, 1.16, 1.58, 1.96, 2.60, 3.63};
      90              :    std::vector<double> m_calC2Phse = {  79,   82,   82,   82,   82,   82,   84,   88,   93}; */
      91              : 
      92              :     /* Cal on 2023-12-03 (w. strain gauges OFF):*/
      93              :     std::vector<double> m_calFreqs =  { 100,   250,   500,   750,  1000,  1250,  1500,  1750,  2000,     2250, 2500,  2750, 3000};
      94              :     std::vector<double> m_calC1Amps = {0.310, 0.317, 0.327, 0.327, 0.333, 0.333, 0.343, 0.350, 0.373,    0.39, 0.405, 0.425, 0.435};
      95              :     std::vector<double> m_calC2Amps = {0.313, 0.317, 0.327, 0.340, 0.357, 0.363, 0.380, 0.407, 0.426667, 0.45, 0.475, 0.490, 0.510}; //have to go to this many sig-figs for max voltage reasons
      96              :     std::vector<double> m_calC2Phse = {  74,   74,    74,    74,    74,    71,   71,     68,    68,      68,   68,     68,   68};
      97              : 
      98              : public:
      99              : 
     100              :    /// Default c'tor.
     101              :    ttmModulator();
     102              : 
     103              :    /// D'tor, declared and defined for noexcept.
     104            0 :    ~ttmModulator() noexcept
     105            0 :    {}
     106              : 
     107              :    /// Setup the configuration system (called by MagAOXApp::setup())
     108              :    virtual void setupConfig();
     109              : 
     110              :    /// load the configuration system results (called by MagAOXApp::setup())
     111              :    virtual void loadConfig();
     112              : 
     113              :    /// Startup functions
     114              :    /** Setsup the INDI vars.
     115              :      *
     116              :      * \returns 0 on success
     117              :      * \returns -1 on error.
     118              :      */
     119              :    virtual int appStartup();
     120              : 
     121              :    /// Implementation of the FSM for the TTM Modulator
     122              :    /**
     123              :      * \returns 0 on success
     124              :      * \returns -1 on error.
     125              :      */
     126              :    virtual int appLogic();
     127              : 
     128              :    /// Do any needed shutdown tasks.  Currently nothing in this app.
     129              :    /**
     130              :      * \returns 0 on success
     131              :      * \returns -1 on error.
     132              :      */
     133              :    virtual int appShutdown();
     134              : 
     135              : 
     136              :    /// Calculate the state of the modulator from the fxn gen params.
     137              :    /**
     138              :      * \returns 0 on success
     139              :      * \returns -1 on error.
     140              :      */
     141              :    int calcState();
     142              : 
     143              :    /// Rest the TTM
     144              :    /**
     145              :      * \returns 0 on success
     146              :      * \returns -1 on error.
     147              :      */
     148              :    int restTTM();
     149              : 
     150              :    /// Set the TTM
     151              :    /**
     152              :      * \returns 0 on success
     153              :      * \returns -1 on error.
     154              :      */
     155              :    int setTTM();
     156              : 
     157              :    /// Begin modulating or modify current modulation parameters.
     158              :    /**
     159              :      * \returns 0 on success
     160              :      * \returns -1 on error.
     161              :      */
     162              :    int modTTM( double newRad, ///< The new radius for modulation [lam/D]
     163              :                double newFreq ///< The new frequency for modulation [Hz]
     164              :              );
     165              : 
     166              :    int offset12( double d1,
     167              :                  double d2
     168              :                );
     169              : 
     170              :    int offsetXY( double dx,
     171              :                  double dy
     172              :                );
     173              : 
     174              : protected:
     175              : 
     176              :    //declare our properties
     177              :    pcf::IndiProperty m_indiP_modState;
     178              : 
     179              :    pcf::IndiProperty m_indiP_modRadius;
     180              :    pcf::IndiProperty m_indiP_modFrequency;
     181              : 
     182              :    pcf::IndiProperty m_indiP_offset12;
     183              :    pcf::IndiProperty m_indiP_offset;
     184              : 
     185              : 
     186              :    pcf::IndiProperty m_indiP_FGState;
     187              : 
     188              :    pcf::IndiProperty m_indiP_C1outp;
     189              :    pcf::IndiProperty m_indiP_C1freq;
     190              :    pcf::IndiProperty m_indiP_C1volts;
     191              :    pcf::IndiProperty m_indiP_C1ofst;
     192              :    pcf::IndiProperty m_indiP_C1phse;
     193              : 
     194              :    pcf::IndiProperty m_indiP_C2outp;
     195              :    pcf::IndiProperty m_indiP_C2freq;
     196              :    pcf::IndiProperty m_indiP_C2volts;
     197              :    pcf::IndiProperty m_indiP_C2ofst;
     198              :    pcf::IndiProperty m_indiP_C2phse;
     199              : 
     200              : public:
     201            0 :    INDI_NEWCALLBACK_DECL(ttmModulator, m_indiP_modState);
     202            0 :    INDI_NEWCALLBACK_DECL(ttmModulator, m_indiP_modRadius);
     203            0 :    INDI_NEWCALLBACK_DECL(ttmModulator, m_indiP_modFrequency);
     204            0 :    INDI_NEWCALLBACK_DECL(ttmModulator, m_indiP_offset12);
     205            0 :    INDI_NEWCALLBACK_DECL(ttmModulator, m_indiP_offset);
     206              : 
     207            0 :    INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C1outp);
     208            0 :    INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C1freq);
     209            0 :    INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C1volts);
     210            0 :    INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C1ofst);
     211            0 :    INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C1phse);
     212              : 
     213            0 :    INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C2outp);
     214            0 :    INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C2freq);
     215            0 :    INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C2volts);
     216            0 :    INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C2ofst);
     217            0 :    INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C2phse);
     218              : 
     219              : };
     220              : 
     221              : inline
     222              : ttmModulator::ttmModulator() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
     223              : {
     224              :    m_powerMgtEnabled = true;
     225              :    return;
     226              : }
     227              : 
     228              : inline
     229            0 : void ttmModulator::setupConfig()
     230              : {
     231            0 :    config.add("limits.maxfreq", "", "limits.maxfreq", argType::Required, "limits", "maxfreq", false, "real", "The maximum frequency [Hz] which can be set through this program.");
     232            0 :    config.add("limits.maxamp", "", "limits.maxamp", argType::Required, "limits", "maxamp", false, "real", "The maximum amplitude [lam/D] which can be set throught this program.");
     233              : 
     234            0 :    config.add("cal.voltsperld1", "", "cal.voltsperld1", argType::Required, "cal", "voltsperld1", false, "real", "The voltage per lam/D for channel 1.");
     235            0 :    config.add("cal.voltsperld2", "", "cal.voltsperld2", argType::Required, "cal", "voltsperld2", false, "real", "The voltage per lam/D for channel 2.");
     236            0 :    config.add("cal.phase", "", "cal.phase", argType::Required, "cal", "phase", false, "real", "The axis phase offset, which is applied to channel 2.");
     237              : 
     238            0 :    config.add("cal.setv1", "", "cal.setv1", argType::Required, "cal", "setv1", false, "real", "The set position voltage of chaannel 1.");
     239            0 :    config.add("cal.setv2", "", "cal.setv2", argType::Required, "cal", "setv2", false, "real", "The set position voltage of chaannel 2.");
     240              : 
     241            0 :    config.add("cal.setDvolts", "", "cal.setDvolts", argType::Required, "cal", "setDvolts", false, "real", "The setting ramp step size [Volts]");
     242              : 
     243            0 :    config.add("cal.modDfreq", "", "cal.modDfreq", argType::Required, "cal", "modDfreq", false, "real", "The modulation ramp frequency step size [Hz]");
     244            0 :    config.add("cal.modDvolts", "", "cal.modDvolts", argType::Required, "cal", "modDvolts", false, "real", "The modulation ramp voltage step size [Volts]");
     245              : 
     246            0 :    config.add("cal.rotAngle", "", "cal.rotAngle", argType::Required, "cal", "rotAngle", false, "real", "The offset rotation matrix angle in degrees.");
     247            0 :    config.add("cal.rotParity", "", "cal.rotParity", argType::Required, "cal", "rotParity", false, "real", "The offset rotation matrix parity, +1 or -1.");
     248            0 : }
     249              : 
     250              : inline
     251            0 : void ttmModulator::loadConfig()
     252              : {
     253            0 :    config(m_maxFreq, "limits.maxfreq");
     254              : 
     255            0 :    config(m_setVoltage_1, "cal.setv1");
     256            0 :    config(m_setVoltage_2, "cal.setv2");
     257              : 
     258            0 :    config(m_setDVolts, "cal.setDvolts");
     259            0 :    config(m_modDFreq, "cal.modDfreq");
     260            0 :    config(m_modDVolts, "cal.modDvolts");
     261              : 
     262            0 :    config(m_rotAngle, "cal.rotAngle");
     263            0 :    m_rotAngle = m_rotAngle*3.14159/180.;
     264              : 
     265            0 :    config(m_rotParity, "cal.rotParity");
     266            0 :    if(m_rotParity < 0) m_rotParity = -1;
     267            0 :    else m_rotParity = 1;
     268              : 
     269              : 
     270            0 : }
     271              : 
     272              : inline
     273            0 : int ttmModulator::appStartup()
     274              : {
     275              :    // set up the  INDI properties
     276            0 :    REG_INDI_NEWPROP(m_indiP_modState, "modState", pcf::IndiProperty::Number);
     277            0 :    m_indiP_modState.add (pcf::IndiElement("current"));
     278            0 :    m_indiP_modState.add (pcf::IndiElement("target"));
     279            0 :    m_indiP_modState["current"].set(m_modState);
     280            0 :    m_indiP_modState["target"].set(m_modStateRequested);
     281              : 
     282            0 :    REG_INDI_NEWPROP(m_indiP_modFrequency, "modFrequency", pcf::IndiProperty::Number);
     283            0 :    m_indiP_modFrequency.add (pcf::IndiElement("current"));
     284            0 :    m_indiP_modFrequency.add (pcf::IndiElement("target"));
     285            0 :    m_indiP_modFrequency["current"].set(m_modFreq);
     286            0 :    m_indiP_modFrequency["target"].set(m_modFreqRequested);
     287              : 
     288            0 :    REG_INDI_NEWPROP(m_indiP_modRadius, "modRadius", pcf::IndiProperty::Number);
     289            0 :    m_indiP_modRadius.add (pcf::IndiElement("current"));
     290            0 :    m_indiP_modRadius.add (pcf::IndiElement("target"));
     291            0 :    m_indiP_modRadius["current"].set(m_modRad);
     292            0 :    m_indiP_modRadius["target"].set(m_modRadRequested);
     293              : 
     294            0 :    REG_INDI_NEWPROP(m_indiP_offset12, "offset12", pcf::IndiProperty::Number);
     295            0 :    m_indiP_offset12.add (pcf::IndiElement("dC1"));
     296            0 :    m_indiP_offset12.add (pcf::IndiElement("dC2"));
     297              : 
     298            0 :    REG_INDI_NEWPROP(m_indiP_offset, "offset", pcf::IndiProperty::Number);
     299            0 :    m_indiP_offset.add (pcf::IndiElement("x"));
     300            0 :    m_indiP_offset.add (pcf::IndiElement("y"));
     301              : 
     302            0 :    REG_INDI_SETPROP(m_indiP_C1outp, "fxngenmodwfs", "C1outp");
     303            0 :    REG_INDI_SETPROP(m_indiP_C1freq, "fxngenmodwfs", "C1freq");
     304            0 :    REG_INDI_SETPROP(m_indiP_C1volts, "fxngenmodwfs", "C1amp");
     305            0 :    REG_INDI_SETPROP(m_indiP_C1ofst, "fxngenmodwfs", "C1ofst");
     306            0 :    REG_INDI_SETPROP(m_indiP_C1phse, "fxngenmodwfs", "C1phse");
     307              : 
     308            0 :    REG_INDI_SETPROP(m_indiP_C2outp, "fxngenmodwfs", "C2outp");
     309            0 :    REG_INDI_SETPROP(m_indiP_C2freq, "fxngenmodwfs", "C2freq");
     310            0 :    REG_INDI_SETPROP(m_indiP_C2volts, "fxngenmodwfs", "C2amp");
     311            0 :    REG_INDI_SETPROP(m_indiP_C2ofst, "fxngenmodwfs", "C2ofst");
     312            0 :    REG_INDI_SETPROP(m_indiP_C2phse, "fxngenmodwfs", "C2phse");
     313              : 
     314            0 :    return 0;
     315              : }
     316              : 
     317              : inline
     318            0 : int ttmModulator::appLogic()
     319              : {
     320            0 :    if(state()==stateCodes::POWEROFF) return 0;
     321              : 
     322            0 :    if(state()==stateCodes::POWERON)
     323              :    {
     324            0 :       sleep(2);
     325              :    }
     326              : 
     327            0 :    if( calcState() < 0 )
     328              :    {
     329              :       //application failure if we can't determine state
     330            0 :       log<software_critical>({__FILE__,__LINE__});
     331            0 :       return -1;
     332              :    }
     333              : 
     334            0 :    if(m_modState == MODSTATE_REST)
     335              :    {
     336            0 :       state(stateCodes::NOTHOMED);
     337            0 :       if(!stateLogged()) log<ttmmod_params>({(uint8_t) m_modState, m_modFreq, m_modRad, 0,0});
     338              :    }
     339            0 :    else if(m_modState == MODSTATE_SET)
     340              :    {
     341            0 :       state(stateCodes::READY);
     342            0 :       if(!stateLogged()) log<ttmmod_params>({(uint8_t) m_modState, m_modFreq, m_modRad, 0,0});
     343              :    }
     344            0 :    else if(m_modState == MODSTATE_MIDSET)
     345              :    {
     346            0 :       state(stateCodes::ERROR);
     347            0 :       if(!stateLogged()) log<ttmmod_params>({(uint8_t) m_modState, m_modFreq, m_modRad, 0,0});
     348              :    }
     349            0 :    else if(m_modState == MODSTATE_MODULATING)
     350              :    {
     351            0 :       state(stateCodes::OPERATING);
     352            0 :       if(!stateLogged()) log<ttmmod_params>({(uint8_t) m_modState, m_modFreq, m_modRad, 0,0});
     353              :    }
     354              : 
     355              :    { //mutex scope
     356            0 :       std::lock_guard<std::mutex> lock(m_indiMutex);
     357            0 :       updateIfChanged(m_indiP_modState, "current", m_modState);
     358            0 :       updateIfChanged(m_indiP_modState, "target", m_modStateRequested);
     359            0 :       updateIfChanged(m_indiP_modRadius, "current", m_modRad);
     360            0 :       updateIfChanged(m_indiP_modRadius, "target", m_modRadRequested);
     361            0 :       updateIfChanged(m_indiP_modFrequency, "current", m_modFreq);
     362            0 :       updateIfChanged(m_indiP_modFrequency, "target", m_modFreqRequested);
     363            0 :    }
     364              : 
     365              :    //This is set by an INDI newProperty
     366            0 :    if(m_modStateRequested > 0)
     367              :    {
     368              :       //Step 0: change the requested state to match, so a new request while we're
     369              :       //        processing gets handled.
     370              : 
     371            0 :       std::unique_lock<std::mutex> lock(m_indiMutex);
     372            0 :       int newState = m_modStateRequested;
     373            0 :       double newRad = m_modRadRequested;
     374            0 :       double newFreq = m_modFreqRequested;
     375              : 
     376            0 :       m_modStateRequested = MODSTATE_OFF;
     377              : 
     378            0 :       lock.unlock();
     379              : 
     380            0 :       state(stateCodes::CONFIGURING);
     381            0 :       if(newState == MODSTATE_REST) restTTM();
     382            0 :       if(newState == MODSTATE_SET) setTTM();
     383            0 :       if(newState == MODSTATE_MODULATING)
     384              :       {
     385            0 :          if(newRad <= 0.1 || newFreq <= 1)
     386              :          {
     387            0 :             log<text_log>("radius or frequency too low", logPrio::LOG_ERROR);
     388              :          }
     389              :          else
     390              :          {
     391            0 :             modTTM(newRad, newFreq);
     392              :          }
     393              :       }
     394            0 :       calcState();
     395              : 
     396              :       //Do this now for responsiveness.
     397            0 :       if(m_modState == MODSTATE_REST)
     398              :       {
     399            0 :          state(stateCodes::NOTHOMED);
     400            0 :          if(!stateLogged()) log<ttmmod_params>({(uint8_t) m_modState, m_modFreq, m_modRad, 0,0});
     401              :       }
     402            0 :       else if(m_modState == MODSTATE_SET)
     403              :       {
     404            0 :          state(stateCodes::READY);
     405            0 :          if(!stateLogged()) log<ttmmod_params>({(uint8_t) m_modState, m_modFreq, m_modRad, 0,0});
     406              :       }
     407            0 :       else if(m_modState == MODSTATE_MIDSET)
     408              :       {
     409            0 :          state(stateCodes::ERROR);
     410            0 :          if(!stateLogged()) log<ttmmod_params>({(uint8_t) m_modState, m_modFreq, m_modRad, 0,0});
     411              :       }
     412            0 :       else if(m_modState == MODSTATE_MODULATING)
     413              :       {
     414            0 :          state(stateCodes::OPERATING);
     415            0 :          if(!stateLogged()) log<ttmmod_params>({(uint8_t) m_modState, m_modFreq, m_modRad, 0,0});
     416              :       }
     417              : 
     418            0 :    }
     419            0 :    return 0;
     420              : 
     421              : }
     422              : 
     423              : 
     424              : 
     425              : inline
     426            0 : int ttmModulator::appShutdown()
     427              : {
     428              :    //don't bother
     429            0 :    return 0;
     430              : }
     431              : 
     432              : inline
     433            0 : int ttmModulator::calcState()
     434              : {
     435              :    //Need TTM power state here.
     436              : 
     437            0 :    if( m_C1outp < 1 || m_C2outp < 1 ) //At least one channel off
     438              :    {
     439              :       //Need to also check fxn gen pwr state here
     440            0 :       m_modState = MODSTATE_REST;
     441              :    }
     442            0 :    else if( (m_C1freq == 0 || m_C1volts <= 0.002) && (m_C2freq == 0 || m_C2volts <= 0.002) )
     443              :    {
     444              :       //To be set:
     445              :       // -- sine wave freq is 0 or amp is 0.002
     446              :       // -- offset V is at setVoltage
     447              :       // -- phase is 0
     448            0 :       if(/*m_C1ofst == m_setVoltage_1 && m_C2ofst == m_setVoltage_2 &&*/ m_C1phse == 0 && m_C2phse == 0 )
     449              :       {
     450            0 :          m_modState = MODSTATE_SET;
     451              :       }
     452              :       else
     453              :       {
     454            0 :          m_modState = MODSTATE_MIDSET; //must be setting
     455              :       }
     456              :    }
     457              :    else
     458              :    {
     459            0 :       if(m_C1freq != m_C2freq)
     460              :       {
     461            0 :          m_modState = MODSTATE_MIDSET;
     462              :       }
     463              :       else
     464              :       {
     465              :          //Possibly some more checks
     466            0 :          m_modFreq = m_C1freq;
     467              : 
     468              :          //Interpolate on C1.
     469            0 :          size_t ngt = 0;
     470              : 
     471            0 :          for(ngt = 0; ngt < m_calFreqs.size(); ++ngt)
     472              :          {
     473            0 :             if( m_calFreqs[ngt] >= m_modFreq) break;
     474              :          }
     475              : 
     476              :          double terpC1Amp;
     477            0 :          if(ngt == 0 || m_calFreqs[ngt] == m_modFreq)
     478              :          {
     479            0 :             terpC1Amp = m_calC1Amps[ngt];
     480              :          }
     481              :          else
     482              :          {
     483            0 :             size_t nlt = ngt -1;
     484            0 :             double dfreq = (m_modFreq - m_calFreqs[nlt])/(m_calFreqs[ngt]-m_calFreqs[nlt]);
     485            0 :             terpC1Amp = m_calC1Amps[nlt] + (m_calC1Amps[ngt]-m_calC1Amps[nlt])*dfreq;
     486              : 
     487              :          }
     488              : 
     489            0 :          m_modRad = m_C1volts/terpC1Amp * m_calRadius;
     490              : 
     491            0 :          m_modState = MODSTATE_MODULATING;
     492              :       }
     493              :    }
     494              : 
     495            0 :    return 0;
     496              : }
     497              : 
     498            0 : void nanoSleep( unsigned long nsec )
     499              : {
     500            0 :    std::this_thread::sleep_for( std::chrono::duration<unsigned long, std::nano>(nsec));
     501            0 : }
     502              : 
     503              : template<typename T>
     504            0 : int waitValue( const T & var,
     505              :                const T & tgtVal,
     506              :                unsigned long timeout = 5000000000,
     507              :                unsigned long pauseWait = 1000000
     508              :               )
     509              : {
     510            0 :    if(var == tgtVal) return 0;
     511              : 
     512              :    struct timespec ts0, ts1;
     513            0 :    clock_gettime(CLOCK_REALTIME, &ts0);
     514            0 :    ts1 = ts0;
     515              : 
     516              : 
     517            0 :    while( (ts1.tv_sec - ts0.tv_sec)*1e9 + (ts1.tv_nsec - ts0.tv_nsec) < timeout)
     518              :    {
     519            0 :       if(var == tgtVal) return 0;
     520              : 
     521            0 :       nanoSleep(pauseWait);
     522              : 
     523            0 :       clock_gettime(CLOCK_REALTIME, &ts1);
     524              :    }
     525              : 
     526            0 :    if(var == tgtVal) return 0;
     527              : 
     528            0 :    std::cerr << "Timeout: " << (ts1.tv_sec - ts0.tv_sec)*1e9 + (ts1.tv_nsec - ts0.tv_nsec) << "\n";
     529              : 
     530            0 :    return -1;
     531              : 
     532              : }
     533              : 
     534              : template<typename T>
     535            0 : int waitValue( const T & var,
     536              :                const T & tgtVal,
     537              :                double tol,
     538              :                unsigned long timeout = 5000000000,
     539              :                unsigned long pauseWait = 1000000
     540              :               )
     541              : {
     542            0 :    if(fabs(tgtVal - var) <= tol) return 0;
     543              : 
     544              :    struct timespec ts0, ts1;
     545            0 :    clock_gettime(CLOCK_REALTIME, &ts0);
     546            0 :    ts1 = ts0;
     547              : 
     548            0 :    while( (ts1.tv_sec - ts0.tv_sec)*1e9 + (ts1.tv_nsec - ts0.tv_nsec) < timeout)
     549              :    {
     550            0 :       if(fabs(tgtVal - var) <= tol) return 0;
     551              : 
     552            0 :       nanoSleep(pauseWait);
     553              : 
     554            0 :       clock_gettime(CLOCK_REALTIME, &ts1);
     555              :    }
     556              : 
     557            0 :    if(fabs(tgtVal - var) <= tol) return 0;
     558              : 
     559            0 :    std::cerr << "Timeout: " << (ts1.tv_sec - ts0.tv_sec)*1e9 + (ts1.tv_nsec - ts0.tv_nsec) << "\n";
     560            0 :    return -1;
     561              : 
     562              : }
     563              : 
     564              : inline
     565            0 : int ttmModulator::restTTM()
     566              : {
     567              :    //Steps:
     568              :    //1) Set freqs to 0
     569            0 :    if( sendNewProperty(m_indiP_C1freq, "target", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     570            0 :    if( sendNewProperty(m_indiP_C2freq, "target", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     571              : 
     572              :    //2) Set amps to 0 (really 0.002)
     573            0 :    if( sendNewProperty(m_indiP_C1volts, "target", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     574            0 :    if( sendNewProperty(m_indiP_C2volts, "target", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     575              : 
     576              :    //3) Set phase to 0
     577            0 :    if( sendNewProperty(m_indiP_C1phse, "value", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     578            0 :    if( sendNewProperty(m_indiP_C2phse, "value", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     579              : 
     580              :    //4) Set offset to 0
     581            0 :    if( sendNewProperty(m_indiP_C1ofst, "value", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     582            0 :    if( sendNewProperty(m_indiP_C2ofst, "value", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     583              : 
     584              :    //5) Set outputs to off
     585            0 :    if( sendNewProperty(m_indiP_C1outp, "value", "Off") < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     586            0 :    if( sendNewProperty(m_indiP_C2outp, "value", "Off") < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     587              : 
     588              :    //Now check if values have changed.
     589            0 :    if( waitValue(m_C1freq, 0.0) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     590            0 :    if( waitValue(m_C2freq, 0.0) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     591            0 :    if( waitValue(m_C1volts, 0.002, 1e-6) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     592            0 :    if( waitValue(m_C2volts, 0.002, 1e-6) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     593            0 :    if( waitValue(m_C1phse, 0.0) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     594            0 :    if( waitValue(m_C2phse, 0.0) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     595            0 :    if( waitValue(m_C1ofst, 0.001, 1e-6) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     596            0 :    if( waitValue(m_C2ofst, 0.001, 1e-6) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     597            0 :    if( waitValue(m_C1outp, 0) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     598            0 :    if( waitValue(m_C2outp, 0) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     599              : 
     600            0 :    log<text_log>("The PyWFS TTM is rested.", logPrio::LOG_NOTICE);
     601              : 
     602            0 :    return 0;
     603              : }
     604              : 
     605              : inline
     606            0 : int ttmModulator::setTTM()
     607              : {
     608            0 :    if(m_modState == MODSTATE_SET) //already Set.
     609              :    {
     610            0 :       return 0;
     611              :    }
     612              : 
     613            0 :    if(m_modState == MODSTATE_MODULATING) //Modulating
     614              :    {
     615            0 :       log<text_log>("Stopping modulation.", logPrio::LOG_INFO);
     616              : 
     617              :       //Steps:
     618              :       //1) Set freqs to 0
     619            0 :       if( sendNewProperty(m_indiP_C1freq, "target", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     620              : 
     621            0 :       if( sendNewProperty(m_indiP_C2freq, "target", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     622              : 
     623              :       //2) Set amps to 0 (really 0.002)
     624            0 :       if( sendNewProperty(m_indiP_C1volts, "target", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     625              : 
     626            0 :       if( sendNewProperty(m_indiP_C2volts, "target", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     627              : 
     628              :       //3) Set phase to 0
     629            0 :       if( sendNewProperty(m_indiP_C1phse, "value", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     630              : 
     631            0 :       if( sendNewProperty(m_indiP_C2phse, "value", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     632              : 
     633              :       //Now check if values have changed.
     634            0 :       if( waitValue(m_C1freq, 0.0) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     635            0 :       if( waitValue(m_C2freq, 0.0) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     636            0 :       if( waitValue(m_C1volts, 0.002, 1e-6) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     637            0 :       if( waitValue(m_C2volts, 0.002,1e-6) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     638            0 :       if( waitValue(m_C1phse, 0.0) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     639            0 :       if( waitValue(m_C2phse, 0.0) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     640              : 
     641            0 :       m_modFreq = 0;
     642            0 :       m_modFreqRequested = 0;
     643            0 :       m_modRad = 0;
     644            0 :       m_modRadRequested = 0;
     645              : 
     646            0 :       log<text_log>("PyWFS TTM is set.", logPrio::LOG_NOTICE);
     647            0 :       return 0;
     648              :    }
     649              : 
     650              :    //Ok, we're in not set or modulating.  Possibly rested, or in a partially set state.
     651              : 
     652              :    //Steps:
     653              :    //1) Make sure we're fully rested:
     654            0 :    if( m_modState != MODSTATE_REST)
     655              :    {
     656            0 :       if( restTTM() < 0 ) return log<software_error, -1>({__FILE__, __LINE__});
     657              : 
     658            0 :       sleep(1);
     659              :    }
     660              : 
     661            0 :    log<text_log>("Setting the PyWFS TTM.", logPrio::LOG_INFO);
     662              : 
     663              :    //2) Set outputs to on
     664            0 :    if( sendNewProperty(m_indiP_C1outp, "value", "On") < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     665            0 :    if( sendNewProperty(m_indiP_C2outp, "value", "On") < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     666              : 
     667            0 :    if( waitValue(m_C1outp, 1) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     668            0 :    if( waitValue(m_C2outp, 1) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     669              : 
     670              :    //3) Now we begin ramp . . .
     671            0 :    size_t N1 = m_setVoltage_1/m_setDVolts;
     672            0 :    size_t N2 = m_setVoltage_2/m_setDVolts;
     673              : 
     674            0 :    size_t N = N1;
     675            0 :    if(N2 < N1) N = N2;
     676              : 
     677            0 :    log<text_log>("Ramping with " + std::to_string(N) + " steps. [" + std::to_string(N1) + " " + std::to_string(N2) + "]", logPrio::LOG_DEBUG);
     678              : 
     679            0 :    for(size_t i=1; i< N ; ++i)
     680              :    {
     681            0 :       double nv = i*m_setDVolts;
     682              : 
     683            0 :       if(nv < 0 || nv > 10) return log<software_error,-1>({__FILE__, __LINE__, "Bad voltage calculated.  Refusing."});
     684              : 
     685            0 :       if( sendNewProperty(m_indiP_C1ofst, "value", nv) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     686              : 
     687            0 :       if( waitValue(m_C1ofst, nv, 1e-10) < 0 ) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     688              : 
     689            0 :       sleep(1);
     690              : 
     691            0 :       if( sendNewProperty(m_indiP_C2ofst, "value", nv) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     692              : 
     693            0 :       if( waitValue(m_C2ofst, nv, 1e-6) < 0 ) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     694              : 
     695            0 :       sleep(1);
     696              :    }
     697              : 
     698            0 :    for(size_t j=N; j< N1;++j)
     699              :    {
     700            0 :       double nv = j*m_setDVolts;
     701              : 
     702            0 :       if(nv < 0 || nv > 10) return log<software_error,-1>({__FILE__, __LINE__, "Bad voltage calculated.  Refusing."});
     703              : 
     704            0 :       if( sendNewProperty(m_indiP_C1ofst, "value", nv) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     705              : 
     706            0 :       if( waitValue(m_C1ofst, nv, 1e-6) < 0 ) return log<software_error, -1>({__FILE__,__LINE__, "fxngen timeout"});
     707              : 
     708            0 :       sleep(1);
     709              :    }
     710              : 
     711            0 :    for(size_t j=N; j< N2;++j)
     712              :    {
     713            0 :       double nv = j*m_setDVolts;
     714              : 
     715            0 :       if(nv < 0 || nv > 10) return log<software_error,-1>({__FILE__, __LINE__, "Bad voltage calculated.  Refusing."});
     716              : 
     717            0 :       if( sendNewProperty(m_indiP_C2ofst, "value", nv) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     718              : 
     719            0 :       if( waitValue(m_C2ofst, nv, 1e-6) < 0 ) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     720              : 
     721            0 :       sleep(1);
     722              :    }
     723              : 
     724            0 :    if(m_C1ofst < m_setVoltage_1)
     725              :    {
     726            0 :       if( m_setVoltage_1 < 0 ||  m_setVoltage_1 > 10) return log<software_error,-1>({__FILE__, __LINE__, "Bad voltage calculated.  Refusing."});
     727              : 
     728            0 :       if( (sendNewProperty(m_indiP_C1ofst, "value", m_setVoltage_1) < 0 ) ) return log<software_error,-1>({__FILE__,__LINE__});
     729              : 
     730            0 :       if(waitValue(m_C1ofst, m_setVoltage_1, 1e-6) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     731              : 
     732              :    }
     733              : 
     734            0 :    if(m_C2ofst < m_setVoltage_2)
     735              :    {
     736            0 :       if( m_setVoltage_2 < 0 ||  m_setVoltage_2 > 10) return log<software_error,-1>({__FILE__, __LINE__, "Bad voltage calculated.  Refusing."});
     737              : 
     738            0 :       if( (sendNewProperty(m_indiP_C2ofst, "value", m_setVoltage_2) < 0 ) ) return log<software_error,-1>({__FILE__,__LINE__});
     739              : 
     740            0 :       if( waitValue(m_C2ofst, m_setVoltage_2, 1e-6) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     741              : 
     742              :    }
     743              : 
     744            0 :    log<text_log>("PyWFS TTM is set.", logPrio::LOG_NOTICE);
     745              : 
     746            0 :    return 0;
     747              : }
     748              : 
     749              : /*double maxRadAtFrequency( const std::vector<double> freqs,
     750              :                           const std::vector<double> amps,
     751              :                           double modrad
     752              :                         )
     753              : {
     754              : }*/
     755              : 
     756              : inline
     757            0 : int ttmModulator::modTTM( double newRad,
     758              :                           double newFreq
     759              :                         )
     760              : {
     761              :    /// \todo log this
     762            0 :    if(newRad < 0 || newFreq < 0) return 0;
     763              : 
     764              :    /// \todo logging in these steps
     765              : 
     766              :    //For now: if we enter modulating, we stop modulating.
     767              :    /// \todo Implement changing modulation without setting first.
     768            0 :    if( m_modState == MODSTATE_MODULATING)
     769              :    {
     770            0 :       if(newRad == m_modRad && newFreq == m_modFreq) return 0;
     771              : 
     772            0 :       if( setTTM() < 0 ) return log<software_error, -1>({__FILE__, __LINE__});
     773              : 
     774            0 :       if( calcState() < 0) return log<software_error, -1>({__FILE__,__LINE__});
     775              : 
     776              :    }
     777              : 
     778              :    //If not set, we first check if we are fully rested.
     779            0 :    if( m_modState < MODSTATE_SET )
     780              :    {
     781            0 :       if( setTTM() < 0 ) return log<software_error, -1>({__FILE__, __LINE__});
     782              : 
     783            0 :       if( calcState() < 0 ) return log<software_error, -1>({__FILE__,__LINE__});
     784              : 
     785            0 :       if( m_modState < MODSTATE_SET) return log<software_error, -1>({__FILE__,__LINE__, "TTM not set/setable."});
     786              :    }
     787              : 
     788              :    //Check frequency for safety.
     789            0 :    if(newFreq > m_maxFreq)
     790              :    {
     791            0 :       log<text_log>("Requested frequency " + std::to_string(newFreq) + " Hz exceeds limit (" + std::to_string(m_maxFreq) + " Hz). Limiting.", logPrio::LOG_WARNING);
     792            0 :       newFreq = m_maxFreq;
     793              :    }
     794              : 
     795              :    //Calculate voltage, and normalize and safety-check Parameters
     796              :    double voltageC1, voltageC2;
     797              : 
     798              :    ///\todo here maximum radius should be frequency dependent.
     799              : 
     800              : 
     801              : 
     802            0 :    double terpC1Amp = 0;
     803            0 :    double terpC2Amp = 0;
     804            0 :    double terpC2Phse = 0;
     805              : 
     806            0 :    size_t ngt = 0;
     807              : 
     808            0 :    for(ngt = 0; ngt < m_calFreqs.size(); ++ngt)
     809              :    {
     810            0 :       if( m_calFreqs[ngt] >= newFreq) break;
     811              :    }
     812              : 
     813            0 :    if(ngt == 0 || m_calFreqs[ngt] == newFreq)
     814              :    {
     815            0 :       terpC1Amp = m_calC1Amps[ngt];
     816            0 :       terpC2Amp = m_calC2Amps[ngt];
     817            0 :       terpC2Phse = m_calC2Phse[ngt];
     818              :    }
     819              :    else
     820              :    {
     821            0 :       size_t nlt = ngt -1;
     822            0 :       double dfreq = (newFreq - m_calFreqs[nlt])/(m_calFreqs[ngt]-m_calFreqs[nlt]);
     823              : 
     824            0 :       terpC1Amp = m_calC1Amps[nlt] + (m_calC1Amps[ngt]-m_calC1Amps[nlt])*dfreq;
     825            0 :       terpC2Amp = m_calC2Amps[nlt] + (m_calC2Amps[ngt]-m_calC2Amps[nlt])*dfreq;
     826            0 :       terpC2Phse = m_calC2Phse[nlt] + (m_calC2Phse[ngt]-m_calC2Phse[nlt])*dfreq;
     827              :    }
     828              : 
     829              : 
     830            0 :    voltageC1 = terpC1Amp*(newRad/m_calRadius);
     831            0 :    voltageC2 = terpC2Amp*(newRad/m_calRadius);
     832              : 
     833              : 
     834            0 :    if(voltageC1 > m_maxVolt)
     835              :    {
     836            0 :       log<text_log>("Requested ch-1 voltge " + std::to_string(voltageC1) + " V exceeds limit (" + std::to_string(m_maxVolt) + " V). Limiting.", logPrio::LOG_WARNING);
     837            0 :       voltageC1 = m_maxVolt;
     838              :    }
     839              : 
     840            0 :    if(voltageC2 > m_maxVolt)
     841              :    {
     842            0 :       log<text_log>("Requested ch-2 voltge " + std::to_string(voltageC2) + " V exceeds limit (" + std::to_string(m_maxVolt) + " V). Limiting.", logPrio::LOG_WARNING);
     843            0 :       voltageC2 = m_maxVolt;
     844              :    }
     845              : 
     846              : 
     847              :    //At this point we have safe calibrated voltage for the frequency.
     848              : 
     849            0 :    if( m_modState == MODSTATE_SET)
     850              :    {
     851              :       // 0) set phase
     852            0 :       if( sendNewProperty(m_indiP_C2phse, "value", terpC2Phse) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     853              : 
     854              :       /// \todo should we set the offset here just to be sure?
     855              : 
     856              :       //Now check if values have changed.
     857            0 :       if( waitValue(m_C2phse, terpC2Phse, 1e-4) < 0  ) return log<software_error, -1>({__FILE__,__LINE__, "fxngen timeout"});
     858              : 
     859              :       // 1) set freq to 100 Hz (or requested if < 100 Hz)
     860            0 :       double nextFreq = 100.0;
     861            0 :       if(nextFreq > newFreq) nextFreq = newFreq;
     862              : 
     863              :       //send to device
     864            0 :       if( sendNewProperty(m_indiP_C1freq, "target", nextFreq) < 0 ) log<software_error,-1>({__FILE__,__LINE__});
     865            0 :       if( sendNewProperty(m_indiP_C2freq, "target", nextFreq) < 0 ) log<software_error,-1>({__FILE__,__LINE__});
     866              : 
     867              :       //Now check if values have changed.
     868            0 :       if( waitValue(m_C1freq, nextFreq, 1e-6) < 0 ) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     869            0 :       if( waitValue(m_C2freq, nextFreq, 1e-6) < 0 ) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     870              : 
     871              :       // 2) set amp to 0.1 V (or requested if < 0.1 V)
     872            0 :       double nextVolts1 = 0.1;
     873            0 :       if(nextVolts1 > voltageC1) nextVolts1 = voltageC1;
     874              : 
     875            0 :       double nextVolts2 = 0.1;
     876            0 :       if(nextVolts2 > voltageC2) nextVolts2 = voltageC2;
     877              : 
     878              :       //send to device
     879            0 :       if( sendNewProperty(m_indiP_C1volts, "target", nextVolts1) < 0 ) return log<software_error, -1>({__FILE__,__LINE__});
     880            0 :       if( sendNewProperty(m_indiP_C2volts, "target", nextVolts2) < 0 ) return log<software_error, -1>({__FILE__,__LINE__});
     881              : 
     882              : 
     883              :       //Now check if values have changed.
     884            0 :       if( waitValue(m_C1volts, nextVolts1, 1e-6) < 0 ) log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     885            0 :       if( waitValue(m_C2volts, nextVolts2, 1e-6) < 0 ) log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     886              : 
     887              :       // 3) Increase freq to 500 Hz, then in 500 Hz increments
     888            0 :       double currFreq = m_C1freq;
     889              : 
     890            0 :       nextFreq = 500.0;
     891            0 :       if(nextFreq > newFreq) nextFreq = newFreq;
     892              : 
     893              :       ///\todo make frequency tolerance a configurable
     894            0 :       while( fabs(currFreq - newFreq) > 1e-4)
     895              :       {
     896            0 :          if( sendNewProperty(m_indiP_C1freq, "target", nextFreq) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     897            0 :          if( sendNewProperty(m_indiP_C2freq, "target", nextFreq) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     898              : 
     899              :          //Now check if values have changed.
     900            0 :          if( waitValue(m_C1freq, nextFreq, 1e-6) < 0 ) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     901            0 :          if( waitValue(m_C2freq, nextFreq, 1e-6) < 0 ) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
     902              : 
     903              :          ///\todo make sleep-time configurable
     904            0 :          sleep(1);
     905            0 :          currFreq = m_C1freq;
     906            0 :          nextFreq = currFreq + m_modDFreq;
     907            0 :          if(nextFreq > newFreq) nextFreq = newFreq;
     908              :       }
     909              : 
     910              :       // 4) Now increase amplitude in 0.1 V increments.
     911            0 :       double currVolts1 = m_C1volts;
     912            0 :       double currVolts2 = m_C2volts;
     913              : 
     914            0 :       nextVolts1 = 0.2;
     915            0 :       if(nextVolts1 > voltageC1) nextVolts1 = voltageC1;
     916              : 
     917            0 :       nextVolts2 = 0.2;
     918            0 :       if(nextVolts2 > voltageC2) nextVolts2 = voltageC2;
     919              :       ///\todo make voltage tolerance a configurable.
     920            0 :       while( fabs(currVolts1 - voltageC1) > 1e-4 || fabs(currVolts2 - voltageC2) > 1e-4)
     921              :       {
     922            0 :          if( sendNewProperty(m_indiP_C1volts, "target", nextVolts1) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     923            0 :          if( sendNewProperty(m_indiP_C2volts, "target", nextVolts2) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     924              : 
     925              :          //Now check if values have changed.
     926            0 :          if( waitValue(m_C1volts, nextVolts1, 1e-3) < 0 )
     927              :          {
     928            0 :             return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout C1"});
     929              :          }
     930              : 
     931            0 :          if( waitValue(m_C2volts, nextVolts2, 1e-3) < 0 )
     932              :          {
     933            0 :             return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout C2"});
     934              :          }
     935              : 
     936            0 :          sleep(1);
     937            0 :          currVolts1 = m_C1volts;
     938            0 :          nextVolts1 = currVolts1 + m_modDVolts;
     939            0 :          if(nextVolts1 > voltageC1) nextVolts1 = voltageC1;
     940              : 
     941            0 :          currVolts2 = m_C2volts;
     942            0 :          nextVolts2 = currVolts2 + m_modDVolts;
     943            0 :          if(nextVolts2 > voltageC2) nextVolts2 = voltageC2;
     944              : 
     945              :       }
     946              : 
     947            0 :       m_modRad = newRad;
     948            0 :       m_modFreq = newFreq;
     949              :    }
     950            0 :    else return log<software_error,-1>({__FILE__,__LINE__, "TTM not set but should be by now."});
     951              : 
     952              : 
     953            0 :    return 0;
     954              : }
     955              : 
     956              : inline
     957            0 : int ttmModulator::offset12( double d1,
     958              :                             double d2
     959              :                           )
     960              : {
     961              : 
     962            0 :    if( sendNewProperty(m_indiP_C1ofst, "value", m_C1ofst + d1) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     963            0 :    if( sendNewProperty(m_indiP_C2ofst, "value", m_C2ofst + d2) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     964              : 
     965            0 :    return 0;
     966              : 
     967              : }
     968              : 
     969              : inline
     970            0 : int ttmModulator::offsetXY( double dx,
     971              :                             double dy
     972              :                           )
     973              : {
     974            0 :    double cs = cos(m_rotAngle);
     975            0 :    double ss = sin(m_rotAngle);
     976              : 
     977            0 :    double rdx = dx * cs - dy * ss;
     978            0 :    double rdy = m_rotParity*(dx * ss + dy * cs);
     979              : 
     980            0 :    if( sendNewProperty(m_indiP_C1ofst, "value", m_C1ofst + rdx) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     981            0 :    if( sendNewProperty(m_indiP_C2ofst, "value", m_C2ofst + rdy) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
     982              : 
     983            0 :    return 0;
     984              : 
     985              : }
     986              : 
     987            0 : INDI_NEWCALLBACK_DEFN(ttmModulator, m_indiP_modState)(const pcf::IndiProperty &ipRecv)
     988              : {
     989            0 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_modState, ipRecv);
     990              : 
     991              :     int target;
     992              : 
     993            0 :     if( indiTargetUpdate( m_indiP_modState, target, ipRecv, false) < 0)
     994              :     {
     995            0 :        return log<software_error, -1>({__FILE__,__LINE__});
     996              :     }
     997              : 
     998            0 :     m_modStateRequested = target;
     999              : 
    1000              :     /*m_references(0,0) = target;
    1001              : 
    1002              :     int state = 0;
    1003              :     try
    1004              :     {
    1005              :         state = ipRecv["target"].get<int>();
    1006              :     }
    1007              :     catch(...)
    1008              :     {
    1009              :         log<software_error>({__FILE__, __LINE__, "exception caught"});
    1010              :         return -1;
    1011              :     }
    1012              : 
    1013              :     m_modStateRequested = state;*/
    1014              : 
    1015            0 :     return 0;
    1016              : }
    1017              : 
    1018            0 : INDI_NEWCALLBACK_DEFN(ttmModulator, m_indiP_modFrequency)(const pcf::IndiProperty &ipRecv)
    1019              : {
    1020            0 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_modFrequency, ipRecv);
    1021              : 
    1022              :     double target;
    1023            0 :     if( indiTargetUpdate( m_indiP_modFrequency, target, ipRecv, false) < 0)
    1024              :     {
    1025            0 :        return log<software_error, -1>({__FILE__,__LINE__});
    1026              :     }
    1027              : 
    1028            0 :     if(target > 0)
    1029              :     {
    1030            0 :         m_modFreqRequested = target;
    1031              :     }
    1032              :     /*
    1033              :     ///\todo use find to test
    1034              :     try
    1035              :     {
    1036              :         double nf = -1;
    1037              :         nf = ipRecv["target"].get<double>();
    1038              :         if(nf > 0) m_modFreqRequested = nf;
    1039              :     }
    1040              :     catch(...)
    1041              :     {
    1042              :         //do nothing, just means no requested in command.
    1043              :     }
    1044              :     */
    1045              : 
    1046            0 :     return 0;
    1047              : 
    1048              : }
    1049              : 
    1050            0 : INDI_NEWCALLBACK_DEFN(ttmModulator, m_indiP_modRadius)(const pcf::IndiProperty &ipRecv)
    1051              : {
    1052            0 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_modRadius, ipRecv);
    1053              : 
    1054              :     double target;
    1055            0 :     if( indiTargetUpdate( m_indiP_modRadius, target, ipRecv, false) < 0)
    1056              :     {
    1057            0 :        return log<software_error, -1>({__FILE__,__LINE__});
    1058              :     }
    1059              : 
    1060            0 :     if(target > 0)
    1061              :     {
    1062            0 :         m_modRadRequested = target;
    1063              :     }
    1064              : 
    1065              : /*
    1066              :     ///\todo use find to test
    1067              :     try
    1068              :     {
    1069              :         double nr = -1;
    1070              :         nr = ipRecv["target"].get<double>();
    1071              :         if(nr > 0) m_modRadRequested = nr;
    1072              :     }
    1073              :     catch(...)
    1074              :     {
    1075              :         //do nothing, just means no requested in command.
    1076              :     }
    1077              :       */
    1078              : 
    1079            0 :     return 0;
    1080              : 
    1081              : }
    1082              : 
    1083            0 : INDI_NEWCALLBACK_DEFN(ttmModulator, m_indiP_offset12)(const pcf::IndiProperty &ipRecv)
    1084              : {
    1085            0 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_offset12, ipRecv);
    1086              : 
    1087            0 :     double dx = 0;
    1088            0 :     if(ipRecv.find("dC1"))
    1089              :     {
    1090            0 :        dx = ipRecv["dC1"].get<double>();
    1091              :     }
    1092            0 :     std::cerr << "dC1: " << dx << "\n";
    1093              : 
    1094            0 :     double dy = 0;
    1095            0 :     if(ipRecv.find("dC2"))
    1096              :     {
    1097            0 :        dy = ipRecv["dC2"].get<double>();
    1098              :     }
    1099              : 
    1100            0 :     std::cerr << "dC2: " << dy << "\n\n";
    1101              : 
    1102              : 
    1103            0 :     return offset12(dx, dy);
    1104              : 
    1105              : }
    1106              : 
    1107            0 : INDI_NEWCALLBACK_DEFN(ttmModulator, m_indiP_offset)(const pcf::IndiProperty &ipRecv)
    1108              : {
    1109            0 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_offset, ipRecv);
    1110              : 
    1111            0 :     double dx = 0;
    1112            0 :     if(ipRecv.find("x"))
    1113              :     {
    1114            0 :        dx = ipRecv["x"].get<double>();
    1115              :     }
    1116            0 :     std::cerr << "dx: " << dx << "\n";
    1117              : 
    1118            0 :     double dy = 0;
    1119            0 :     if(ipRecv.find("y"))
    1120              :     {
    1121            0 :        dy = ipRecv["y"].get<double>();
    1122              :     }
    1123              : 
    1124            0 :     std::cerr << "dy: " << dy << "\n\n";
    1125              : 
    1126              : 
    1127            0 :     return offsetXY(dx, dy);
    1128              : 
    1129              : }
    1130              : 
    1131              : 
    1132            0 : INDI_SETCALLBACK_DEFN(ttmModulator, m_indiP_C1outp)(const pcf::IndiProperty &ipRecv)
    1133              : {
    1134            0 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C1outp, ipRecv);
    1135              : 
    1136              :     ///\todo use find to test
    1137              :     try
    1138              :     {
    1139            0 :        m_indiP_C1outp = ipRecv;
    1140            0 :        std::string outp = ipRecv["value"].getValue();
    1141              : 
    1142            0 :        if( outp == "Off" )
    1143              :        {
    1144            0 :           m_C1outp = 0;
    1145              :        }
    1146            0 :        else if (outp == "On")
    1147              :        {
    1148            0 :           m_C1outp = 1;
    1149              :        }
    1150              :        else
    1151              :        {
    1152            0 :           m_C1outp = -1;
    1153              :        }
    1154              : 
    1155            0 :        return 0;
    1156            0 :     }
    1157            0 :     catch(...)
    1158              :     {
    1159            0 :        log<software_error>({__FILE__, __LINE__, "exception from libcommon"});
    1160            0 :        return -1;
    1161            0 :     }
    1162              : 
    1163              : }
    1164              : 
    1165            0 : INDI_SETCALLBACK_DEFN(ttmModulator, m_indiP_C1freq)(const pcf::IndiProperty &ipRecv)
    1166              : {
    1167            0 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C1freq, ipRecv);
    1168              : 
    1169              :     ///\todo use find to test
    1170              :     try
    1171              :     {
    1172            0 :        m_indiP_C1freq = ipRecv;
    1173            0 :        double nv = ipRecv["current"].get<double>();
    1174              : 
    1175            0 :        m_C1freq = nv;
    1176              : 
    1177            0 :        return 0;
    1178              :     }
    1179            0 :     catch(...)
    1180              :     {
    1181            0 :        log<software_error>({__FILE__, __LINE__, "exception from libcommon"});
    1182            0 :        return -1;
    1183            0 :     }
    1184              : 
    1185              : }
    1186              : 
    1187            0 : INDI_SETCALLBACK_DEFN(ttmModulator, m_indiP_C1volts)(const pcf::IndiProperty &ipRecv)
    1188              : {
    1189            0 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C1volts, ipRecv);
    1190              : 
    1191              :     ///\todo use find to test
    1192              :     try
    1193              :     {
    1194            0 :        m_indiP_C1volts = ipRecv;
    1195            0 :        double nv = ipRecv["current"].get<double>();
    1196              : 
    1197            0 :        m_C1volts = nv;
    1198            0 :        return 0;
    1199              :     }
    1200            0 :     catch(...)
    1201              :     {
    1202            0 :        log<software_error>({__FILE__, __LINE__, "exception from libcommon"});
    1203            0 :        return -1;
    1204            0 :     }
    1205              : 
    1206              : }
    1207              : 
    1208            0 : INDI_SETCALLBACK_DEFN(ttmModulator, m_indiP_C1ofst)(const pcf::IndiProperty &ipRecv)
    1209              : {
    1210            0 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C1ofst, ipRecv);
    1211              : 
    1212              :     ///\todo use find to test
    1213              :     try
    1214              :     {
    1215            0 :        m_indiP_C1ofst = ipRecv;
    1216            0 :        double nv = ipRecv["value"].get<double>();
    1217              : 
    1218            0 :        m_C1ofst = nv;
    1219              : 
    1220            0 :        return 0;
    1221              :     }
    1222            0 :     catch(...)
    1223              :     {
    1224            0 :        log<software_error>({__FILE__, __LINE__, "exception from libcommon"});
    1225            0 :        return -1;
    1226            0 :     }
    1227              : 
    1228              : }
    1229              : 
    1230            0 : INDI_SETCALLBACK_DEFN(ttmModulator, m_indiP_C1phse)(const pcf::IndiProperty &ipRecv)
    1231              : {
    1232              : 
    1233            0 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C1phse, ipRecv);
    1234              : 
    1235              :     ///\todo use find to test
    1236              :     try
    1237              :     {
    1238            0 :        m_indiP_C1phse = ipRecv;
    1239            0 :        double nv = ipRecv["value"].get<double>();
    1240              : 
    1241            0 :        m_C1phse = nv;
    1242              : 
    1243            0 :        return 0;
    1244              :     }
    1245            0 :     catch(...)
    1246              :     {
    1247            0 :        log<software_error>({__FILE__, __LINE__, "exception from libcommon"});
    1248            0 :        return -1;
    1249            0 :     }
    1250              : 
    1251              : }
    1252              : 
    1253            0 : INDI_SETCALLBACK_DEFN(ttmModulator, m_indiP_C2outp)(const pcf::IndiProperty &ipRecv)
    1254              : {
    1255            0 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C2outp, ipRecv);
    1256              : 
    1257              :     ///\todo use find to test
    1258              :     try
    1259              :     {
    1260            0 :        m_indiP_C2outp = ipRecv;
    1261            0 :        std::string outp = ipRecv["value"].getValue();
    1262              : 
    1263            0 :        if( outp == "Off" )
    1264              :        {
    1265            0 :           m_C2outp = 0;
    1266              :        }
    1267            0 :        else if (outp == "On")
    1268              :        {
    1269            0 :           m_C2outp = 1;
    1270              :        }
    1271              :        else
    1272              :        {
    1273            0 :           m_C2outp = -1;
    1274              :        }
    1275              : 
    1276            0 :        return 0;
    1277            0 :     }
    1278            0 :     catch(...)
    1279              :     {
    1280            0 :        log<software_error>({__FILE__, __LINE__, "exception from libcommon"});
    1281            0 :        return -1;
    1282            0 :     }
    1283              : 
    1284              : }
    1285              : 
    1286            0 : INDI_SETCALLBACK_DEFN(ttmModulator, m_indiP_C2freq)(const pcf::IndiProperty &ipRecv)
    1287              : {
    1288            0 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C2freq, ipRecv);
    1289              : 
    1290              :     ///\todo use find to test
    1291              :     try
    1292              :     {
    1293            0 :        m_indiP_C2freq = ipRecv;
    1294            0 :        double nv = ipRecv["current"].get<double>();
    1295              : 
    1296            0 :        m_C2freq = nv;
    1297              : 
    1298            0 :        return 0;
    1299              :     }
    1300            0 :     catch(...)
    1301              :     {
    1302            0 :        log<software_error>({__FILE__, __LINE__, "exception from libcommon"});
    1303            0 :        return -1;
    1304            0 :     }
    1305              : 
    1306              : }
    1307              : 
    1308            0 : INDI_SETCALLBACK_DEFN(ttmModulator, m_indiP_C2volts)(const pcf::IndiProperty &ipRecv)
    1309              : {
    1310            0 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C2volts, ipRecv);
    1311              : 
    1312              :     ///\todo use find to test
    1313              :     try
    1314              :     {
    1315            0 :        m_indiP_C2volts = ipRecv;
    1316            0 :        double nv = ipRecv["current"].get<double>();
    1317              : 
    1318            0 :        m_C2volts = nv;
    1319            0 :        return 0;
    1320              :     }
    1321            0 :     catch(...)
    1322              :     {
    1323            0 :        log<software_error>({__FILE__, __LINE__, "exception from libcommon"});
    1324            0 :        return -1;
    1325            0 :     }
    1326              : 
    1327              : }
    1328              : 
    1329            0 : INDI_SETCALLBACK_DEFN(ttmModulator, m_indiP_C2ofst)(const pcf::IndiProperty &ipRecv)
    1330              : {
    1331            0 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C2ofst, ipRecv);
    1332              : 
    1333              :     ///\todo use find to test
    1334              :     try
    1335              :     {
    1336            0 :        m_indiP_C2ofst = ipRecv;
    1337              : 
    1338            0 :        double nv = ipRecv["value"].get<double>();
    1339              : 
    1340            0 :        m_C2ofst = nv;
    1341              : 
    1342            0 :        return 0;
    1343              :     }
    1344            0 :     catch(...)
    1345              :     {
    1346            0 :        log<software_error>({__FILE__, __LINE__, "exception from libcommon"});
    1347            0 :        return -1;
    1348            0 :     }
    1349              : 
    1350              : }
    1351              : 
    1352            0 : INDI_SETCALLBACK_DEFN(ttmModulator, m_indiP_C2phse)(const pcf::IndiProperty &ipRecv)
    1353              : {
    1354            0 :     INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C2phse, ipRecv);
    1355              : 
    1356              :     ///\todo use find to test
    1357              :     try
    1358              :     {
    1359            0 :        m_indiP_C2phse = ipRecv;
    1360            0 :        double nv = ipRecv["value"].get<double>();
    1361              : 
    1362            0 :        m_C2phse = nv;
    1363              : 
    1364            0 :        return 0;
    1365              :     }
    1366            0 :     catch(...)
    1367              :     {
    1368            0 :        log<software_error>({__FILE__, __LINE__, "exception from libcommon"});
    1369            0 :        return -1;
    1370            0 :     }
    1371              : }
    1372              : 
    1373              : } //namespace app
    1374              : } //namespace MagAOX
    1375              : 
    1376              : #endif //ttmModulator_hpp
        

Generated by: LCOV version 2.0-1