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