API
 
Loading...
Searching...
No Matches
irisaoCtrl.hpp
Go to the documentation of this file.
1/** \file irisaoCtrl.hpp
2 * \brief The MagAO-X IrisAO PTTL DM controller header file
3 *
4 * \ingroup irisaoCtrl_files
5 */
6
7/*
8To do:
9X get the code compiling
10X create conf file
11X rewrite zero_dm fcn
12* figure out best way to check for saturation (does position query state before or after sending commands to the driver?)
13* figure out shmim shape (3x37 or 37x3?)
14* error checking (IrisAO API functions don't return error codes)
15* figure out install process for irisAO .so and .h
16X re-enable power management
17*/
18
19
20
21// #define _GLIBCXX_USE_CXX11_ABI 0
22
23
24#ifndef irisaoCtrl_hpp
25#define irisaoCtrl_hpp
26
27
28#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
29#include "../../magaox_git_version.h"
30
31
32/* IrisAO SDK C Header */
33#include <irisao.mirrors.h>
34
35
36/** \defgroup irisaoCtrl
37 * \brief The MagAO-X application to control an IrisAO DM
38 *
39 * <a href="..//apps_html/page_module_irisaoCtrl.html">Application Documentation</a>
40 *
41 * \ingroup apps
42 *
43 */
44
45/** \defgroup irisaoCtrl_files
46 * \ingroup irisaoCtrl
47 */
48
49namespace MagAOX
50{
51namespace app
52{
53
54/// The MagAO-X IrisAO DM Controller
55/**
56 * \ingroup irisaoCtrl
57 */
58class irisaoCtrl : public MagAOXApp<true>, public dev::dm<irisaoCtrl,float>, public dev::shmimMonitor<irisaoCtrl>
59{
60
61 //Give the test harness access.
62 friend class irisaoCtrl_test;
63
64 friend class dev::dm<irisaoCtrl,float>;
65
66 friend class dev::shmimMonitor<irisaoCtrl>;
67
68 typedef float realT; ///< This defines the datatype used to signal the DM using the ImageStreamIO library.
69
70 size_t m_nsat {0};
71
72protected:
73
74 /** \name Configurable Parameters
75 *@{
76 */
77
78 std::string m_mserialNumber; ///< The IrisAO MIRROR serial number
79 std::string m_dserialNumber; ///< The IrisAO DRIVER serial number
80 bool m_hardwareDisable; ///< Hardware disable flag (set to true to disable sending commands)
81
82 ///@}
83
84public:
85 /// Default c'tor.
86 irisaoCtrl();
87
88 /// D'tor.
90
91 /// Setup the configuration system.
92 virtual void setupConfig();
93
94 /// Implementation of loadConfig logic, separated for testing.
95 /** This is called by loadConfig().
96 */
97 int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
98
99 /// Load the configuration
100 virtual void loadConfig();
101
102 /// Startup function
103 /** Sets up INDI, and starts the shmim thread.
104 *
105 */
106 virtual int appStartup();
107
108 /// Implementation of the FSM for irisaoCtrl.
109 /**
110 * \returns 0 on no critical error
111 * \returns -1 on an error requiring shutdown
112 */
113 virtual int appLogic();
114
115 /// Shutdown the app.
116 /**
117 *
118 */
119 virtual int appShutdown();
120
121 /// Cleanup after a power off.
122 /**
123 */
124 virtual int onPowerOff();
125
126 /// Maintenace while powered off.
127 /**
128 */
130
131 /** \name DM Base Class Interface
132 *
133 *@{
134 */
135
136 /// Initialize the DM and prepare for operation.
137 /** Application is in state OPERATING upon successful conclusion.
138 *
139 * \returns 0 on success
140 * \returns -1 on error
141 */
142 int initDM();
143
144 /// Zero all commands on the DM
145 /** This does not update the shared memory buffer.
146 *
147 * \returns 0 on success
148 * \returns -1 on error
149 */
150 int zeroDM();
151
152 /// Send a command to the DM
153 /** This is called by the shmim monitoring thread in response to a semaphore trigger.
154 *
155 * \returns 0 on success
156 * \returns -1 on error
157 */
158 int commandDM(void * curr_src);
159
160 /// Release the DM, making it safe to turn off power.
161 /** The application will be state READY at the conclusion of this.
162 *
163 * \returns 0 on success
164 * \returns -1 on error
165 */
166 int releaseDM();
167
168 ///@}
169
170 /** \name IrisAO Interface
171 *@{
172 */
173
175
176 uint32_t m_nbAct {0}; ///< The number of actuators
177
178 double * m_dminputs {nullptr}; ///< Pre-allocated command vector, used only in commandDM
179
180 MirrorHandle m_dm; ///< IrisAO SDK handle for the DM.
181
182 bool m_dmopen {false}; ///< Track whether the DM connection has been opened
183
184public:
185
186};
187
188irisaoCtrl::irisaoCtrl() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
189{
190 m_powerMgtEnabled = true;
191 return;
192}
193
195{
196 //f(m_actuator_mapping) free(m_actuator_mapping);
198
199}
200
202{
203 config.add("dm.mserialNumber", "", "dm.mserialNumber", argType::Required, "dm", "mserialNumber", false, "string", "The IrisAO MIRROR serial number used to find correct DM Profile.");
204 config.add("dm.dserialNumber", "", "dm.dserialNumber", argType::Required, "dm", "dserialNumber", false, "string", "The IrisAO DRIVER serial number used to find correct DM Profile.");
205 config.add("dm.hardwareDisable", "", "dm.hardwareDisable", argType::Required, "dm", "hardwareDisable", false, "bool", "Set to true to disable hardware for testing purposes.");
206 config.add("dm.calibRelDir", "", "dm.calibRelDir", argType::Required, "dm", "calibRelDir", false, "string", "Used to find the default config directory.");
208
209}
210
211int irisaoCtrl::loadConfigImpl( mx::app::appConfigurator & _config )
212{
213 config(m_calibRelDir, "dm.calibRelDir");
214 config(m_mserialNumber, "dm.mserialNumber");
215 config(m_dserialNumber, "dm.dserialNumber");
216 config(m_hardwareDisable, "dm.hardwareDisable");
217
219
220 return 0;
221}
222
224{
225 loadConfigImpl(config);
226
227}
228
237
239{
242
243 if(state()==stateCodes::POWEROFF) return 0;
244
246 {
247 log<text_log>("detected POWERON");
248 sleep(5);
249 return initDM();
250 }
251
252 if(m_nsat > 0)
253 {
254 log<text_log>("Saturated actuators in last second: " + std::to_string(m_nsat), logPrio::LOG_WARNING);
255 }
256 m_nsat = 0;
257
258 return 0;
259}
260
270
275
280
282{
283 log<text_log>("trying to init DM");
284 sleep(2);
285
286 if(m_dmopen)
287 {
288 log<text_log>("DM is already initialized. Release first.", logPrio::LOG_ERROR);
289 return -1;
290 }
291
292 std::string mser = mx::ioutils::toUpper(m_mserialNumber);
293 std::string dser = mx::ioutils::toUpper(m_dserialNumber);
294
295 log<text_log>("Okay, connecting now");
296 sleep(2);
297 try
298 {
299 m_dm = MirrorConnect(mser.c_str(), dser.c_str(), m_hardwareDisable); // segfault
300 }
301 catch (...)
302 {
303 return -1;
304 }
305 log<text_log>("GOT THE MIRROR HANDLE");
306 sleep(2);
307
308 // not sure the irisAO API gives us any output to check for success/failure
309 m_dmopen = true;
310
311 /*if(ret == NO_ERR) m_dmopen = true; // remember that the DM connection has been opened
312
313 if(ret != NO_ERR)
314 {
315 const char *err;
316 err = IrisAOErrorString(ret);
317 log<text_log>(std::string("DM initialization failed: ") + err, logPrio::LOG_ERROR);
318
319 m_dm = {};
320 return -1;
321 }
322
323 if (!m_dmopen)
324 {
325 log<text_log>("DM initialization failed. Couldn't open DM handle.", logPrio::LOG_ERROR);
326 return -1;
327 }*/
328
329 log<text_log>("IrisAO mirror " + mser + "with driver " + dser + " initialized", logPrio::LOG_NOTICE);
330
331 // Get number of actuators
332 // this is stupid, but I don't know how else to get this number
333 SegmentNumber segment = 0; // don't know if this should start at 0 or 1
334 while (MirrorIterate(m_dm, segment)){
335 segment++;
336 }
337 m_nbAct = 3*segment; // 3*(segment+1)
338 log<text_log>("Found " + std::to_string(segment) + " segments for IrisAO mirror " + mser, logPrio::LOG_NOTICE);
339
340 // cacao input -- FIX ME?
342 m_dminputs = (double*) calloc( m_nbAct, sizeof( double ) );
343
344 if(zeroDM() < 0)
345 {
346 log<text_log>("DM initialization failed. Error zeroing DM.", logPrio::LOG_ERROR);
347 return -1;
348 }
349
351
352 return 0;
353}
354
356{
357 if(!m_dmopen)
358 {
359 log<text_log>("DM not initialized (NULL pointer)", logPrio::LOG_ERROR);
360 return -1;
361 }
362
363 if(m_nbAct == 0)
364 {
365 log<text_log>("DM not initialized (number of actuators)", logPrio::LOG_ERROR);
366 return -1;
367 }
368
369 /* Send the all 0 command to the DM */
371 while (MirrorIterate(m_dm, segment)){
372 SetMirrorPosition(m_dm, segment, 0, 0, 0); // z, xgrad, ygrad
373 segment++;
374 }
376
377 log<text_log>("DM zeroed");
378 return 0;
379}
380
381int irisaoCtrl::commandDM(void * curr_src)
382{
383 //Based on Alex Rodack's IrisAO script
384 SegmentNumber segment = 0; // start at 0 or 1?
386 int idx;
387 while (MirrorIterate(m_dm, segment)){
388
389 // need shmim array formatted in a way that's consistent with this loop
390 idx = segment * 3; // may need (segment - 1) if they start counting segments at 1
391 SetMirrorPosition(m_dm, segment, ((float *)curr_src)[idx], ((float *)curr_src)[idx+1], ((float *)curr_src)[idx+2]); // z, xgrad, ygrad
392
393 // check if the current segment was saturated
394 // not sure you can do this here. might need to send the commands first (depends on what this is actually querying)
395 // not sure how to handle ptt in the m_instSatMap. I guess I need to saturate a whole row/column at once??
397 if (!position.reachable)
398 {
399 m_instSatMap.data()[idx] = 1;
400 m_instSatMap.data()[idx+1] = 1;
401 m_instSatMap.data()[idx+2] = 1;
402 }
403 else
404 {
405 m_instSatMap.data()[idx] = 0;
406 m_instSatMap.data()[idx+1] = 0;
407 m_instSatMap.data()[idx+2] = 0;
408 }
409
410 segment++;
411 }
412
413 /* Finally, send the command to the DM */
415
416 return 0 ;
417}
418
420{
421 // Safe DM shutdown on interrupt
422
423 if(!m_dmopen)
424 {
425 log<text_log>("dm is not initialized", logPrio::LOG_ERROR);
426 return -1;
427 }
428
430
431 if(!shutdown())
432 {
433 pthread_kill(m_smThread.native_handle(), SIGUSR1);
434 }
435
436 sleep(1); ///\todo need to trigger shmimMonitor loop to pause it.
437
438 if(zeroDM() < 0)
439 {
440 log<text_log>("DM release failed. Error zeroing DM.", logPrio::LOG_ERROR);
441 return -1;
442 }
443
444 // Close IrisAO connection
446
447 m_dmopen = false;
448 m_dm = {};
449
450 log<text_log>("IrisAO " + m_mserialNumber + " with driver " + m_dserialNumber + " reset and released", logPrio::LOG_NOTICE);
451
452 return 0;
453}
454
455} //namespace app
456} //namespace MagAOX
457
458#endif //irisaoCtrl_hpp
The base-class for MagAO-X applications.
Definition MagAOXApp.hpp:73
stateCodes::stateCodeT state()
Get the current state code.
int shutdown()
Get the value of the shutdown flag.
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
std::string m_calibRelDir
The directory relative to the calibPath. Set this before calling dm<derivedT,realT>::loadConfig().
Definition dm.hpp:107
int appShutdown()
DM shutdown.
Definition dm.hpp:880
mx::improc::eigenImage< uint8_t > m_instSatMap
The instantaneous saturation map, 0/1, set by the commandDM() function of the derived class.
Definition dm.hpp:313
int loadConfig(mx::app::appConfigurator &config)
load the configuration system results
Definition dm.hpp:616
int appStartup()
Startup function.
Definition dm.hpp:689
int setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
Definition dm.hpp:574
int appLogic()
DM application logic.
Definition dm.hpp:823
std::thread m_smThread
A separate thread for the actual monitoring.
The MagAO-X IrisAO DM Controller.
bool m_hardwareDisable
Hardware disable flag (set to true to disable sending commands)
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
~irisaoCtrl() noexcept
D'tor.
virtual int appStartup()
Startup function.
std::string m_dserialNumber
The IrisAO DRIVER serial number.
virtual int appLogic()
Implementation of the FSM for irisaoCtrl.
int commandDM(void *curr_src)
Send a command to the DM.
double * m_dminputs
Pre-allocated command vector, used only in commandDM.
bool m_dmopen
Track whether the DM connection has been opened.
MirrorHandle m_dm
IrisAO SDK handle for the DM.
virtual void setupConfig()
Setup the configuration system.
int zeroDM()
Zero all commands on the DM.
virtual int whilePowerOff()
Maintenace while powered off.
irisaoCtrl()
Default c'tor.
virtual void loadConfig()
Load the configuration.
uint32_t m_nbAct
The number of actuators.
int initDM()
Initialize the DM and prepare for operation.
virtual int appShutdown()
Shutdown the app.
std::string m_mserialNumber
The IrisAO MIRROR serial number.
virtual int onPowerOff()
Cleanup after a power off.
float realT
This defines the datatype used to signal the DM using the ImageStreamIO library.
int releaseDM()
Release the DM, making it safe to turn off power.
friend class irisaoCtrl_test
@ OPERATING
The device is operating, other than homing.
@ POWEROFF
The device power is off.
@ READY
The device is ready for operation, but is not operating.
@ POWERON
The device power is on.
Definition dm.hpp:24
static constexpr logPrioT LOG_NOTICE
A normal but significant condition.
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.