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