API
 
Loading...
Searching...
No Matches
alignLoop.hpp
Go to the documentation of this file.
1/** \file alignLoop.hpp
2 * \brief The MagAO-X XXXXXX header file
3 *
4 * \ingroup alignLoop_files
5 */
6
7#ifndef alignLoop_hpp
8#define alignLoop_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/** \defgroup alignLoop
15 * \brief The XXXXXX application to do YYYYYYY
16 *
17 * <a href="../handbook/operating/software/apps/XXXXXX.html">Application Documentation</a>
18 *
19 * \ingroup apps
20 *
21 */
22
23/** \defgroup alignLoop_files
24 * \ingroup alignLoop
25 */
26
27namespace MagAOX
28{
29namespace app
30{
31
32/// The MagAO-X xxxxxxxx
33/**
34 * \ingroup alignLoop
35 */
36class alignLoop : public MagAOXApp<true>, public dev::shmimMonitor<alignLoop>
37{
38 //Give the test harness access.
39 friend class alignLoop_test;
40
41 friend class dev::shmimMonitor<alignLoop>;
42
43public:
44 //The base shmimMonitor type
46
47protected:
48
49 /** \name Configurable Parameters
50 *@{
51 */
52
53 std::vector<std::string> m_ctrlDevices;
54 std::vector<std::string> m_ctrlProperties;
55 std::vector<std::string> m_ctrlCurrents;
56 std::vector<std::string> m_ctrlTargets;
57
58 std::vector<float> m_currents;
59
60 std::vector<pcf::IndiProperty> m_indiP_ctrl;
61
62 std::string m_intMatFile;
63
64 std::vector<float> m_defaultGains;
65
66 std::string m_upstreamDevice;
67 std::string m_upstreamProperty {"loop_state"};
69
70
71 ///@}
72
73 mx::improc::eigenImage<float> m_intMat;
74
75 mx::improc::eigenImage<float> m_measurements;
76 float m_delta0 {0};
77 float m_delta1 {0};
78
79 mx::improc::eigenImage<float> m_commands;
80
81 float m_ggain {0};
82
83 std::vector<float> m_gains;
84
85 bool m_ctrlEnabled {false};
86
87public:
88 /// Default c'tor.
89 alignLoop();
90
91 /// D'tor, declared and defined for noexcept.
94
95 virtual void setupConfig();
96
97 /// Implementation of loadConfig logic, separated for testing.
98 /** This is called by loadConfig().
99 */
100 int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
101
102 virtual void loadConfig();
103
104 /// Startup function
105 /**
106 *
107 */
108 virtual int appStartup();
109
110 /// Implementation of the FSM for alignLoop.
111 /**
112 * \returns 0 on no critical error
113 * \returns -1 on an error requiring shutdown
114 */
115 virtual int appLogic();
116
117 /// Shutdown the app.
118 /**
119 *
120 */
121 virtual int appShutdown();
122
123 int toggleLoop( bool onoff );
124
125 // shmimMonitor interface:
126 int allocate( const dev::shmimT &);
127
128 int processImage( void* curr_src,
129 const dev::shmimT &
130 );
131
132 int sendCommands(std::vector<float> & commands);
133
134 //INDI
135
136 pcf::IndiProperty m_indiP_deltas;
137
138 pcf::IndiProperty m_indiP_ggain;
139 pcf::IndiProperty m_indiP_ctrlEnabled;
140
143
144 static int st_setCallBack_ctrl( void * app, const pcf::IndiProperty &ipRecv)
145 {
146 return static_cast<alignLoop *>(app)->setCallBack_ctrl(ipRecv);
147 }
148
149 int setCallBack_ctrl(const pcf::IndiProperty &ipRecv);
150
152 pcf::IndiProperty m_indiP_upstream; ///< Property used to report the loop state
153
155};
156
157alignLoop::alignLoop() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
158{
159
160 return;
161}
162
164{
166
167 config.add("ctrl.devices", "", "ctrl.devices", argType::Required, "ctrl", "devices", false, "string", "Device names of the controller(s) (one per element).");
168 config.add("ctrl.properties", "", "ctrl.properties", argType::Required, "ctrl", "properties", false, "string", "Properties of the ctrl devices to which to give the commands. One per element");
169 config.add("ctrl.currents", "", "ctrl.currents", argType::Required, "ctrl", "currents", false, "vector<string>", "current elements of the properties on which base the commands.");
170 config.add("ctrl.targets", "", "ctrl.targets", argType::Required, "ctrl", "targets", false, "vector<string>", "target elements of the properties to which to send the commands.");
171
172 config.add("loop.gain", "", "loop.gain", argType::Required, "loop", "gain", false, "float", "default global loop gain.");
173 config.add("loop.intMat", "", "loop.intMat", argType::Required, "loop", "intMat", false, "string", "file name of the interaction matrix.");
174 config.add("loop.gains", "", "loop.gains", argType::Required, "loop", "gains", false, "vector<float>", "default loop gains. If single number, it is applied to all axes.");
175 config.add("loop.upstream", "", "loop.upstream", argType::Required, "loop", "upstream", false, "string", "Upstream loop device name. This loop will open, and optionally close, with the upstream loop. Default none.");
176 config.add("loop.upstreamProperty", "", "loop.upstreamProperty", argType::Required, "loop", "upstreamProperty", false, "string", "Property of upstream loop device to follow. Must be a toggle. Default is loop_state.");
177
178}
179
180int alignLoop::loadConfigImpl( mx::app::appConfigurator & _config )
181{
183
184 _config(m_ctrlDevices, "ctrl.devices");
185 _config(m_ctrlProperties, "ctrl.properties");
186 _config(m_ctrlCurrents, "ctrl.currents");
187 _config(m_ctrlTargets, "ctrl.targets");
188 _config(m_ggain, "loop.gain");
189 _config(m_intMatFile, "loop.intMat");
190 _config(m_defaultGains, "loop.gains");
191 _config(m_upstreamDevice, "loop.upstream");
192 _config(m_upstreamProperty, "loop.upstreamProperty");
193 return 0;
194}
195
197{
198 loadConfigImpl(config);
199}
200
202{
204 {
205 return log<software_error,-1>({__FILE__, __LINE__});
206 }
207
208 if(m_ctrlTargets.size() != m_ctrlDevices.size())
209 {
210 return log<software_error, -1>({__FILE__, __LINE__, "ctrl.Targets and ctrl.devices are not the same size"});
211 }
212
213 if(m_ctrlTargets.size() != m_ctrlProperties.size())
214 {
215 return log<software_error, -1>({__FILE__, __LINE__, "ctrl.Targets and ctrl.properties are not the same size"});
216 }
217
218 if(m_ctrlTargets.size() != m_ctrlCurrents.size())
219 {
220 return log<software_error, -1>({__FILE__, __LINE__, "ctrl.Currents and ctrl.properties are not the same size"});
221 }
222
223 if(m_ctrlTargets.size() != m_defaultGains.size())
224 {
225 if(m_defaultGains.size()==1)
226 {
227 float g = m_defaultGains[0];
228 m_defaultGains.resize(m_ctrlTargets.size(), g);
229 log<text_log>("Setting loop.gains gains to be same size as ctrl.Targets", logPrio::LOG_NOTICE);
230 }
231 else
232 {
233 return log<software_error, -1>({__FILE__, __LINE__, "ctrl.Targets and loop.gains are not the same size"});
234 }
235 }
236
237 CREATE_REG_INDI_RO_NUMBER( m_indiP_deltas, "deltas", "Deltas", "Deltas");
238 m_indiP_deltas.add(pcf::IndiElement("delta0"));
239 m_indiP_deltas["delta0"] = 0;
240 m_indiP_deltas.add(pcf::IndiElement("delta1"));
241 m_indiP_deltas["delta1"] = 0;
242
243 m_gains.resize(m_defaultGains.size());
244 for(size_t n=0; n < m_defaultGains.size(); ++n) m_gains[n] = m_defaultGains[n];
245
246 createStandardIndiNumber<unsigned>( m_indiP_ggain, "loop_gain", 0, 1, 0, "%0.2f");
247 m_indiP_ggain["current"] = m_ggain;
248 m_indiP_ggain["target"] = m_ggain;
250 {
252 return -1;
253 }
254
257 {
259 return -1;
260 }
261
262 m_currents.resize(m_ctrlDevices.size(), -1e15);
263
264 m_indiP_ctrl.resize(m_ctrlDevices.size());
265
266 for(size_t n=0; n< m_ctrlDevices.size();++n)
267 {
269 }
270
271 m_commands.resize(m_ctrlTargets.size(), m_ctrlTargets.size()) ;
272 m_commands.setZero();
273
274 m_intMat.resize(m_ctrlTargets.size(), m_ctrlTargets.size()) ;
275 m_intMat.setZero();
276 m_intMat(1,0) = 0.926;
277 m_intMat(1,1) = -0.370;
278 m_intMat(0,0) = 0.185;
279 m_intMat(0,1) = 0.926;
280
281/*
282 std::string intMatPath = m_calibDir + "/" + m_intMatFile;
283
284 mx::fits::fitsFile<float> ff;
285 try
286 {
287 ff.read(m_intMat, intMatPath);
288 }
289 catch(...)
290 {
291 return log<software_error, -1>({__FILE__, __LINE__, "error reading loop.intMatFile. Does it exist?"});
292 }
293
294 if(m_intMat.rows() != m_ctrlTargets.size())
295 {
296 return log<software_error, -1>({__FILE__, __LINE__, "interaction matrix wrong size: rows do not match sensor Targets"});
297 }
298
299 if(m_intMat.cols() != m_correctorTargets.size())
300 {
301 return log<software_error, -1>({__FILE__, __LINE__, "interaction matrix wrong size: cols do not match corrector Targets"});
302 }
303*/
304
305 //Get the loop state for managing offloading
306 if(m_upstreamDevice != "")
307 {
309 }
310
311 return 0;
312}
313
315{
316 if( shmimMonitorT::appLogic() < 0)
317 {
318 return log<software_error,-1>({__FILE__,__LINE__});
319 }
320
322
323 return 0;
324}
325
327{
329
330 return 0;
331}
332
334{
335 if(!m_ctrlEnabled && onoff) //not enabled so change
336 {
337 m_ctrlEnabled = true;
339 updateSwitchIfChanged(m_indiP_ctrlEnabled, "toggle", pcf::IndiElement::On, INDI_OK);
340 return 0;
341 }
342
343 if(m_ctrlEnabled && !onoff)
344 {
345 m_ctrlEnabled = false;
347 updateSwitchIfChanged(m_indiP_ctrlEnabled, "toggle", pcf::IndiElement::Off, INDI_IDLE);
348
349 return 0;
350 }
351
352 return 0;
353}
354
355inline
357{
358 static_cast<void>(dummy);
359
360 std::lock_guard<std::mutex> guard(m_indiMutex);
361
362 std::cerr << shmimMonitorT::m_width << shmimMonitorT::m_height << "\n";
364
365 return 0;
366}
367
368inline
369int alignLoop::processImage( void* curr_src,
370 const dev::shmimT & dummy
371 )
372{
373 static_cast<void>(dummy);
374
376 {
377 m_measurements.data()[nn] = (static_cast<float*>(curr_src)) [nn];
378 }
379
380
383
384 std::cout << "measurements: ";
385 for(int cc = 0; cc < m_measurements.rows(); ++cc)
386 {
387 std::cout << m_measurements(cc,0) << " ";
388 }
389 std::cout << "\n";
390
391 if(m_currents[0] < -1e14) return 0;
392
393 m_commands.matrix() = m_intMat.matrix() * m_measurements.matrix();
394
395
396
397 std::cout << "delta commands: ";
398 for(int cc = 0; cc < m_measurements.rows(); ++cc)
399 {
400 std::cout << -m_commands(cc,0) << " ";
401 }
402 std::cout << "\n";
403
404 std::vector<float> commands;
405 commands.resize(m_measurements.rows());
406
407 std::cout << "commands: ";
408 for(int cc = 0; cc < m_measurements.rows(); ++cc)
409 {
411 std::cout << commands[cc] << " ";
412 }
413 std::cout << "\n";
414
415 //And send commands.
416 int rv;
417 if(m_ctrlEnabled)
418 {
420 }
421 else
422 {
423 rv = 0;
424 }
425
426 updateIfChanged(m_indiP_deltas, std::vector<std::string>({"delta0", "delta1"}), std::vector<float>({m_delta0, m_delta1}));
427 return rv;
428}
429
430inline
431int alignLoop::sendCommands(std::vector<float> & commands)
432{
433 for(size_t n=0; n < m_ctrlDevices.size(); ++n)
434 {
435 pcf::IndiProperty ip(pcf::IndiProperty::Number);
436
437 ip.setDevice(m_ctrlDevices[n]);
438 ip.setName(m_ctrlProperties[n]);
439 ip.add(pcf::IndiElement(m_ctrlTargets[n]));
441
443 }
444
445 return 0;
446}
447
448INDI_NEWCALLBACK_DEFN(alignLoop, m_indiP_ggain)(const pcf::IndiProperty &ipRecv)
449{
450 if(ipRecv.getName() != m_indiP_ggain.getName())
451 {
452 log<software_error>({__FILE__, __LINE__, "invalid indi property received"});
453 return -1;
454 }
455
456 float target;
457
458 if( indiTargetUpdate( m_indiP_ggain, target, ipRecv, true) < 0)
459 {
460 log<software_error>({__FILE__,__LINE__});
461 return -1;
462 }
463
464 m_ggain = target;
465
466 updateIfChanged(m_indiP_ggain, "current", m_ggain);
467 updateIfChanged(m_indiP_ggain, "target", m_ggain);
468
469 log<text_log>("set global gain to " + std::to_string(m_ggain), logPrio::LOG_NOTICE);
470
471 return 0;
472}
473
474INDI_NEWCALLBACK_DEFN(alignLoop, m_indiP_ctrlEnabled)(const pcf::IndiProperty &ipRecv)
475{
476 if(ipRecv.getName() != m_indiP_ctrlEnabled.getName())
477 {
478 log<software_error>({__FILE__, __LINE__, "invalid indi property received"});
479 return -1;
480 }
481
482 //switch is toggled to on
483 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On)
484 {
485 return toggleLoop(true);
486 }
487
488 //switch is toggle to off
489 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off)
490 {
491 return toggleLoop(false);
492 }
493
494 return 0;
495}
496
497inline
498int alignLoop::setCallBack_ctrl(const pcf::IndiProperty &ipRecv)
499{
500 for(size_t n = 0; n < m_ctrlDevices.size(); ++n)
501 {
502 if( ipRecv.getDevice() == m_ctrlDevices[n])
503 {
504 if(ipRecv.getName() == m_ctrlProperties[n] && ipRecv.find(m_ctrlCurrents[n]))
505 {
506 m_currents[n] = ipRecv[m_ctrlCurrents[n]].get<float>();
507 }
508 }
509 }
510
511 return 0;
512}
513
514INDI_SETCALLBACK_DEFN(alignLoop, m_indiP_upstream)(const pcf::IndiProperty &ipRecv)
515{
516 if(ipRecv.getName() != m_indiP_upstream.getName())
517 {
518 return log<software_error>({__FILE__,__LINE__, "wrong INDI property received"});
519 }
520
521 if(!ipRecv.find("toggle")) return 0;
522
523 if(ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On && m_upstreamFollowClosed)
524 {
525 std::cerr << "upstream on\n";
526 return toggleLoop(true);
527 }
528 else if(ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off)
529 {
530 std::cerr << "upstream off\n";
531 return toggleLoop(false);
532 }
533
534 return 0;
535}
536
537
538} //namespace app
539} //namespace MagAOX
540
541#endif //alignLoop_hpp
The base-class for MagAO-X applications.
Definition MagAOXApp.hpp:73
void updateIfChanged(pcf::IndiProperty &p, const std::string &el, const T &newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI property element value if it has changed.
stateCodes::stateCodeT state()
Get the current state code.
int registerIndiPropertyNew(pcf::IndiProperty &prop, int(*)(void *, const pcf::IndiProperty &))
Register an INDI property which is exposed for others to request a New Property for.
int createStandardIndiToggleSw(pcf::IndiProperty &prop, const std::string &name, const std::string &label="", const std::string &group="")
Create a standard R/W INDI switch with a single toggle element.
void updateSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, const pcf::IndiElement::SwitchStateType &newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI switch element value if it has changed.
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)
int registerIndiPropertySet(pcf::IndiProperty &prop, const std::string &devName, const std::string &propName, int(*)(void *, const pcf::IndiProperty &))
Register an INDI property which is monitored for updates from others.
The MagAO-X xxxxxxxx.
Definition alignLoop.hpp:37
int processImage(void *curr_src, const dev::shmimT &)
pcf::IndiProperty m_indiP_ctrlEnabled
std::vector< std::string > m_ctrlProperties
Definition alignLoop.hpp:54
mx::improc::eigenImage< float > m_commands
Definition alignLoop.hpp:79
static int st_setCallBack_ctrl(void *app, const pcf::IndiProperty &ipRecv)
int toggleLoop(bool onoff)
std::vector< float > m_gains
Definition alignLoop.hpp:83
virtual int appStartup()
Startup function.
INDI_NEWCALLBACK_DECL(alignLoop, m_indiP_ctrlEnabled)
std::vector< std::string > m_ctrlCurrents
Definition alignLoop.hpp:55
std::vector< std::string > m_ctrlTargets
Definition alignLoop.hpp:56
INDI_SETCALLBACK_DECL(alignLoop, m_indiP_upstream)
pcf::IndiProperty m_indiP_deltas
int allocate(const dev::shmimT &)
dev::shmimMonitor< alignLoop > shmimMonitorT
Definition alignLoop.hpp:45
mx::improc::eigenImage< float > m_intMat
Definition alignLoop.hpp:73
std::vector< std::string > m_ctrlDevices
Definition alignLoop.hpp:53
std::string m_upstreamDevice
Definition alignLoop.hpp:66
std::vector< float > m_defaultGains
Definition alignLoop.hpp:64
std::string m_intMatFile
Definition alignLoop.hpp:62
virtual int appLogic()
Implementation of the FSM for alignLoop.
std::string m_upstreamProperty
Definition alignLoop.hpp:67
int setCallBack_ctrl(const pcf::IndiProperty &ipRecv)
virtual int appShutdown()
Shutdown the app.
pcf::IndiProperty m_indiP_ggain
std::vector< float > m_currents
Definition alignLoop.hpp:58
~alignLoop() noexcept
D'tor, declared and defined for noexcept.
Definition alignLoop.hpp:92
alignLoop()
Default c'tor.
friend class alignLoop_test
Definition alignLoop.hpp:39
INDI_NEWCALLBACK_DECL(alignLoop, m_indiP_ggain)
std::vector< pcf::IndiProperty > m_indiP_ctrl
Definition alignLoop.hpp:60
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
mx::improc::eigenImage< float > m_measurements
Definition alignLoop.hpp:75
pcf::IndiProperty m_indiP_upstream
Property used to report the loop state.
virtual void setupConfig()
int sendCommands(std::vector< float > &commands)
virtual void loadConfig()
uint32_t m_width
The width of the images in the stream.
int setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
int appLogic()
Checks the shmimMonitor thread.
uint32_t m_height
The height of the images in the stream.
int appShutdown()
Shuts down the shmimMonitor thread.
int loadConfig(mx::app::appConfigurator &config)
load the configuration system results
#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.
#define CREATE_REG_INDI_RO_NUMBER(prop, name, label, group)
Create and register a RO INDI property as a number, using the standard callback name.
@ OPERATING
The device is operating, other than homing.
#define INDI_IDLE
Definition indiUtils.hpp:28
#define INDI_OK
Definition indiUtils.hpp:29
const pcf::IndiProperty & ipRecv
updateIfChanged(m_indiP_angle, "target", m_angle)
Definition dm.hpp:24
static constexpr logPrioT LOG_NOTICE
A normal but significant condition.
Software ERR log entry.