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