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