API
 
Loading...
Searching...
No Matches
adcTracker.hpp
Go to the documentation of this file.
1/** \file adcTracker.hpp
2 * \brief The MagAO-X ADC Tracker header file
3 *
4 * \ingroup adcTracker_files
5 */
6
7#ifndef adcTracker_hpp
8#define adcTracker_hpp
9
10
11#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
12#include "../../magaox_git_version.h"
13
14#include <mx/math/gslInterpolator.hpp>
15#include <mx/ioutils/readColumns.hpp>
16
17/** \defgroup adcTracker
18 * \brief The MagAO-X application to track sky rotation with the atmospheric dispersion corrector.
19 *
20 * <a href="../handbook/operating/software/apps/adcTracker.html">Application Documentation</a>
21 *
22 * \ingroup apps
23 *
24 */
25
26/** \defgroup adcTracker_files
27 * \ingroup adcTracker
28 */
29
30namespace MagAOX
31{
32namespace app
33{
34
35/// The MagAO-X ADC Tracker
36/**
37 * \ingroup adcTracker
38 */
39class adcTracker : public MagAOXApp<true>
40{
41
42 //Give the test harness access.
43 friend class adcTracker_test;
44
45protected:
46
47 /** \name Configurable Parameters
48 *@{
49 */
50
51 //here add parameters which will be config-able at runtime
52 std::string m_lookupFile {"adc_lookup_table.txt"}; ///< The name of the file, in the calib directory, containing the adc lookup table. Default is 'adc_lookup_table.txt'.
53
54
55 float m_adc1zero {0}; ///< The starting point for ADC 1. Default is 0.
56
57 int m_adc1lupsign {1}; ///< The sign to apply to the lookup table value for ADC 1
58
59 float m_adc2zero {0}; ///< The starting point for ADC 2. Default is 0.
60
61 int m_adc2lupsign {1}; ///< The sign to apply to the lookup table value for ADC 2
62
63 float m_deltaAngle {0}; ///< The offset angle to apply to the looked-up values, applied to both. Default is 0.
64
65 float m_adc1delta {0}; ///< The offset angle to apply to the looked-up value for ADC 1, applied in addition to deltaAngle. Default is 0.
66
67 float m_adc2delta {0}; ///< The offset angle to apply to the looked-up value for ADC 2, applied in addition to deltaAngle. Default is 0.
68
69 float m_minZD {5.1}; ///< "The minimum zenith distance at which to interpolate and move the ADCs. Default is 0.
70
71
72 std::string m_adc1DevName {"stageadc1"}; ///< The device name of the ADC 1 stage. Default is 'stageadc1'
73 std::string m_adc2DevName {"stageadc2"}; ///< The device name of the ADC 2 stage. Default is 'stageadc2'
74
75 std::string m_tcsDevName {"tcsi"}; ///< The device name of the TCS Interface providing 'teldata.zd'. Default is 'tcsi'
76
77 float m_updateInterval {10};
78
79 ///@}
80
81 float m_maxZD {60};
82
83 std::vector<double> m_lupZD;
84 std::vector<double> m_lupADC1;
85 std::vector<double> m_lupADC2;
86
87 mx::math::gslInterpolator<mx::math::gsl_interp_linear<double>> m_terpADC1;
88 mx::math::gslInterpolator<mx::math::gsl_interp_linear<double>> m_terpADC2;
89
90 bool m_tracking {false};
91
92 float m_zd {0};
93
94public:
95 /// Default c'tor.
96 adcTracker();
97
98 /// D'tor, declared and defined for noexcept.
101
102 virtual void setupConfig();
103
104 /// Implementation of loadConfig logic, separated for testing.
105 /** This is called by loadConfig().
106 */
107 int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
108
109 virtual void loadConfig();
110
111 /// Startup function
112 /**
113 *
114 */
115 virtual int appStartup();
116
117 /// Implementation of the FSM for adcTracker.
118 /**
119 * \returns 0 on no critical error
120 * \returns -1 on an error requiring shutdown
121 */
122 virtual int appLogic();
123
124 /// Shutdown the app.
125 /**
126 *
127 */
128 virtual int appShutdown();
129
130
131 /** @name INDI
132 *
133 * @{
134 */
135protected:
136
137 pcf::IndiProperty m_indiP_tracking;
138
139 pcf::IndiProperty m_indiP_deltaAngle;
140 pcf::IndiProperty m_indiP_deltaADC1;
141 pcf::IndiProperty m_indiP_deltaADC2;
142
143 pcf::IndiProperty m_indiP_minZD;
144
145
146 pcf::IndiProperty m_indiP_teldata;
147
148
149 pcf::IndiProperty m_indiP_adc1pos;
150 pcf::IndiProperty m_indiP_adc2pos;
151
152public:
154
158
160
162
163
164
165 ///@}
166};
167
168adcTracker::adcTracker() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
169{
170
171 return;
172}
173
175{
176 config.add("adcs.lookupFile", "", "adcs.lookupFile", argType::Required, "adcs", "lookupFile", false, "string", "The name of the file, in the calib directory, containing the adc lookup table. Default is 'adc_lookup_table.txt'.");
177
178 config.add("adcs.adc1zero", "", "adcs.adc1zero", argType::Required, "adcs", "adc1zero", false, "float", "The starting point for ADC 1. Default is 0.");
179
180 config.add("adcs.adc1lupsign", "", "adcs.adc1lupsign", argType::Required, "adcs", "adc1lupsign", false, "int", "The sign to apply for the LUP values for ADC 1. Default is +1.");
181
182 config.add("adcs.adc2zero", "", "adcs.adc2zero", argType::Required, "adcs", "adc2zero", false, "float", "The starting point for ADC 2. Default is 0.");
183
184 config.add("adcs.adc2lupsign", "", "adcs.adc2lupsign", argType::Required, "adcs", "adc2lupsign", false, "int", "The sign to apply for the LUP values for ADC 2. Default is +1.");
185
186 config.add("adcs.deltaAngle", "", "adcs.deltaAngle", argType::Required, "adcs", "deltaAngle", false, "float", "The offset angle to apply to the looked-up values, applied to both. Default is 0.");
187
188 config.add("adcs.adc1delta", "", "adcs.adc1delta", argType::Required, "adcs", "adc1delta", false, "float", "The offset angle to apply to the looked-up value for ADC 1, applied in addition to deltaAngle. Default is 0.");
189
190 config.add("adcs.adc2delta", "", "adcs.adc2delta", argType::Required, "adcs", "adc2delta", false, "float", "The offset angle to apply to the looked-up value for ADC 2, applied in addition to deltaAngle. Default is 0.");
191
192 config.add("adcs.minZD", "", "adcs.minZD", argType::Required, "adcs", "minZD", false, "float", "The minimum zenith distance at which to interpolate and move the ADCs. Default is 5.1");
193
194 config.add("adcs.adc1DevName", "", "adcs.adc1devName", argType::Required, "adcs", "adc1DevName", false, "string", "The device name of the ADC 1 stage. Default is 'stageadc1'");
195
196 config.add("adcs.adc2DevName", "", "adcs.adc2devName", argType::Required, "adcs", "adc2DevName", false, "string", "The device name of the ADC 2 stage. Default is 'stageadc2'");
197
198 config.add("tcs.devName", "", "tcs.devName", argType::Required, "tcs", "devName", false, "string", "The device name of the TCS Interface providing 'teldata.zd'. Default is 'tcsi'");
199
200 config.add("tracking.updateInterval", "", "tracking.updateInterval", argType::Required, "tracking", "updateInterval", false, "float", "The interval at which to update positions, in seconds. Default is 10 secs.");
201}
202
203int adcTracker::loadConfigImpl( mx::app::appConfigurator & _config )
204{
205 _config(m_lookupFile, "adcs.lookupFile");
206 _config(m_adc1zero, "adcs.adc1zero");
207 _config(m_adc1lupsign, "adcs.adc1lupsign");
208 _config(m_adc2zero, "adcs.adc2zero");
209 _config(m_adc2lupsign, "adcs.adc2lupsign");
210 _config(m_deltaAngle, "adcs.deltaAngle");
211 _config(m_adc1delta, "adcs.adc1delta");
212 _config(m_adc2delta, "adcs.adc2delta");
213 _config(m_minZD, "adcs.minZD");
214 _config(m_adc1DevName, "adcs.adc1DevName");
215 _config(m_adc2DevName, "adcs.adc2DevName");
216
217 _config(m_tcsDevName, "tcs.devName");
218
219 _config(m_updateInterval, "tracking.updateInterval");
220
221 return 0;
222}
223
225{
226 loadConfigImpl(config);
227}
228
230{
231
232 std::string luppath = m_calibDir + "/" + m_lookupFile;
233
234 std::cerr << "Reading " << luppath << "\n";
235
236 if(mx::ioutils::readColumns<','>(luppath, m_lupZD, m_lupADC1, m_lupADC2) < 0)
237 {
238 log<software_critical>({__FILE__,__LINE__, "error reading lookup table from " + luppath});
239 return -1;
240 }
241
242 if(m_lupZD.size() != m_lupADC1.size() || m_lupZD.size()!= m_lupADC2.size())
243 {
244 log<software_critical>({__FILE__,__LINE__, "inconsistent sizes in " + luppath});
245 return -1;
246 }
247
248 log<text_log>("Read " + std::to_string(m_lupZD.size()) + " points from " + m_lookupFile);
249
252
255
256 createStandardIndiNumber<float>( m_indiP_deltaAngle, "deltaAngle", 0.0, 180.0, 0, "%0.2f");
257 m_indiP_deltaAngle["target"].set(m_deltaAngle);
258 m_indiP_deltaAngle["current"].set(m_deltaAngle);
260
261 createStandardIndiNumber<float>( m_indiP_deltaADC1, "deltaADC1", 0.0, 180.0, 0, "%0.2f");
262 m_indiP_deltaADC1["target"].set(m_adc1delta);
263 m_indiP_deltaADC1["current"].set(m_adc1delta);
265
266 createStandardIndiNumber<float>( m_indiP_deltaADC2, "deltaADC2", 0.0, 180.0, 0, "%0.2f");
267 m_indiP_deltaADC2["target"].set(m_adc2delta);
268 m_indiP_deltaADC2["current"].set(m_adc2delta);
270
271 createStandardIndiNumber<float>( m_indiP_minZD, "minZD", 0.0, 90.0, 0, "%0.2f");
272 m_indiP_minZD["target"].set(m_minZD);
273 m_indiP_minZD["current"].set(m_minZD);
275
277
278 m_indiP_adc1pos = pcf::IndiProperty(pcf::IndiProperty::Number);
280 m_indiP_adc1pos.setName("position");
281 m_indiP_adc1pos.add(pcf::IndiElement("target"));
282
283 m_indiP_adc2pos = pcf::IndiProperty(pcf::IndiProperty::Number);
285 m_indiP_adc2pos.setName("position");
286 m_indiP_adc2pos.add(pcf::IndiElement("target"));
287
289
290 return 0;
291}
292
294{
295
296 static double lastupdate = 0;
297
298 if(m_tracking && mx::sys::get_curr_time() - lastupdate > m_updateInterval)
299 {
300 float dadc1 = 0.0;
301 float dadc2 = 0.0;
302
303 if(m_zd > m_lupZD.back())
304 {
305 std::cerr << "end of lup\n";
306 dadc1 = m_lupADC1.back();
307 dadc2 = m_lupADC2.back();
308 }
309 else if(m_zd >= m_minZD)
310 {
313 }
314 else
315 {
316 std::cerr << "zenith limit\n";
317 }
318
321
322 std::cerr << "Sending adcs to: " << adc1 << " " << adc2 << "\n";
323
324
325 m_indiP_adc1pos["target"] = adc1;
327
328 m_indiP_adc2pos["target"] = adc2;
330
331 lastupdate = mx::sys::get_curr_time();
332 }
333 else if(!m_tracking) lastupdate = 0;
334
335 return 0;
336}
337
339{
340 return 0;
341}
342
343INDI_NEWCALLBACK_DEFN(adcTracker, m_indiP_tracking)(const pcf::IndiProperty &ipRecv)
344{
345 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_tracking, ipRecv);
346
347 if(!ipRecv.find("toggle")) return 0;
348
349 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On)
350 {
351 updateSwitchIfChanged(m_indiP_tracking, "toggle", pcf::IndiElement::On, INDI_IDLE);
352
353 m_tracking = true;
354
355 log<text_log>("started ADC rotation tracking");
356 }
357 else
358 {
359 updateSwitchIfChanged(m_indiP_tracking, "toggle", pcf::IndiElement::Off, INDI_IDLE);
360
361 m_tracking = false;
362
363 log<text_log>("stopped ADC rotation tracking");
364 }
365
366 return 0;
367}
368
369INDI_NEWCALLBACK_DEFN(adcTracker, m_indiP_deltaAngle)(const pcf::IndiProperty &ipRecv)
370{
371 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_deltaAngle, ipRecv);
372
373 float target;
374
375 if( indiTargetUpdate( m_indiP_deltaAngle, target, ipRecv) < 0)
376 {
377 log<software_error>({__FILE__,__LINE__});
378 return -1;
379 }
380
381 m_deltaAngle = target;
382
383 std::lock_guard<std::mutex> guard(m_indiMutex);
384
385 updateIfChanged(m_indiP_deltaAngle, "current", m_deltaAngle);
386
387 log<text_log>("set deltaAngle to " + std::to_string(m_deltaAngle));
388
389 return 0;
390}
391
392INDI_NEWCALLBACK_DEFN(adcTracker, m_indiP_deltaADC1)(const pcf::IndiProperty &ipRecv)
393{
394 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_deltaADC1, ipRecv);
395
396 float target;
397
398 if( indiTargetUpdate( m_indiP_deltaADC1, target, ipRecv) < 0)
399 {
400 log<software_error>({__FILE__,__LINE__});
401 return -1;
402 }
403
404 m_adc1delta = target;
405
406 std::lock_guard<std::mutex> guard(m_indiMutex);
407
408 updateIfChanged(m_indiP_deltaADC1, "current", m_adc1delta);
409
410 log<text_log>("set deltaADC1 to " + std::to_string(m_adc1delta));
411
412 return 0;
413}
414
415INDI_NEWCALLBACK_DEFN(adcTracker, m_indiP_deltaADC2)(const pcf::IndiProperty &ipRecv)
416{
417 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_deltaADC2, ipRecv);
418
419 float target;
420
421 if( indiTargetUpdate( m_indiP_deltaADC2, target, ipRecv) < 0)
422 {
423 log<software_error>({__FILE__,__LINE__});
424 return -1;
425 }
426
427 m_adc2delta = target;
428
429 std::lock_guard<std::mutex> guard(m_indiMutex);
430
431 updateIfChanged(m_indiP_deltaADC2, "current", m_adc2delta);
432
433 log<text_log>("set deltaADC2 to " + std::to_string(m_adc2delta));
434
435 return 0;
436}
437
438INDI_NEWCALLBACK_DEFN(adcTracker, m_indiP_minZD)(const pcf::IndiProperty &ipRecv)
439{
440 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_minZD, ipRecv);
441
442 float target;
443
444 if( indiTargetUpdate( m_indiP_minZD, target, ipRecv) < 0)
445 {
446 log<software_error>({__FILE__,__LINE__});
447 return -1;
448 }
449
450 m_minZD = target;
451
452 std::lock_guard<std::mutex> guard(m_indiMutex);
453
454 updateIfChanged(m_indiP_minZD, "current", m_minZD);
455
456 log<text_log>("set minZD to " + std::to_string(m_minZD));
457
458 return 0;
459}
460
461INDI_SETCALLBACK_DEFN(adcTracker, m_indiP_teldata)(const pcf::IndiProperty &ipRecv)
462{
463 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_teldata, ipRecv);
464
465
466 if(!ipRecv.find("zd")) return 0;
467
468 m_zd = ipRecv["zd"].get<float>();
469
470 return 0;
471}
472
473} //namespace app
474} //namespace MagAOX
475
476#endif //adcTracker_hpp
477
The base-class for MagAO-X applications.
Definition MagAOXApp.hpp:73
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.
std::string m_calibDir
The path to calibration files for MagAOX.
Definition MagAOXApp.hpp:89
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
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)
The MagAO-X ADC Tracker.
pcf::IndiProperty m_indiP_deltaADC1
std::string m_lookupFile
The name of the file, in the calib directory, containing the adc lookup table. Default is 'adc_lookup...
virtual int appShutdown()
Shutdown the app.
std::vector< double > m_lupZD
std::vector< double > m_lupADC1
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
float m_deltaAngle
The offset angle to apply to the looked-up values, applied to both. Default is 0.
float m_adc1delta
The offset angle to apply to the looked-up value for ADC 1, applied in addition to deltaAngle....
pcf::IndiProperty m_indiP_deltaADC2
pcf::IndiProperty m_indiP_teldata
INDI_NEWCALLBACK_DECL(adcTracker, m_indiP_tracking)
INDI_NEWCALLBACK_DECL(adcTracker, m_indiP_deltaADC2)
~adcTracker() noexcept
D'tor, declared and defined for noexcept.
std::string m_adc2DevName
The device name of the ADC 2 stage. Default is 'stageadc2'.
INDI_SETCALLBACK_DECL(adcTracker, m_indiP_teldata)
pcf::IndiProperty m_indiP_tracking
mx::math::gslInterpolator< mx::math::gsl_interp_linear< double > > m_terpADC1
pcf::IndiProperty m_indiP_deltaAngle
std::string m_adc1DevName
The device name of the ADC 1 stage. Default is 'stageadc1'.
pcf::IndiProperty m_indiP_adc2pos
INDI_NEWCALLBACK_DECL(adcTracker, m_indiP_deltaAngle)
friend class adcTracker_test
virtual void setupConfig()
pcf::IndiProperty m_indiP_minZD
std::string m_tcsDevName
The device name of the TCS Interface providing 'teldata.zd'. Default is 'tcsi'.
float m_adc2delta
The offset angle to apply to the looked-up value for ADC 2, applied in addition to deltaAngle....
mx::math::gslInterpolator< mx::math::gsl_interp_linear< double > > m_terpADC2
float m_adc1zero
The starting point for ADC 1. Default is 0.
adcTracker()
Default c'tor.
virtual int appStartup()
Startup function.
int m_adc1lupsign
The sign to apply to the lookup table value for ADC 1.
float m_adc2zero
The starting point for ADC 2. Default is 0.
pcf::IndiProperty m_indiP_adc1pos
INDI_NEWCALLBACK_DECL(adcTracker, m_indiP_minZD)
int m_adc2lupsign
The sign to apply to the lookup table value for ADC 2.
std::vector< double > m_lupADC2
virtual int appLogic()
Implementation of the FSM for adcTracker.
float m_minZD
"The minimum zenith distance at which to interpolate and move the ADCs. Default is 0.
INDI_NEWCALLBACK_DECL(adcTracker, m_indiP_deltaADC1)
virtual void loadConfig()
#define INDI_NEWCALLBACK_DEFN(class, prop)
Define the callback for a new property request.
#define INDI_NEWCALLBACK(prop)
Get the name of the static callback wrapper for a new property.
#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.
@ READY
The device is ready for operation, but is not operating.
#define INDI_VALIDATE_CALLBACK_PROPS(prop1, prop2)
Standard check for matching INDI properties in a callback.
#define INDI_IDLE
Definition indiUtils.hpp:28
const pcf::IndiProperty & ipRecv
updateIfChanged(m_indiP_angle, "target", m_angle)
Definition dm.hpp:24