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