API
 
Loading...
Searching...
No Matches
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
11
12namespace MagAOX
13{
14namespace 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 */
26class 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
38private:
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?
42protected:
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
96private:
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
102public:
103
104 /// Default c'tor.
105 siglentSDG();
106
107 /// D'tor, declared and defined for noexcept.
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 */
376protected:
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
407public:
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
443inline
444siglentSDG::siglentSDG() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
445{
446 m_powerMgtEnabled = true;
447 m_telnetConn.m_prompt = "\n";
448 return;
449}
450
451inline
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
469inline
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
488inline
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");
550 {
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");
607 {
609 return -1;
610 }
611
613 {
614 return log<software_error,-1>({__FILE__,__LINE__});
615 }
616
617 return 0;
618}
619
620inline
622{
623
624 if( state() == stateCodes::POWERON )
625 {
626 m_poweredOn = true; //So we reset the device.
627
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
700
701 return 0;
702 }
703 }
704
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 {
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 {
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 {
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 {
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 {
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);
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 {
870 }
871 return 0;
872 }
873
874 if( queryOUTP(2) < 0 )
875 {
876 if((m_powerState != 1 || m_powerTargetState != 1) > 0 && !m_shutdown)
877 {
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 {
899 return 0;
900 }
901
902 return 0;
903
904 }
905
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
924inline
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
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
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
989inline
991{
992 return onPowerOff();
993}
994
995inline
997{
999
1000 return 0;
1001}
1002
1003inline
1004int siglentSDG::writeRead( std::string & strRead,
1005 const std::string & command
1006 )
1007{
1008 int rv;
1011
1012 if(rv < 0)
1013 {
1014 std::cout << command << "\n";
1015 std::cout << "writeRead return val was " << rv << "\n";
1018 return -1;
1019 }
1020
1021 //Clear the newline
1023 if(rv < 0)
1024 {
1026 return -1;
1027 }
1028
1030 if(rv < 0)
1031 {
1033 return -1;
1034 }
1035 return 0;
1036
1037}
1038
1039inline
1040int siglentSDG::writeCommand( const std::string & command )
1041{
1042
1044 if(rv < 0)
1045 {
1047 return -1;
1048 }
1049
1050 //Clear the newline
1052 if(rv < 0)
1053 {
1055 return -1;
1056 }
1057
1059 if(rv < 0)
1060 {
1062 return -1;
1063 }
1064
1065 return 0;
1066}
1067
1068inline
1069std::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
1082inline
1083int 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
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
1127inline
1128int 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
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
1172inline
1173int 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
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
1217inline
1218int 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
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
1262inline
1263int 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;
1284
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 {
1299 m_C1vpp = resp_amp;
1303
1305 if(m_C1vpp_tgt == -1) m_C1vpp_tgt = m_C1vpp;
1306
1307 recordParams();
1308
1312
1314
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 {
1326 m_C2vpp = resp_amp;
1330
1332 if(m_C2vpp_tgt == -1) m_C2vpp_tgt = m_C2vpp;
1333
1334 recordParams();
1335
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
1357inline
1358int 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
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
1402inline
1403int 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
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 {
1442 recordParams();
1443 updateIfChanged(m_indiP_C1outp, "value", ro);
1444 }
1445
1446 else if(channel == 2)
1447 {
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
1462inline
1464{
1465 std::string state;
1466 int index;
1467 int rv;
1468
1469 rv = queryMDWV(state, 1);
1470
1471 if(rv < 0)
1472 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
1586 return rv;
1587 }
1588
1589 rv = querySYNC(m_C2sync, 2);
1590
1591 if(rv < 0)
1592 {
1594 return rv;
1595 }
1596
1597
1598 return 0;
1599}
1600
1601inline
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";
1618
1621
1622 afterColon = "SWWV STATE,OFF";
1625
1628
1629 afterColon = "BTWV STATE,OFF";
1632
1635
1636 afterColon = "ARWV INDEX,0";
1639
1642
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
1685
1686 recordParams(true);
1687
1688 std::cerr << "Done\n";
1689 return 0;
1690}
1691
1692inline
1693int 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 {
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
1735inline
1736int 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
1760
1761 int rv = changeOutp(channel, newOutp);
1763
1765
1766 return rv;
1767}
1768
1769inline
1770int 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 {
1813 }
1814 else
1815 {
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 {
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
1856inline
1857int 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.
1880
1881 int rv = changeFreq(channel,newFreq);
1883
1885
1886 return rv;
1887}
1888
1889inline
1890int 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 {
1948 }
1949 else
1950 {
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 {
1967 return -1;
1968 }
1969
1970 return 0;
1971}
1972
1973inline
1974int 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
1998
1999 int rv = changeAmp(channel, newAmp);
2001
2003
2004 return rv;
2005}
2006
2007inline
2008int 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 {
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 {
2051 return -1;
2052 }
2053
2054 return 0;
2055}
2056
2057inline
2058int 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
2082
2083 int rv = changeOfst(channel, newOfst);
2085
2087
2088 return rv;
2089}
2090
2091inline
2092int 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 {
2113 return -1;
2114 }
2115
2116 return 0;
2117}
2118
2119inline
2120int 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
2144
2145 int rv = changePhse(channel, newPhse);
2147
2149
2150 return rv;
2151}
2152
2153inline
2154int 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 {
2175 return -1;
2176 }
2177
2178 return 0;
2179}
2180
2181inline
2182int 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
2206
2207 int rv = changeWdth(channel, newWdth);
2209
2211
2212 return rv;
2213}
2214
2215
2216inline
2217int 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 {
2233 return -1;
2234 }
2235
2236 return 0;
2237}
2238
2239inline
2240int 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
2264
2265 int rv = changeWvtp(channel, newWvtp);
2267
2269
2270 return rv;
2271}
2272
2273inline
2274int 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 {
2296 return -1;
2297 }
2298
2299 return 0;
2300}
2301
2302inline
2303int 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
2330
2331 int rv = changeSync(channel, newSync);
2333
2335
2336 return rv;
2337}
2338
2339INDI_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
2347INDI_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
2354INDI_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
2361INDI_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
2368INDI_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
2375INDI_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
2382INDI_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
2389INDI_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
2396INDI_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
2403INDI_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
2410INDI_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
2417INDI_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
2424INDI_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
2431INDI_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
2438INDI_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
2445INDI_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
2456inline
2461
2462inline
2464{
2465 return recordParams(true);
2466}
2467
2468inline
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
2527
2536
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.
stateCodes::stateCodeT state()
Get the current state code.
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.
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.
int m_powerState
Current power state, 1=On, 0=Off, -1=Unk.
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.
int stateLogged()
Updates and returns the value of m_stateLogged. Will be 0 on first call after a state change,...
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
std::mutex m_indiMutex
Mutex for locking INDI communications.
int m_powerTargetState
Current target power state, 1=On, 0=Off, -1=Unk.
static constexpr double cs_MaxVolts
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.
double m_C1vpp
The peak-2-peak voltage of channel 1.
int changePhse(int channel, double newPhse)
Send a change phase command to the device.
virtual int onPowerOff()
Implementation of the on-power-off FSM logic.
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.
tty::telnetConn m_telnetConn
The telnet connection manager.
double m_C1frequency
The output frequency of channel 1.
std::string m_devicePort
The device port.
uint8_t m_C2outp
The output status channel 2.
double m_C1vppDefault
default value for vpp of channel 1
virtual int appStartup()
Startup functions.
int changeAmp(int channel, double newAmp)
Send a change amplitude command to the device.
pcf::IndiProperty m_indiP_C2sync
pcf::IndiProperty m_indiP_C2wvtp
double m_C2phse
The phase of channel 2 (SINE only)
pcf::IndiProperty m_indiP_C2freq
INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C1wvtp)
std::string m_C1wvtp
The wave type of channel 1.
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.
~siglentSDG() noexcept
D'tor, declared and defined for noexcept.
virtual void loadConfig()
load the configuration system results (called by MagAOXApp::setup())
std::vector< double > m_maxAmp
int changeWvtp(int channel, const std::string &newWvtp)
Send a change wavetype command to the device.
static constexpr double cs_MaxOfst
pcf::IndiProperty m_indiP_C1amp
pcf::IndiProperty m_indiP_C2wdth
INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C2phse)
pcf::IndiProperty m_indiP_status
pcf::IndiProperty m_indiP_C1peri
pcf::IndiProperty m_indiP_C2ofst
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)
pcf::IndiProperty m_indiP_C2llev
double m_C2vppDefault
default value for vpp of channel 2
INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C1sync)
pcf::IndiProperty m_indiP_C1ofst
virtual int whilePowerOff()
Implementation of the while-powered-off FSM.
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
pcf::IndiProperty m_indiP_C1wdth
pcf::IndiProperty m_indiP_C1wvtp
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
std::vector< double > m_maxFreq
pcf::IndiProperty m_indiP_C1freq
double m_C1phse
The phase of channel 1 (SINE only)
INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C2outp)
double m_C2setVoltage
the set position voltage of Ch. 2.
virtual int appLogic()
Implementation of the FSM for the Siglent SDG.
pcf::IndiProperty m_indiP_C2ampvrms
INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C2wvtp)
pcf::IndiProperty m_indiP_C1hlev
siglentSDG()
Default c'tor.
virtual void setupConfig()
Setup the configuration system (called by MagAOXApp::setup())
INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C1amp)
std::string m_deviceAddr
The device address.
pcf::IndiProperty m_indiP_C2hlev
int changeSync(int channel, bool newSync)
Send a change sync command to the device.
pcf::IndiProperty m_indiP_C1phse
pcf::IndiProperty m_indiP_C1outp
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
int recordTelem(const telem_fxngen *)
INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C2amp)
double m_C1wdth
The width of channel 1 (PULSE only)
int m_readTimeOut
The timeout for reading from the device [msec].
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
double m_C2frequency
The output frequency of channel 2.
virtual int appShutdown()
Do any needed shutdown tasks. Currently nothing in this app.
int m_writeTimeOut
The timeout for writing to the device [msec].
int normalizeSetup()
Normalize the setup, called during connection if checkSetup shows a problem, or on power-up.
friend class siglentSDG_test
uint8_t m_C1outp
std::string m_clock; ///<INTernal or EXTernal
pcf::IndiProperty m_indiP_C2phse
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.
double m_C2ofst
The offset voltage of channel 2.
double m_C1setVoltage
the set position voltage of Ch. 1.
std::string m_C2wvtp
The wave type of channel 2.
pcf::IndiProperty m_indiP_C1sync
int queryBTWV(std::string &state, int channel)
Send the BTWV? query and get the response state.
pcf::IndiProperty m_indiP_C1ampvrms
INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C1ofst)
INDI_NEWCALLBACK_DECL(siglentSDG, m_indiP_C2freq)
#define INDI_NEWCALLBACK_DEFN(class, prop)
Define the callback for a new property request.
#define REG_INDI_NEWPROP_NOCB(prop, propName, type)
Register a NEW INDI property with the class, with no callback.
#define REG_INDI_NEWPROP(prop, propName, type)
Register a NEW INDI property with the class, using the standard callback name.
#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...
@ OPERATING
The device is operating, other than homing.
@ CONFIGURING
The application is configuring the device.
@ ERROR
The application has encountered an error, from which it is recovering (with or without intervention)
@ READY
The device is ready for operation, but is not operating.
@ CONNECTED
The application has connected to the device or service.
@ NOTCONNECTED
The application is not connected to the device or service.
@ POWERON
The device power is on.
std::string ttyErrorString(int ec)
Get a text explanation of a TTY_E_ error code.
Definition ttyErrors.cpp:15
#define INDI_VALIDATE_CALLBACK_PROPS(prop1, prop2)
Standard check for matching INDI properties in a callback.
#define INDI_IDLE
Definition indiUtils.hpp:28
#define INDI_OK
Definition indiUtils.hpp:29
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)
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
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.
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
static constexpr logPrioT LOG_NOTICE
A normal but significant condition.
static constexpr logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
static constexpr logPrioT LOG_WARNING
A condition has occurred which may become an error, but the process continues.
static constexpr logPrioT LOG_ERROR
An error has occured which the software will attempt to correct.
#define SDG_PARSEERR_WVTP
A device base class which saves telemetry.
Definition telemeter.hpp:69
int appShutdown()
Perform telemeter application shutdown.
int loadConfig(appConfigurator &config)
Load the device section from an application configurator.
int setupConfig(appConfigurator &config)
Setup an application configurator for the device section.
int16_t stateCodeT
The type of the state code.
static std::string codeText(const stateCodeT &stateCode)
Get an ASCII string corresponding to an application stateCode.
Software ERR log entry.
Log entry recording the function generator parameters.
A Telnet connection manager, wrapping libtelnet.
int write(const std::string &buffWrite, int timeoutWrite)
Write to a telnet connection.
std::string m_strRead
The accumulated string read from the device.
int noLogin()
Set flags as if we're logged in, used when device doesn't require it.
std::string m_prompt
The device's prompt, used for detecting end of transmission.
int writeRead(const std::string &strWrite, bool swallowEcho, int timeoutWrite, int timeoutRead)
Write to a telnet connection, then get the reply.
int read(const std::string &eot, int timeoutRead, bool clear=true)
Read from a telnet connection, until end-of-transmission string is read.
int connect(const std::string &host, const std::string &port)
Connect to the device.
#define TELEM_FXNGEN_WVTP_DC
#define TELEM_FXNGEN_WVTP_PULSE
#define TELEM_FXNGEN_WVTP_SINE