API
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 /*
8 To do:
9 X get the code compiling
10 X create conf file
11 X 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
16 X 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 
49 namespace MagAOX
50 {
51 namespace app
52 {
53 
54 /// The MagAO-X IrisAO DM Controller
55 /**
56  * \ingroup irisaoCtrl
57  */
58 class 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 
72 protected:
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 
84 public:
85  /// Default c'tor.
86  irisaoCtrl();
87 
88  /// D'tor.
89  ~irisaoCtrl() noexcept;
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  */
129  virtual int whilePowerOff();
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 
174 protected:
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 
184 public:
185 
186 };
187 
188 irisaoCtrl::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);
197  if(m_dminputs) free(m_dminputs);
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 
211 int 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 
230 {
231 
234 
235  return 0;
236 }
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 
262 {
263  if(m_dmopen) releaseDM();
264 
267 
268  return 0;
269 }
270 
272 {
274 }
275 
277 {
279 }
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?
341  if(m_dminputs) free(m_dminputs);
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 */
370  SegmentNumber segment = 0;
371  while (MirrorIterate(m_dm, segment)){
372  SetMirrorPosition(m_dm, segment, 0, 0, 0); // z, xgrad, ygrad
373  segment++;
374  }
375  MirrorCommand(m_dm, MirrorSendSettings);
376 
377  log<text_log>("DM zeroed");
378  return 0;
379 }
380 
381 int irisaoCtrl::commandDM(void * curr_src)
382 {
383  //Based on Alex Rodack's IrisAO script
384  SegmentNumber segment = 0; // start at 0 or 1?
385  MirrorPosition position;
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??
396  GetMirrorPosition(m_dm, segment, &position);
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 */
414  MirrorCommand(m_dm, MirrorSendSettings);
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
445  MirrorRelease(m_dm);
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:75
stateCodes::stateCodeT state()
Get the current state code.
Definition: MagAOXApp.hpp:2082
int shutdown()
Get the value of the shutdown flag.
Definition: MagAOXApp.hpp:1146
bool m_powerMgtEnabled
Flag controls whether power mgt is used. Set this in the constructor of a derived app....
Definition: MagAOXApp.hpp:981
void setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
Definition: dm.hpp:569
std::string m_calibRelDir
The directory relative to the calibPath. Set this before calling dm<derivedT,realT>::loadConfig().
Definition: dm.hpp:109
void loadConfig(mx::app::appConfigurator &config)
load the configuration system results
Definition: dm.hpp:610
int appShutdown()
DM shutdown.
Definition: dm.hpp:840
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:319
int whilePowerOff()
DM Poweroff Updates.
Definition: dm.hpp:865
int appStartup()
Startup function.
Definition: dm.hpp:683
int appLogic()
DM application logic.
Definition: dm.hpp:815
int appLogic()
Checks the shmimMonitor thread.
std::thread m_smThread
A separate thread for the actual monitoring.
int appShutdown()
Shuts down the shmimMonitor thread.
The MagAO-X IrisAO DM Controller.
Definition: irisaoCtrl.hpp:59
bool m_hardwareDisable
Hardware disable flag (set to true to disable sending commands)
Definition: irisaoCtrl.hpp:80
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
Definition: irisaoCtrl.hpp:211
~irisaoCtrl() noexcept
D'tor.
Definition: irisaoCtrl.hpp:194
virtual int appStartup()
Startup function.
Definition: irisaoCtrl.hpp:229
std::string m_dserialNumber
The IrisAO DRIVER serial number.
Definition: irisaoCtrl.hpp:79
virtual int appLogic()
Implementation of the FSM for irisaoCtrl.
Definition: irisaoCtrl.hpp:238
int commandDM(void *curr_src)
Send a command to the DM.
Definition: irisaoCtrl.hpp:381
double * m_dminputs
Pre-allocated command vector, used only in commandDM.
Definition: irisaoCtrl.hpp:178
bool m_dmopen
Track whether the DM connection has been opened.
Definition: irisaoCtrl.hpp:182
MirrorHandle m_dm
IrisAO SDK handle for the DM.
Definition: irisaoCtrl.hpp:180
virtual void setupConfig()
Setup the configuration system.
Definition: irisaoCtrl.hpp:201
int zeroDM()
Zero all commands on the DM.
Definition: irisaoCtrl.hpp:355
virtual int whilePowerOff()
Maintenace while powered off.
Definition: irisaoCtrl.hpp:276
irisaoCtrl()
Default c'tor.
Definition: irisaoCtrl.hpp:188
virtual void loadConfig()
Load the configuration.
Definition: irisaoCtrl.hpp:223
uint32_t m_nbAct
The number of actuators.
Definition: irisaoCtrl.hpp:176
int initDM()
Initialize the DM and prepare for operation.
Definition: irisaoCtrl.hpp:281
virtual int appShutdown()
Shutdown the app.
Definition: irisaoCtrl.hpp:261
std::string m_mserialNumber
The IrisAO MIRROR serial number.
Definition: irisaoCtrl.hpp:78
virtual int onPowerOff()
Cleanup after a power off.
Definition: irisaoCtrl.hpp:271
float realT
This defines the datatype used to signal the DM using the ImageStreamIO library.
Definition: irisaoCtrl.hpp:68
int releaseDM()
Release the DM, making it safe to turn off power.
Definition: irisaoCtrl.hpp:419
friend class irisaoCtrl_test
Definition: irisaoCtrl.hpp:62
@ OPERATING
The device is operating, other than homing.
Definition: stateCodes.hpp:50
@ POWEROFF
The device power is off.
Definition: stateCodes.hpp:42
@ READY
The device is ready for operation, but is not operating.
Definition: stateCodes.hpp:51
@ POWERON
The device power is on.
Definition: stateCodes.hpp:43
Definition: dm.hpp:24
constexpr static logPrioT LOG_ERROR
An error has occured which the software will attempt to correct.
Definition: logPriority.hpp:40
constexpr static logPrioT LOG_WARNING
A condition has occurred which may become an error, but the process continues.
Definition: logPriority.hpp:43
constexpr static logPrioT LOG_NOTICE
A normal but significant condition.
Definition: logPriority.hpp:46