Line data Source code
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 :
18 : namespace MagAOX
19 : {
20 : namespace app
21 : {
22 :
23 : /** MagAO-X application to control TTM modulation
24 : *
25 : * \todo need tests fo ttmModulator
26 : */
27 : class ttmModulator : public MagAOXApp<>
28 : {
29 :
30 : protected:
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 :
98 : public:
99 :
100 : /// Default c'tor.
101 : ttmModulator();
102 :
103 : /// D'tor, declared and defined for noexcept.
104 0 : ~ttmModulator() noexcept
105 0 : {}
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 :
174 : protected:
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 :
200 : public:
201 0 : INDI_NEWCALLBACK_DECL(ttmModulator, m_indiP_modState);
202 0 : INDI_NEWCALLBACK_DECL(ttmModulator, m_indiP_modRadius);
203 0 : INDI_NEWCALLBACK_DECL(ttmModulator, m_indiP_modFrequency);
204 0 : INDI_NEWCALLBACK_DECL(ttmModulator, m_indiP_offset12);
205 0 : INDI_NEWCALLBACK_DECL(ttmModulator, m_indiP_offset);
206 :
207 0 : INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C1outp);
208 0 : INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C1freq);
209 0 : INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C1volts);
210 0 : INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C1ofst);
211 0 : INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C1phse);
212 :
213 0 : INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C2outp);
214 0 : INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C2freq);
215 0 : INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C2volts);
216 0 : INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C2ofst);
217 0 : INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C2phse);
218 :
219 : };
220 :
221 : inline
222 : ttmModulator::ttmModulator() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
223 : {
224 : m_powerMgtEnabled = true;
225 : return;
226 : }
227 :
228 : inline
229 0 : void ttmModulator::setupConfig()
230 : {
231 0 : config.add("limits.maxfreq", "", "limits.maxfreq", argType::Required, "limits", "maxfreq", false, "real", "The maximum frequency [Hz] which can be set through this program.");
232 0 : 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 0 : config.add("cal.voltsperld1", "", "cal.voltsperld1", argType::Required, "cal", "voltsperld1", false, "real", "The voltage per lam/D for channel 1.");
235 0 : config.add("cal.voltsperld2", "", "cal.voltsperld2", argType::Required, "cal", "voltsperld2", false, "real", "The voltage per lam/D for channel 2.");
236 0 : config.add("cal.phase", "", "cal.phase", argType::Required, "cal", "phase", false, "real", "The axis phase offset, which is applied to channel 2.");
237 :
238 0 : config.add("cal.setv1", "", "cal.setv1", argType::Required, "cal", "setv1", false, "real", "The set position voltage of chaannel 1.");
239 0 : config.add("cal.setv2", "", "cal.setv2", argType::Required, "cal", "setv2", false, "real", "The set position voltage of chaannel 2.");
240 :
241 0 : config.add("cal.setDvolts", "", "cal.setDvolts", argType::Required, "cal", "setDvolts", false, "real", "The setting ramp step size [Volts]");
242 :
243 0 : config.add("cal.modDfreq", "", "cal.modDfreq", argType::Required, "cal", "modDfreq", false, "real", "The modulation ramp frequency step size [Hz]");
244 0 : config.add("cal.modDvolts", "", "cal.modDvolts", argType::Required, "cal", "modDvolts", false, "real", "The modulation ramp voltage step size [Volts]");
245 :
246 0 : config.add("cal.rotAngle", "", "cal.rotAngle", argType::Required, "cal", "rotAngle", false, "real", "The offset rotation matrix angle in degrees.");
247 0 : config.add("cal.rotParity", "", "cal.rotParity", argType::Required, "cal", "rotParity", false, "real", "The offset rotation matrix parity, +1 or -1.");
248 0 : }
249 :
250 : inline
251 0 : void ttmModulator::loadConfig()
252 : {
253 0 : config(m_maxFreq, "limits.maxfreq");
254 :
255 0 : config(m_setVoltage_1, "cal.setv1");
256 0 : config(m_setVoltage_2, "cal.setv2");
257 :
258 0 : config(m_setDVolts, "cal.setDvolts");
259 0 : config(m_modDFreq, "cal.modDfreq");
260 0 : config(m_modDVolts, "cal.modDvolts");
261 :
262 0 : config(m_rotAngle, "cal.rotAngle");
263 0 : m_rotAngle = m_rotAngle*3.14159/180.;
264 :
265 0 : config(m_rotParity, "cal.rotParity");
266 0 : if(m_rotParity < 0) m_rotParity = -1;
267 0 : else m_rotParity = 1;
268 :
269 :
270 0 : }
271 :
272 : inline
273 0 : int ttmModulator::appStartup()
274 : {
275 : // set up the INDI properties
276 0 : REG_INDI_NEWPROP(m_indiP_modState, "modState", pcf::IndiProperty::Number);
277 0 : m_indiP_modState.add (pcf::IndiElement("current"));
278 0 : m_indiP_modState.add (pcf::IndiElement("target"));
279 0 : m_indiP_modState["current"].set(m_modState);
280 0 : m_indiP_modState["target"].set(m_modStateRequested);
281 :
282 0 : REG_INDI_NEWPROP(m_indiP_modFrequency, "modFrequency", pcf::IndiProperty::Number);
283 0 : m_indiP_modFrequency.add (pcf::IndiElement("current"));
284 0 : m_indiP_modFrequency.add (pcf::IndiElement("target"));
285 0 : m_indiP_modFrequency["current"].set(m_modFreq);
286 0 : m_indiP_modFrequency["target"].set(m_modFreqRequested);
287 :
288 0 : REG_INDI_NEWPROP(m_indiP_modRadius, "modRadius", pcf::IndiProperty::Number);
289 0 : m_indiP_modRadius.add (pcf::IndiElement("current"));
290 0 : m_indiP_modRadius.add (pcf::IndiElement("target"));
291 0 : m_indiP_modRadius["current"].set(m_modRad);
292 0 : m_indiP_modRadius["target"].set(m_modRadRequested);
293 :
294 0 : REG_INDI_NEWPROP(m_indiP_offset12, "offset12", pcf::IndiProperty::Number);
295 0 : m_indiP_offset12.add (pcf::IndiElement("dC1"));
296 0 : m_indiP_offset12.add (pcf::IndiElement("dC2"));
297 :
298 0 : REG_INDI_NEWPROP(m_indiP_offset, "offset", pcf::IndiProperty::Number);
299 0 : m_indiP_offset.add (pcf::IndiElement("x"));
300 0 : m_indiP_offset.add (pcf::IndiElement("y"));
301 :
302 0 : REG_INDI_SETPROP(m_indiP_C1outp, "fxngenmodwfs", "C1outp");
303 0 : REG_INDI_SETPROP(m_indiP_C1freq, "fxngenmodwfs", "C1freq");
304 0 : REG_INDI_SETPROP(m_indiP_C1volts, "fxngenmodwfs", "C1amp");
305 0 : REG_INDI_SETPROP(m_indiP_C1ofst, "fxngenmodwfs", "C1ofst");
306 0 : REG_INDI_SETPROP(m_indiP_C1phse, "fxngenmodwfs", "C1phse");
307 :
308 0 : REG_INDI_SETPROP(m_indiP_C2outp, "fxngenmodwfs", "C2outp");
309 0 : REG_INDI_SETPROP(m_indiP_C2freq, "fxngenmodwfs", "C2freq");
310 0 : REG_INDI_SETPROP(m_indiP_C2volts, "fxngenmodwfs", "C2amp");
311 0 : REG_INDI_SETPROP(m_indiP_C2ofst, "fxngenmodwfs", "C2ofst");
312 0 : REG_INDI_SETPROP(m_indiP_C2phse, "fxngenmodwfs", "C2phse");
313 :
314 0 : return 0;
315 : }
316 :
317 : inline
318 0 : int ttmModulator::appLogic()
319 : {
320 0 : if(state()==stateCodes::POWEROFF) return 0;
321 :
322 0 : if(state()==stateCodes::POWERON)
323 : {
324 0 : sleep(2);
325 : }
326 :
327 0 : if( calcState() < 0 )
328 : {
329 : //application failure if we can't determine state
330 0 : log<software_critical>({__FILE__,__LINE__});
331 0 : return -1;
332 : }
333 :
334 0 : if(m_modState == MODSTATE_REST)
335 : {
336 0 : state(stateCodes::NOTHOMED);
337 0 : if(!stateLogged()) log<ttmmod_params>({(uint8_t) m_modState, m_modFreq, m_modRad, 0,0});
338 : }
339 0 : else if(m_modState == MODSTATE_SET)
340 : {
341 0 : state(stateCodes::READY);
342 0 : if(!stateLogged()) log<ttmmod_params>({(uint8_t) m_modState, m_modFreq, m_modRad, 0,0});
343 : }
344 0 : else if(m_modState == MODSTATE_MIDSET)
345 : {
346 0 : state(stateCodes::ERROR);
347 0 : if(!stateLogged()) log<ttmmod_params>({(uint8_t) m_modState, m_modFreq, m_modRad, 0,0});
348 : }
349 0 : else if(m_modState == MODSTATE_MODULATING)
350 : {
351 0 : state(stateCodes::OPERATING);
352 0 : if(!stateLogged()) log<ttmmod_params>({(uint8_t) m_modState, m_modFreq, m_modRad, 0,0});
353 : }
354 :
355 : { //mutex scope
356 0 : std::lock_guard<std::mutex> lock(m_indiMutex);
357 0 : updateIfChanged(m_indiP_modState, "current", m_modState);
358 0 : updateIfChanged(m_indiP_modState, "target", m_modStateRequested);
359 0 : updateIfChanged(m_indiP_modRadius, "current", m_modRad);
360 0 : updateIfChanged(m_indiP_modRadius, "target", m_modRadRequested);
361 0 : updateIfChanged(m_indiP_modFrequency, "current", m_modFreq);
362 0 : updateIfChanged(m_indiP_modFrequency, "target", m_modFreqRequested);
363 0 : }
364 :
365 : //This is set by an INDI newProperty
366 0 : 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 0 : std::unique_lock<std::mutex> lock(m_indiMutex);
372 0 : int newState = m_modStateRequested;
373 0 : double newRad = m_modRadRequested;
374 0 : double newFreq = m_modFreqRequested;
375 :
376 0 : m_modStateRequested = MODSTATE_OFF;
377 :
378 0 : lock.unlock();
379 :
380 0 : state(stateCodes::CONFIGURING);
381 0 : if(newState == MODSTATE_REST) restTTM();
382 0 : if(newState == MODSTATE_SET) setTTM();
383 0 : if(newState == MODSTATE_MODULATING)
384 : {
385 0 : if(newRad <= 0.1 || newFreq <= 1)
386 : {
387 0 : log<text_log>("radius or frequency too low", logPrio::LOG_ERROR);
388 : }
389 : else
390 : {
391 0 : modTTM(newRad, newFreq);
392 : }
393 : }
394 0 : calcState();
395 :
396 : //Do this now for responsiveness.
397 0 : if(m_modState == MODSTATE_REST)
398 : {
399 0 : state(stateCodes::NOTHOMED);
400 0 : if(!stateLogged()) log<ttmmod_params>({(uint8_t) m_modState, m_modFreq, m_modRad, 0,0});
401 : }
402 0 : else if(m_modState == MODSTATE_SET)
403 : {
404 0 : state(stateCodes::READY);
405 0 : if(!stateLogged()) log<ttmmod_params>({(uint8_t) m_modState, m_modFreq, m_modRad, 0,0});
406 : }
407 0 : else if(m_modState == MODSTATE_MIDSET)
408 : {
409 0 : state(stateCodes::ERROR);
410 0 : if(!stateLogged()) log<ttmmod_params>({(uint8_t) m_modState, m_modFreq, m_modRad, 0,0});
411 : }
412 0 : else if(m_modState == MODSTATE_MODULATING)
413 : {
414 0 : state(stateCodes::OPERATING);
415 0 : if(!stateLogged()) log<ttmmod_params>({(uint8_t) m_modState, m_modFreq, m_modRad, 0,0});
416 : }
417 :
418 0 : }
419 0 : return 0;
420 :
421 : }
422 :
423 :
424 :
425 : inline
426 0 : int ttmModulator::appShutdown()
427 : {
428 : //don't bother
429 0 : return 0;
430 : }
431 :
432 : inline
433 0 : int ttmModulator::calcState()
434 : {
435 : //Need TTM power state here.
436 :
437 0 : if( m_C1outp < 1 || m_C2outp < 1 ) //At least one channel off
438 : {
439 : //Need to also check fxn gen pwr state here
440 0 : m_modState = MODSTATE_REST;
441 : }
442 0 : 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 0 : if(/*m_C1ofst == m_setVoltage_1 && m_C2ofst == m_setVoltage_2 &&*/ m_C1phse == 0 && m_C2phse == 0 )
449 : {
450 0 : m_modState = MODSTATE_SET;
451 : }
452 : else
453 : {
454 0 : m_modState = MODSTATE_MIDSET; //must be setting
455 : }
456 : }
457 : else
458 : {
459 0 : if(m_C1freq != m_C2freq)
460 : {
461 0 : m_modState = MODSTATE_MIDSET;
462 : }
463 : else
464 : {
465 : //Possibly some more checks
466 0 : m_modFreq = m_C1freq;
467 :
468 : //Interpolate on C1.
469 0 : size_t ngt = 0;
470 :
471 0 : for(ngt = 0; ngt < m_calFreqs.size(); ++ngt)
472 : {
473 0 : if( m_calFreqs[ngt] >= m_modFreq) break;
474 : }
475 :
476 : double terpC1Amp;
477 0 : if(ngt == 0 || m_calFreqs[ngt] == m_modFreq)
478 : {
479 0 : terpC1Amp = m_calC1Amps[ngt];
480 : }
481 : else
482 : {
483 0 : size_t nlt = ngt -1;
484 0 : double dfreq = (m_modFreq - m_calFreqs[nlt])/(m_calFreqs[ngt]-m_calFreqs[nlt]);
485 0 : terpC1Amp = m_calC1Amps[nlt] + (m_calC1Amps[ngt]-m_calC1Amps[nlt])*dfreq;
486 :
487 : }
488 :
489 0 : m_modRad = m_C1volts/terpC1Amp * m_calRadius;
490 :
491 0 : m_modState = MODSTATE_MODULATING;
492 : }
493 : }
494 :
495 0 : return 0;
496 : }
497 :
498 0 : void nanoSleep( unsigned long nsec )
499 : {
500 0 : std::this_thread::sleep_for( std::chrono::duration<unsigned long, std::nano>(nsec));
501 0 : }
502 :
503 : template<typename T>
504 0 : int waitValue( const T & var,
505 : const T & tgtVal,
506 : unsigned long timeout = 5000000000,
507 : unsigned long pauseWait = 1000000
508 : )
509 : {
510 0 : if(var == tgtVal) return 0;
511 :
512 : struct timespec ts0, ts1;
513 0 : clock_gettime(CLOCK_REALTIME, &ts0);
514 0 : ts1 = ts0;
515 :
516 :
517 0 : while( (ts1.tv_sec - ts0.tv_sec)*1e9 + (ts1.tv_nsec - ts0.tv_nsec) < timeout)
518 : {
519 0 : if(var == tgtVal) return 0;
520 :
521 0 : nanoSleep(pauseWait);
522 :
523 0 : clock_gettime(CLOCK_REALTIME, &ts1);
524 : }
525 :
526 0 : if(var == tgtVal) return 0;
527 :
528 0 : std::cerr << "Timeout: " << (ts1.tv_sec - ts0.tv_sec)*1e9 + (ts1.tv_nsec - ts0.tv_nsec) << "\n";
529 :
530 0 : return -1;
531 :
532 : }
533 :
534 : template<typename T>
535 0 : int waitValue( const T & var,
536 : const T & tgtVal,
537 : double tol,
538 : unsigned long timeout = 5000000000,
539 : unsigned long pauseWait = 1000000
540 : )
541 : {
542 0 : if(fabs(tgtVal - var) <= tol) return 0;
543 :
544 : struct timespec ts0, ts1;
545 0 : clock_gettime(CLOCK_REALTIME, &ts0);
546 0 : ts1 = ts0;
547 :
548 0 : while( (ts1.tv_sec - ts0.tv_sec)*1e9 + (ts1.tv_nsec - ts0.tv_nsec) < timeout)
549 : {
550 0 : if(fabs(tgtVal - var) <= tol) return 0;
551 :
552 0 : nanoSleep(pauseWait);
553 :
554 0 : clock_gettime(CLOCK_REALTIME, &ts1);
555 : }
556 :
557 0 : if(fabs(tgtVal - var) <= tol) return 0;
558 :
559 0 : std::cerr << "Timeout: " << (ts1.tv_sec - ts0.tv_sec)*1e9 + (ts1.tv_nsec - ts0.tv_nsec) << "\n";
560 0 : return -1;
561 :
562 : }
563 :
564 : inline
565 0 : int ttmModulator::restTTM()
566 : {
567 : //Steps:
568 : //1) Set freqs to 0
569 0 : if( sendNewProperty(m_indiP_C1freq, "target", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
570 0 : 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 0 : if( sendNewProperty(m_indiP_C1volts, "target", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
574 0 : if( sendNewProperty(m_indiP_C2volts, "target", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
575 :
576 : //3) Set phase to 0
577 0 : if( sendNewProperty(m_indiP_C1phse, "value", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
578 0 : if( sendNewProperty(m_indiP_C2phse, "value", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
579 :
580 : //4) Set offset to 0
581 0 : if( sendNewProperty(m_indiP_C1ofst, "value", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
582 0 : if( sendNewProperty(m_indiP_C2ofst, "value", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
583 :
584 : //5) Set outputs to off
585 0 : if( sendNewProperty(m_indiP_C1outp, "value", "Off") < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
586 0 : if( sendNewProperty(m_indiP_C2outp, "value", "Off") < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
587 :
588 : //Now check if values have changed.
589 0 : if( waitValue(m_C1freq, 0.0) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
590 0 : if( waitValue(m_C2freq, 0.0) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
591 0 : if( waitValue(m_C1volts, 0.002, 1e-6) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
592 0 : if( waitValue(m_C2volts, 0.002, 1e-6) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
593 0 : if( waitValue(m_C1phse, 0.0) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
594 0 : if( waitValue(m_C2phse, 0.0) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
595 0 : if( waitValue(m_C1ofst, 0.001, 1e-6) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
596 0 : if( waitValue(m_C2ofst, 0.001, 1e-6) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
597 0 : if( waitValue(m_C1outp, 0) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
598 0 : if( waitValue(m_C2outp, 0) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
599 :
600 0 : log<text_log>("The PyWFS TTM is rested.", logPrio::LOG_NOTICE);
601 :
602 0 : return 0;
603 : }
604 :
605 : inline
606 0 : int ttmModulator::setTTM()
607 : {
608 0 : if(m_modState == MODSTATE_SET) //already Set.
609 : {
610 0 : return 0;
611 : }
612 :
613 0 : if(m_modState == MODSTATE_MODULATING) //Modulating
614 : {
615 0 : log<text_log>("Stopping modulation.", logPrio::LOG_INFO);
616 :
617 : //Steps:
618 : //1) Set freqs to 0
619 0 : if( sendNewProperty(m_indiP_C1freq, "target", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
620 :
621 0 : 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 0 : if( sendNewProperty(m_indiP_C1volts, "target", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
625 :
626 0 : if( sendNewProperty(m_indiP_C2volts, "target", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
627 :
628 : //3) Set phase to 0
629 0 : if( sendNewProperty(m_indiP_C1phse, "value", 0.0) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
630 :
631 0 : 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 0 : if( waitValue(m_C1freq, 0.0) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
635 0 : if( waitValue(m_C2freq, 0.0) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
636 0 : if( waitValue(m_C1volts, 0.002, 1e-6) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
637 0 : if( waitValue(m_C2volts, 0.002,1e-6) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
638 0 : if( waitValue(m_C1phse, 0.0) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
639 0 : if( waitValue(m_C2phse, 0.0) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
640 :
641 0 : m_modFreq = 0;
642 0 : m_modFreqRequested = 0;
643 0 : m_modRad = 0;
644 0 : m_modRadRequested = 0;
645 :
646 0 : log<text_log>("PyWFS TTM is set.", logPrio::LOG_NOTICE);
647 0 : 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:
654 0 : if( m_modState != MODSTATE_REST)
655 : {
656 0 : if( restTTM() < 0 ) return log<software_error, -1>({__FILE__, __LINE__});
657 :
658 0 : sleep(1);
659 : }
660 :
661 0 : log<text_log>("Setting the PyWFS TTM.", logPrio::LOG_INFO);
662 :
663 : //2) Set outputs to on
664 0 : if( sendNewProperty(m_indiP_C1outp, "value", "On") < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
665 0 : if( sendNewProperty(m_indiP_C2outp, "value", "On") < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
666 :
667 0 : if( waitValue(m_C1outp, 1) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
668 0 : if( waitValue(m_C2outp, 1) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
669 :
670 : //3) Now we begin ramp . . .
671 0 : size_t N1 = m_setVoltage_1/m_setDVolts;
672 0 : size_t N2 = m_setVoltage_2/m_setDVolts;
673 :
674 0 : size_t N = N1;
675 0 : if(N2 < N1) N = N2;
676 :
677 0 : log<text_log>("Ramping with " + std::to_string(N) + " steps. [" + std::to_string(N1) + " " + std::to_string(N2) + "]", logPrio::LOG_DEBUG);
678 :
679 0 : for(size_t i=1; i< N ; ++i)
680 : {
681 0 : double nv = i*m_setDVolts;
682 :
683 0 : if(nv < 0 || nv > 10) return log<software_error,-1>({__FILE__, __LINE__, "Bad voltage calculated. Refusing."});
684 :
685 0 : if( sendNewProperty(m_indiP_C1ofst, "value", nv) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
686 :
687 0 : if( waitValue(m_C1ofst, nv, 1e-10) < 0 ) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
688 :
689 0 : sleep(1);
690 :
691 0 : if( sendNewProperty(m_indiP_C2ofst, "value", nv) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
692 :
693 0 : if( waitValue(m_C2ofst, nv, 1e-6) < 0 ) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
694 :
695 0 : sleep(1);
696 : }
697 :
698 0 : for(size_t j=N; j< N1;++j)
699 : {
700 0 : double nv = j*m_setDVolts;
701 :
702 0 : if(nv < 0 || nv > 10) return log<software_error,-1>({__FILE__, __LINE__, "Bad voltage calculated. Refusing."});
703 :
704 0 : if( sendNewProperty(m_indiP_C1ofst, "value", nv) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
705 :
706 0 : if( waitValue(m_C1ofst, nv, 1e-6) < 0 ) return log<software_error, -1>({__FILE__,__LINE__, "fxngen timeout"});
707 :
708 0 : sleep(1);
709 : }
710 :
711 0 : for(size_t j=N; j< N2;++j)
712 : {
713 0 : double nv = j*m_setDVolts;
714 :
715 0 : if(nv < 0 || nv > 10) return log<software_error,-1>({__FILE__, __LINE__, "Bad voltage calculated. Refusing."});
716 :
717 0 : if( sendNewProperty(m_indiP_C2ofst, "value", nv) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
718 :
719 0 : if( waitValue(m_C2ofst, nv, 1e-6) < 0 ) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
720 :
721 0 : sleep(1);
722 : }
723 :
724 0 : if(m_C1ofst < m_setVoltage_1)
725 : {
726 0 : if( m_setVoltage_1 < 0 || m_setVoltage_1 > 10) return log<software_error,-1>({__FILE__, __LINE__, "Bad voltage calculated. Refusing."});
727 :
728 0 : if( (sendNewProperty(m_indiP_C1ofst, "value", m_setVoltage_1) < 0 ) ) return log<software_error,-1>({__FILE__,__LINE__});
729 :
730 0 : if(waitValue(m_C1ofst, m_setVoltage_1, 1e-6) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
731 :
732 : }
733 :
734 0 : if(m_C2ofst < m_setVoltage_2)
735 : {
736 0 : if( m_setVoltage_2 < 0 || m_setVoltage_2 > 10) return log<software_error,-1>({__FILE__, __LINE__, "Bad voltage calculated. Refusing."});
737 :
738 0 : if( (sendNewProperty(m_indiP_C2ofst, "value", m_setVoltage_2) < 0 ) ) return log<software_error,-1>({__FILE__,__LINE__});
739 :
740 0 : if( waitValue(m_C2ofst, m_setVoltage_2, 1e-6) < 0) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
741 :
742 : }
743 :
744 0 : log<text_log>("PyWFS TTM is set.", logPrio::LOG_NOTICE);
745 :
746 0 : 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 :
756 : inline
757 0 : int ttmModulator::modTTM( double newRad,
758 : double newFreq
759 : )
760 : {
761 : /// \todo log this
762 0 : 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.
768 0 : if( m_modState == MODSTATE_MODULATING)
769 : {
770 0 : if(newRad == m_modRad && newFreq == m_modFreq) return 0;
771 :
772 0 : if( setTTM() < 0 ) return log<software_error, -1>({__FILE__, __LINE__});
773 :
774 0 : if( calcState() < 0) return log<software_error, -1>({__FILE__,__LINE__});
775 :
776 : }
777 :
778 : //If not set, we first check if we are fully rested.
779 0 : if( m_modState < MODSTATE_SET )
780 : {
781 0 : if( setTTM() < 0 ) return log<software_error, -1>({__FILE__, __LINE__});
782 :
783 0 : if( calcState() < 0 ) return log<software_error, -1>({__FILE__,__LINE__});
784 :
785 0 : if( m_modState < MODSTATE_SET) return log<software_error, -1>({__FILE__,__LINE__, "TTM not set/setable."});
786 : }
787 :
788 : //Check frequency for safety.
789 0 : if(newFreq > m_maxFreq)
790 : {
791 0 : log<text_log>("Requested frequency " + std::to_string(newFreq) + " Hz exceeds limit (" + std::to_string(m_maxFreq) + " Hz). Limiting.", logPrio::LOG_WARNING);
792 0 : newFreq = m_maxFreq;
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 0 : double terpC1Amp = 0;
803 0 : double terpC2Amp = 0;
804 0 : double terpC2Phse = 0;
805 :
806 0 : size_t ngt = 0;
807 :
808 0 : for(ngt = 0; ngt < m_calFreqs.size(); ++ngt)
809 : {
810 0 : if( m_calFreqs[ngt] >= newFreq) break;
811 : }
812 :
813 0 : if(ngt == 0 || m_calFreqs[ngt] == newFreq)
814 : {
815 0 : terpC1Amp = m_calC1Amps[ngt];
816 0 : terpC2Amp = m_calC2Amps[ngt];
817 0 : terpC2Phse = m_calC2Phse[ngt];
818 : }
819 : else
820 : {
821 0 : size_t nlt = ngt -1;
822 0 : double dfreq = (newFreq - m_calFreqs[nlt])/(m_calFreqs[ngt]-m_calFreqs[nlt]);
823 :
824 0 : terpC1Amp = m_calC1Amps[nlt] + (m_calC1Amps[ngt]-m_calC1Amps[nlt])*dfreq;
825 0 : terpC2Amp = m_calC2Amps[nlt] + (m_calC2Amps[ngt]-m_calC2Amps[nlt])*dfreq;
826 0 : terpC2Phse = m_calC2Phse[nlt] + (m_calC2Phse[ngt]-m_calC2Phse[nlt])*dfreq;
827 : }
828 :
829 :
830 0 : voltageC1 = terpC1Amp*(newRad/m_calRadius);
831 0 : voltageC2 = terpC2Amp*(newRad/m_calRadius);
832 :
833 :
834 0 : if(voltageC1 > m_maxVolt)
835 : {
836 0 : log<text_log>("Requested ch-1 voltge " + std::to_string(voltageC1) + " V exceeds limit (" + std::to_string(m_maxVolt) + " V). Limiting.", logPrio::LOG_WARNING);
837 0 : voltageC1 = m_maxVolt;
838 : }
839 :
840 0 : if(voltageC2 > m_maxVolt)
841 : {
842 0 : log<text_log>("Requested ch-2 voltge " + std::to_string(voltageC2) + " V exceeds limit (" + std::to_string(m_maxVolt) + " V). Limiting.", logPrio::LOG_WARNING);
843 0 : voltageC2 = m_maxVolt;
844 : }
845 :
846 :
847 : //At this point we have safe calibrated voltage for the frequency.
848 :
849 0 : if( m_modState == MODSTATE_SET)
850 : {
851 : // 0) set phase
852 0 : if( sendNewProperty(m_indiP_C2phse, "value", terpC2Phse) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
853 :
854 : /// \todo should we set the offset here just to be sure?
855 :
856 : //Now check if values have changed.
857 0 : 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 0 : double nextFreq = 100.0;
861 0 : if(nextFreq > newFreq) nextFreq = newFreq;
862 :
863 : //send to device
864 0 : if( sendNewProperty(m_indiP_C1freq, "target", nextFreq) < 0 ) log<software_error,-1>({__FILE__,__LINE__});
865 0 : if( sendNewProperty(m_indiP_C2freq, "target", nextFreq) < 0 ) log<software_error,-1>({__FILE__,__LINE__});
866 :
867 : //Now check if values have changed.
868 0 : if( waitValue(m_C1freq, nextFreq, 1e-6) < 0 ) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
869 0 : 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 0 : double nextVolts1 = 0.1;
873 0 : if(nextVolts1 > voltageC1) nextVolts1 = voltageC1;
874 :
875 0 : double nextVolts2 = 0.1;
876 0 : if(nextVolts2 > voltageC2) nextVolts2 = voltageC2;
877 :
878 : //send to device
879 0 : if( sendNewProperty(m_indiP_C1volts, "target", nextVolts1) < 0 ) return log<software_error, -1>({__FILE__,__LINE__});
880 0 : if( sendNewProperty(m_indiP_C2volts, "target", nextVolts2) < 0 ) return log<software_error, -1>({__FILE__,__LINE__});
881 :
882 :
883 : //Now check if values have changed.
884 0 : if( waitValue(m_C1volts, nextVolts1, 1e-6) < 0 ) log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
885 0 : 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 0 : double currFreq = m_C1freq;
889 :
890 0 : nextFreq = 500.0;
891 0 : if(nextFreq > newFreq) nextFreq = newFreq;
892 :
893 : ///\todo make frequency tolerance a configurable
894 0 : while( fabs(currFreq - newFreq) > 1e-4)
895 : {
896 0 : if( sendNewProperty(m_indiP_C1freq, "target", nextFreq) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
897 0 : if( sendNewProperty(m_indiP_C2freq, "target", nextFreq) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
898 :
899 : //Now check if values have changed.
900 0 : if( waitValue(m_C1freq, nextFreq, 1e-6) < 0 ) return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout"});
901 0 : 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 0 : sleep(1);
905 0 : currFreq = m_C1freq;
906 0 : nextFreq = currFreq + m_modDFreq;
907 0 : if(nextFreq > newFreq) nextFreq = newFreq;
908 : }
909 :
910 : // 4) Now increase amplitude in 0.1 V increments.
911 0 : double currVolts1 = m_C1volts;
912 0 : double currVolts2 = m_C2volts;
913 :
914 0 : nextVolts1 = 0.2;
915 0 : if(nextVolts1 > voltageC1) nextVolts1 = voltageC1;
916 :
917 0 : nextVolts2 = 0.2;
918 0 : if(nextVolts2 > voltageC2) nextVolts2 = voltageC2;
919 : ///\todo make voltage tolerance a configurable.
920 0 : while( fabs(currVolts1 - voltageC1) > 1e-4 || fabs(currVolts2 - voltageC2) > 1e-4)
921 : {
922 0 : if( sendNewProperty(m_indiP_C1volts, "target", nextVolts1) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
923 0 : if( sendNewProperty(m_indiP_C2volts, "target", nextVolts2) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
924 :
925 : //Now check if values have changed.
926 0 : if( waitValue(m_C1volts, nextVolts1, 1e-3) < 0 )
927 : {
928 0 : return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout C1"});
929 : }
930 :
931 0 : if( waitValue(m_C2volts, nextVolts2, 1e-3) < 0 )
932 : {
933 0 : return log<software_error,-1>({__FILE__,__LINE__, "fxngen timeout C2"});
934 : }
935 :
936 0 : sleep(1);
937 0 : currVolts1 = m_C1volts;
938 0 : nextVolts1 = currVolts1 + m_modDVolts;
939 0 : if(nextVolts1 > voltageC1) nextVolts1 = voltageC1;
940 :
941 0 : currVolts2 = m_C2volts;
942 0 : nextVolts2 = currVolts2 + m_modDVolts;
943 0 : if(nextVolts2 > voltageC2) nextVolts2 = voltageC2;
944 :
945 : }
946 :
947 0 : m_modRad = newRad;
948 0 : m_modFreq = newFreq;
949 : }
950 0 : else return log<software_error,-1>({__FILE__,__LINE__, "TTM not set but should be by now."});
951 :
952 :
953 0 : return 0;
954 : }
955 :
956 : inline
957 0 : int ttmModulator::offset12( double d1,
958 : double d2
959 : )
960 : {
961 :
962 0 : if( sendNewProperty(m_indiP_C1ofst, "value", m_C1ofst + d1) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
963 0 : if( sendNewProperty(m_indiP_C2ofst, "value", m_C2ofst + d2) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
964 :
965 0 : return 0;
966 :
967 : }
968 :
969 : inline
970 0 : int ttmModulator::offsetXY( double dx,
971 : double dy
972 : )
973 : {
974 0 : double cs = cos(m_rotAngle);
975 0 : double ss = sin(m_rotAngle);
976 :
977 0 : double rdx = dx * cs - dy * ss;
978 0 : double rdy = m_rotParity*(dx * ss + dy * cs);
979 :
980 0 : if( sendNewProperty(m_indiP_C1ofst, "value", m_C1ofst + rdx) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
981 0 : if( sendNewProperty(m_indiP_C2ofst, "value", m_C2ofst + rdy) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
982 :
983 0 : return 0;
984 :
985 : }
986 :
987 0 : INDI_NEWCALLBACK_DEFN(ttmModulator, m_indiP_modState)(const pcf::IndiProperty &ipRecv)
988 : {
989 0 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_modState, ipRecv);
990 :
991 : int target;
992 :
993 0 : if( indiTargetUpdate( m_indiP_modState, target, ipRecv, false) < 0)
994 : {
995 0 : return log<software_error, -1>({__FILE__,__LINE__});
996 : }
997 :
998 0 : 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 0 : return 0;
1016 : }
1017 :
1018 0 : INDI_NEWCALLBACK_DEFN(ttmModulator, m_indiP_modFrequency)(const pcf::IndiProperty &ipRecv)
1019 : {
1020 0 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_modFrequency, ipRecv);
1021 :
1022 : double target;
1023 0 : if( indiTargetUpdate( m_indiP_modFrequency, target, ipRecv, false) < 0)
1024 : {
1025 0 : return log<software_error, -1>({__FILE__,__LINE__});
1026 : }
1027 :
1028 0 : if(target > 0)
1029 : {
1030 0 : 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 0 : return 0;
1047 :
1048 : }
1049 :
1050 0 : INDI_NEWCALLBACK_DEFN(ttmModulator, m_indiP_modRadius)(const pcf::IndiProperty &ipRecv)
1051 : {
1052 0 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_modRadius, ipRecv);
1053 :
1054 : double target;
1055 0 : if( indiTargetUpdate( m_indiP_modRadius, target, ipRecv, false) < 0)
1056 : {
1057 0 : return log<software_error, -1>({__FILE__,__LINE__});
1058 : }
1059 :
1060 0 : if(target > 0)
1061 : {
1062 0 : 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 0 : return 0;
1080 :
1081 : }
1082 :
1083 0 : INDI_NEWCALLBACK_DEFN(ttmModulator, m_indiP_offset12)(const pcf::IndiProperty &ipRecv)
1084 : {
1085 0 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_offset12, ipRecv);
1086 :
1087 0 : double dx = 0;
1088 0 : if(ipRecv.find("dC1"))
1089 : {
1090 0 : dx = ipRecv["dC1"].get<double>();
1091 : }
1092 0 : std::cerr << "dC1: " << dx << "\n";
1093 :
1094 0 : double dy = 0;
1095 0 : if(ipRecv.find("dC2"))
1096 : {
1097 0 : dy = ipRecv["dC2"].get<double>();
1098 : }
1099 :
1100 0 : std::cerr << "dC2: " << dy << "\n\n";
1101 :
1102 :
1103 0 : return offset12(dx, dy);
1104 :
1105 : }
1106 :
1107 0 : INDI_NEWCALLBACK_DEFN(ttmModulator, m_indiP_offset)(const pcf::IndiProperty &ipRecv)
1108 : {
1109 0 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_offset, ipRecv);
1110 :
1111 0 : double dx = 0;
1112 0 : if(ipRecv.find("x"))
1113 : {
1114 0 : dx = ipRecv["x"].get<double>();
1115 : }
1116 0 : std::cerr << "dx: " << dx << "\n";
1117 :
1118 0 : double dy = 0;
1119 0 : if(ipRecv.find("y"))
1120 : {
1121 0 : dy = ipRecv["y"].get<double>();
1122 : }
1123 :
1124 0 : std::cerr << "dy: " << dy << "\n\n";
1125 :
1126 :
1127 0 : return offsetXY(dx, dy);
1128 :
1129 : }
1130 :
1131 :
1132 0 : INDI_SETCALLBACK_DEFN(ttmModulator, m_indiP_C1outp)(const pcf::IndiProperty &ipRecv)
1133 : {
1134 0 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C1outp, ipRecv);
1135 :
1136 : ///\todo use find to test
1137 : try
1138 : {
1139 0 : m_indiP_C1outp = ipRecv;
1140 0 : std::string outp = ipRecv["value"].getValue();
1141 :
1142 0 : if( outp == "Off" )
1143 : {
1144 0 : m_C1outp = 0;
1145 : }
1146 0 : else if (outp == "On")
1147 : {
1148 0 : m_C1outp = 1;
1149 : }
1150 : else
1151 : {
1152 0 : m_C1outp = -1;
1153 : }
1154 :
1155 0 : return 0;
1156 0 : }
1157 0 : catch(...)
1158 : {
1159 0 : log<software_error>({__FILE__, __LINE__, "exception from libcommon"});
1160 0 : return -1;
1161 0 : }
1162 :
1163 : }
1164 :
1165 0 : INDI_SETCALLBACK_DEFN(ttmModulator, m_indiP_C1freq)(const pcf::IndiProperty &ipRecv)
1166 : {
1167 0 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C1freq, ipRecv);
1168 :
1169 : ///\todo use find to test
1170 : try
1171 : {
1172 0 : m_indiP_C1freq = ipRecv;
1173 0 : double nv = ipRecv["current"].get<double>();
1174 :
1175 0 : m_C1freq = nv;
1176 :
1177 0 : return 0;
1178 : }
1179 0 : catch(...)
1180 : {
1181 0 : log<software_error>({__FILE__, __LINE__, "exception from libcommon"});
1182 0 : return -1;
1183 0 : }
1184 :
1185 : }
1186 :
1187 0 : INDI_SETCALLBACK_DEFN(ttmModulator, m_indiP_C1volts)(const pcf::IndiProperty &ipRecv)
1188 : {
1189 0 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C1volts, ipRecv);
1190 :
1191 : ///\todo use find to test
1192 : try
1193 : {
1194 0 : m_indiP_C1volts = ipRecv;
1195 0 : double nv = ipRecv["current"].get<double>();
1196 :
1197 0 : m_C1volts = nv;
1198 0 : return 0;
1199 : }
1200 0 : catch(...)
1201 : {
1202 0 : log<software_error>({__FILE__, __LINE__, "exception from libcommon"});
1203 0 : return -1;
1204 0 : }
1205 :
1206 : }
1207 :
1208 0 : INDI_SETCALLBACK_DEFN(ttmModulator, m_indiP_C1ofst)(const pcf::IndiProperty &ipRecv)
1209 : {
1210 0 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C1ofst, ipRecv);
1211 :
1212 : ///\todo use find to test
1213 : try
1214 : {
1215 0 : m_indiP_C1ofst = ipRecv;
1216 0 : double nv = ipRecv["value"].get<double>();
1217 :
1218 0 : m_C1ofst = nv;
1219 :
1220 0 : return 0;
1221 : }
1222 0 : catch(...)
1223 : {
1224 0 : log<software_error>({__FILE__, __LINE__, "exception from libcommon"});
1225 0 : return -1;
1226 0 : }
1227 :
1228 : }
1229 :
1230 0 : INDI_SETCALLBACK_DEFN(ttmModulator, m_indiP_C1phse)(const pcf::IndiProperty &ipRecv)
1231 : {
1232 :
1233 0 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C1phse, ipRecv);
1234 :
1235 : ///\todo use find to test
1236 : try
1237 : {
1238 0 : m_indiP_C1phse = ipRecv;
1239 0 : double nv = ipRecv["value"].get<double>();
1240 :
1241 0 : m_C1phse = nv;
1242 :
1243 0 : return 0;
1244 : }
1245 0 : catch(...)
1246 : {
1247 0 : log<software_error>({__FILE__, __LINE__, "exception from libcommon"});
1248 0 : return -1;
1249 0 : }
1250 :
1251 : }
1252 :
1253 0 : INDI_SETCALLBACK_DEFN(ttmModulator, m_indiP_C2outp)(const pcf::IndiProperty &ipRecv)
1254 : {
1255 0 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C2outp, ipRecv);
1256 :
1257 : ///\todo use find to test
1258 : try
1259 : {
1260 0 : m_indiP_C2outp = ipRecv;
1261 0 : std::string outp = ipRecv["value"].getValue();
1262 :
1263 0 : if( outp == "Off" )
1264 : {
1265 0 : m_C2outp = 0;
1266 : }
1267 0 : else if (outp == "On")
1268 : {
1269 0 : m_C2outp = 1;
1270 : }
1271 : else
1272 : {
1273 0 : m_C2outp = -1;
1274 : }
1275 :
1276 0 : return 0;
1277 0 : }
1278 0 : catch(...)
1279 : {
1280 0 : log<software_error>({__FILE__, __LINE__, "exception from libcommon"});
1281 0 : return -1;
1282 0 : }
1283 :
1284 : }
1285 :
1286 0 : INDI_SETCALLBACK_DEFN(ttmModulator, m_indiP_C2freq)(const pcf::IndiProperty &ipRecv)
1287 : {
1288 0 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C2freq, ipRecv);
1289 :
1290 : ///\todo use find to test
1291 : try
1292 : {
1293 0 : m_indiP_C2freq = ipRecv;
1294 0 : double nv = ipRecv["current"].get<double>();
1295 :
1296 0 : m_C2freq = nv;
1297 :
1298 0 : return 0;
1299 : }
1300 0 : catch(...)
1301 : {
1302 0 : log<software_error>({__FILE__, __LINE__, "exception from libcommon"});
1303 0 : return -1;
1304 0 : }
1305 :
1306 : }
1307 :
1308 0 : INDI_SETCALLBACK_DEFN(ttmModulator, m_indiP_C2volts)(const pcf::IndiProperty &ipRecv)
1309 : {
1310 0 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C2volts, ipRecv);
1311 :
1312 : ///\todo use find to test
1313 : try
1314 : {
1315 0 : m_indiP_C2volts = ipRecv;
1316 0 : double nv = ipRecv["current"].get<double>();
1317 :
1318 0 : m_C2volts = nv;
1319 0 : return 0;
1320 : }
1321 0 : catch(...)
1322 : {
1323 0 : log<software_error>({__FILE__, __LINE__, "exception from libcommon"});
1324 0 : return -1;
1325 0 : }
1326 :
1327 : }
1328 :
1329 0 : INDI_SETCALLBACK_DEFN(ttmModulator, m_indiP_C2ofst)(const pcf::IndiProperty &ipRecv)
1330 : {
1331 0 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C2ofst, ipRecv);
1332 :
1333 : ///\todo use find to test
1334 : try
1335 : {
1336 0 : m_indiP_C2ofst = ipRecv;
1337 :
1338 0 : double nv = ipRecv["value"].get<double>();
1339 :
1340 0 : m_C2ofst = nv;
1341 :
1342 0 : return 0;
1343 : }
1344 0 : catch(...)
1345 : {
1346 0 : log<software_error>({__FILE__, __LINE__, "exception from libcommon"});
1347 0 : return -1;
1348 0 : }
1349 :
1350 : }
1351 :
1352 0 : INDI_SETCALLBACK_DEFN(ttmModulator, m_indiP_C2phse)(const pcf::IndiProperty &ipRecv)
1353 : {
1354 0 : INDI_VALIDATE_CALLBACK_PROPS(m_indiP_C2phse, ipRecv);
1355 :
1356 : ///\todo use find to test
1357 : try
1358 : {
1359 0 : m_indiP_C2phse = ipRecv;
1360 0 : double nv = ipRecv["value"].get<double>();
1361 :
1362 0 : m_C2phse = nv;
1363 :
1364 0 : return 0;
1365 : }
1366 0 : catch(...)
1367 : {
1368 0 : log<software_error>({__FILE__, __LINE__, "exception from libcommon"});
1369 0 : return -1;
1370 0 : }
1371 : }
1372 :
1373 : } //namespace app
1374 : } //namespace MagAOX
1375 :
1376 : #endif //ttmModulator_hpp
|