API
zaberCtrl.hpp
Go to the documentation of this file.
1 /** \file zaberCtrl.hpp
2  * \brief The MagAO-X Zaber Stage Controller header file
3  *
4  * \ingroup zaberCtrl_files
5  */
6 
7 #ifndef zaberCtrl_hpp
8 #define zaberCtrl_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 zaberCtrl
15  * \brief The MagAO-X application to control a single Zaber stage
16  *
17  * <a href="../handbook/operating/software/apps/zaberCtrl.html">Application Documentation</a>
18  *
19  * \ingroup apps
20  *
21  */
22 
23 /** \defgroup zaberCtrl_files
24  * \ingroup zaberCtrl
25  */
26 
27 namespace MagAOX
28 {
29 namespace app
30 {
31 
32 /// The MagAO-X Zaber Stage Controller
33 /** Interacts with the stage through a zaberLowLevel process via INDI.
34  *
35  * \ingroup zaberCtrl
36  */
37 class zaberCtrl : public MagAOXApp<>, public dev::stdMotionStage<zaberCtrl>, public dev::telemeter<zaberCtrl>
38 {
39 
40  //Give the test harness access.
41  friend class zaberCtrl_test;
42 
43  friend class dev::stdMotionStage<zaberCtrl>;
44 
45  friend class dev::telemeter<zaberCtrl>;
46 
47 protected:
48 
49  /** \name Configurable Parameters
50  *@{
51  */
52 
53  std::string m_lowLevelName {"zaberLowLevel"};
54 
55  std::string m_stageName; ///< The name of this stage used for accessing via zaberLowLevel
56 
57  double m_countsPerMillimeter {10078.740157480315}; ///< Counts per millimeter calibration of this stage.
58 
59  unsigned long m_maxRawPos {0}; ///< Maximum counts available on this stage.
60 
61  ///@}
62 
63  double m_rawPos {0}; ///< Current raw position in counts
64  double m_tgtRawPos {0}; ///< Target raw position in counts
65  double m_stageTemp{0}; ///< Temperature reported by the stage
66 
67  double m_maxPos {0}; ///< Maximum position in mm available on this stage
68  double m_pos {0}; ///< Current position in mm
69  double m_tgtPos {0}; ///< Target position in mm.
70 
71  int m_homingState{0}; ///< The homing state, tracks the stages of homing.
72 
73 public:
74  /// Default c'tor.
75  zaberCtrl();
76 
77  /// D'tor, declared and defined for noexcept.
78  ~zaberCtrl() noexcept
79  {}
80 
81  /// Setup the configuration of this stage controller.
82  virtual void setupConfig();
83 
84  /// Implementation of loadConfig logic, separated for testing.
85  /** This is called by loadConfig().
86  */
87  int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
88 
89  ///Load the stage configuration
90  /** Calls loadConfigImpl()
91  */
92  virtual void loadConfig();
93 
94  /// Startup function
95  /**
96  *
97  */
98  virtual int appStartup();
99 
100  /// Implementation of the FSM for zaberCtrl.
101  /**
102  * \returns 0 on no critical error
103  * \returns -1 on an error requiring shutdown
104  */
105  virtual int appLogic();
106 
107  /// Shutdown the app.
108  /**
109  *
110  */
111  virtual int appShutdown();
112 
113  /// Start a high-level homing sequence.
114  /**
115  *
116  * \returns 0 on success.
117  * \returns -1 on error.
118  */
119  int startHoming();
120 
121  /// Stop the stage motion immediately.
122  /**
123  * \returns 0 on success.
124  * \returns -1 on error.
125  */
126  int stop();
127 
128  double presetNumber();
129 
130  /// Move to a new position in mm.
131  /** \todo this actually should move to a preset position by nearest integet.. A moveToMM should be used for the mm command.
132  *
133  * \returns 0 on success.
134  * \returns -1 on error.
135  */
136  int moveTo( const double & pos /**< [in] The new position in mm*/ );
137 
138 protected:
139 
140  //INDI properties for user interaction:
141  pcf::IndiProperty m_indiP_pos;
142  pcf::IndiProperty m_indiP_rawPos;
143  pcf::IndiProperty m_indiP_maxPos;
144  pcf::IndiProperty m_indiP_temp;
145 
146 public:
147 
150 
151  //INDI properties for interacting with Low-Level
152  pcf::IndiProperty m_indiP_stageState;
153  pcf::IndiProperty m_indiP_stageMaxRawPos;
154  pcf::IndiProperty m_indiP_stageRawPos;
155  pcf::IndiProperty m_indiP_stageTgtPos;
156  pcf::IndiProperty m_indiP_stageTemp;
157 
158 public:
164 
165  /** \name Telemeter Interface
166  *
167  * @{
168  */
169  int checkRecordTimes();
170 
171  int recordTelem( const telem_stage * );
172 
173  int recordTelem( const telem_zaber * );
174 
175  int recordZaber(bool force = false);
176 
177  ///@}
178 };
179 
180 zaberCtrl::zaberCtrl() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
181 {
182  m_fractionalPresets = false;
183  m_defaultPositions = false;
184 
185  return;
186 }
187 
189 {
190  config.add("stage.lowLevelName", "", "stage.lowLevelName", argType::Required, "stage", "lowLevelName", false, "string", "The name of the low-level control process actually controlling this stage. Default is zaberLowLevel.");
191 
192  config.add("stage.stageName", "", "stage.stageName", argType::Required, "stage", "stageName", false, "string", "the name of this stage in the low-level process INDI properties. Default is the configuration name.");
193 
194  config.add("stage.countsPerMillimeter", "", "stage.countsPerMillimeter", argType::Required, "stage", "countsPerMillimeter", false, "float", "The counts per mm calibration of the stage. Default is 10078.74, which applies tot he X-LRQ-DE.");
195 
196  config.add("stage.maxCounts", "", "stage.maxCounts", argType::Required, "stage", "maxCounts", false, "unsigned long", "The maximum counts possible for this stage.");
197 
199 
201 }
202 
203 
204 int zaberCtrl::loadConfigImpl( mx::app::appConfigurator & _config )
205 {
206  _config(m_lowLevelName, "stage.lowLevelName");
207 
209  _config(m_stageName, "stage.stageName");
210 
211  _config(m_countsPerMillimeter, "stage.countsPerMillimeter");
212 
213  _config(m_maxRawPos, "stage.maxCounts");
215 
217 
219 
220  return 0;
221 }
222 
224 {
225  loadConfigImpl(config);
226 }
227 
229 {
230 
231  createStandardIndiNumber<float>( m_indiP_pos, "position", 0.0, m_maxPos, 1/m_countsPerMillimeter, "%.4f");
232  m_indiP_pos["current"].set(0);
233  m_indiP_pos["target"].set(0);
235  {
236  #ifndef ZABERCTRL_TEST_NOLOG
237  log<software_error>({__FILE__,__LINE__});
238  #endif
239  return -1;
240  }
241 
242  createStandardIndiNumber<unsigned long>( m_indiP_rawPos, "rawpos", 0.0, m_maxRawPos, 1, "%lu");
243  m_indiP_rawPos["current"].set(0);
244  m_indiP_rawPos["target"].set(0);
246  {
247  #ifndef ZABERCTRL_TEST_NOLOG
248  log<software_error>({__FILE__,__LINE__});
249  #endif
250  return -1;
251  }
252 
253  createROIndiNumber( m_indiP_maxPos, "maxpos", "Maximum Position");
254  indi::addNumberElement( m_indiP_maxPos, "value", m_maxPos, m_maxPos, 0.0, "%0.4f");
255  m_indiP_maxPos["value"].set<double>(m_maxPos);
257 
258  createROIndiNumber( m_indiP_temp, "temp", "Stage Temperature [C]");
259  indi::addNumberElement( m_indiP_temp, "current", -50,100, 0, "%0.1f");
261 
262  //Register for the low level status reports
264  REG_INDI_SETPROP(m_indiP_stageMaxRawPos, m_lowLevelName, std::string("max_pos"));
265  REG_INDI_SETPROP(m_indiP_stageRawPos, m_lowLevelName, std::string("curr_pos"));
266  REG_INDI_SETPROP(m_indiP_stageTgtPos, m_lowLevelName, std::string("tgt_pos"));
267  REG_INDI_SETPROP(m_indiP_stageTemp, m_lowLevelName, std::string("temp"));
268 
269 
270  if(m_presetNames.size() != m_presetPositions.size())
271  {
272  return log<text_log,-1>("must set a position for each preset", logPrio::LOG_CRITICAL);
273  }
274 
275  m_presetNames.insert(m_presetNames.begin(), "none");
276  m_presetPositions.insert(m_presetPositions.begin(), -1);
277 
279 
281  {
282  return log<software_error,-1>({__FILE__,__LINE__});
283  }
284 
285  return 0;
286 }
287 
289 {
291  {
293  }
294 
296  {
297  //Here do poweroff update
299  {
300  log<software_error>({__FILE__,__LINE__});
301  }
302 
303  recordStage();
304 
305  //record telem if it's been longer than 10 sec:
307  {
308  log<software_error>({__FILE__, __LINE__});
309  }
310 
311  return 0;
312  }
313 
314  if(state() == stateCodes::POWERON)
315  {
316  recordStage();
317  return 0;
318  }
319 
320  if(state() == stateCodes::NOTHOMED)
321  {
323  }
324 
325  if(state() == stateCodes::HOMING)
326  {
327  if(m_homingState == 2)
328  {
329  if(m_homePreset >= 0)
330  {
333 
334  //sleep(2); //pause to give time for controller to update itself and throw a warning
335 
337  }
338 
339  m_homingState = 0;
340  }
341  }
342  //Otherwise we don't do anything differently
343  std::lock_guard<std::mutex> guard(m_indiMutex);
344 
345  static int last_moving = -10;
346 
347  bool changed = false;
348  if(last_moving != m_moving)
349  {
350  changed = true;
351  last_moving = m_moving;
352  }
353 
354  if(changed)
355  {
356  if(m_moving)
357  {
358  m_indiP_pos.setState(INDI_BUSY);
359  m_indiP_rawPos.setState(INDI_BUSY);
360  }
361  else
362  {
363  m_indiP_pos.setState(INDI_IDLE);
364  m_indiP_pos["target"] = m_pos;
365  m_indiP_rawPos.setState(INDI_IDLE);
366  m_indiP_rawPos["target"] = m_rawPos;
367  }
368 
369  m_indiDriver->sendSetProperty(m_indiP_pos);
370  m_indiDriver->sendSetProperty(m_indiP_rawPos);
371  }
372 
373  if(m_moving && m_movingState < 1)
374  {
377  }
378  else
379  {
382  }
383 
384  int n = presetNumber();
385  if(n == -1)
386  {
387  m_preset = 0;
388  m_preset_target = 0;
389  }
390  else
391  {
392  m_preset = n+1;
393  m_preset_target = n+1;
394  }
395 
396  recordStage();
397  recordZaber();
398 
400 
402  {
403  log<software_error>({__FILE__, __LINE__});
404  return 0;
405  }
406 
407  return 0;
408 }
409 
411 {
412  return 0;
413 }
414 
416 {
417  updateSwitchIfChanged(m_indiP_home, "request", pcf::IndiElement::Off, INDI_IDLE);
418 
419  pcf::IndiProperty indiP_stageHome = pcf::IndiProperty(pcf::IndiProperty::Text);
420  indiP_stageHome.setDevice(m_lowLevelName);
421  indiP_stageHome.setName("req_home");
422  indiP_stageHome.setPerm(pcf::IndiProperty::ReadWrite);
423  indiP_stageHome.setState(pcf::IndiProperty::Idle);
424  indiP_stageHome.add(pcf::IndiElement(m_stageName));
425 
426  m_moving = 2;
427  m_homingState = 1;
428  if( sendNewProperty(indiP_stageHome, m_stageName, "1") < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
429 
430  return 0;
431 }
432 
434 {
435  updateSwitchIfChanged(m_indiP_stop, "request", pcf::IndiElement::Off, INDI_IDLE);
436 
437  pcf::IndiProperty indiP_stageHalt = pcf::IndiProperty(pcf::IndiProperty::Text);
438  indiP_stageHalt.setDevice(m_lowLevelName);
439  indiP_stageHalt.setName("req_halt");
440  indiP_stageHalt.setPerm(pcf::IndiProperty::ReadWrite);
441  indiP_stageHalt.setState(pcf::IndiProperty::Idle);
442  indiP_stageHalt.add(pcf::IndiElement(m_stageName));
443 
444  if( sendNewProperty(indiP_stageHalt, m_stageName, "1") < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
445 
446  return 0;
447 }
448 
450 {
451  for( size_t n=1; n < m_presetPositions.size(); ++n)
452  {
453  if( fabs(m_pos-m_presetPositions[n]) < 1./m_countsPerMillimeter) return n;
454  }
455 
456  return 0;
457 }
458 
459 int zaberCtrl::moveTo( const double & target)
460 {
461  if(target < 0) return 0;
462 
463  m_tgtRawPos = (target*m_countsPerMillimeter + 0.5);
464 
465  pcf::IndiProperty indiP_stageTgtPos = pcf::IndiProperty(pcf::IndiProperty::Number);
466  indiP_stageTgtPos.setDevice(m_lowLevelName);
467  indiP_stageTgtPos.setName("tgt_pos");
468  indiP_stageTgtPos.setPerm(pcf::IndiProperty::ReadWrite);
469  indiP_stageTgtPos.setState(pcf::IndiProperty::Idle);
470  indiP_stageTgtPos.add(pcf::IndiElement(m_stageName));
471 
472  m_moving = 1;
474  recordZaber(true);
475 
476  if( sendNewProperty(indiP_stageTgtPos, m_stageName, m_tgtRawPos) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
477 
478  return 0;
479 }
480 
481 INDI_NEWCALLBACK_DEFN( zaberCtrl, m_indiP_pos)(const pcf::IndiProperty &ipRecv)
482 {
483  INDI_VALIDATE_CALLBACK_PROPS(m_indiP_pos, ipRecv);
484 
485  double target =-1;
486  if( ipRecv.find("target") ) //Just not our stage.
487  {
488  target = ipRecv["target"].get<double>();
489  }
490 
491  if(target < 0)
492  {
493  return 0;
494  /*if( ipRecv.find("current") ) //Just not our stage.
495  {
496  target = ipRecv["current"].get<double>();
497  }
498 
499  if(target < 0 )
500  {
501  return log<text_log,-1>("no valid target position provided", logPrio::LOG_ERROR);
502  }*/
503  }
504 
505  if(m_moving != 0)
506  {
507  log<text_log>("abs move to " + std::to_string(target) + " rejected due to already moving");
508  return 0;
509  }
510 
511  log<text_log>("moving stage to " + std::to_string(target));
512 
513  std::lock_guard<std::mutex> guard(m_indiMutex);
514 
515  m_tgtPos = target;
516 
517  moveTo(m_tgtPos);
518  updateIfChanged(m_indiP_pos, "target", m_tgtPos, INDI_BUSY);
519  updateIfChanged(m_indiP_rawPos, "target", m_tgtRawPos, INDI_BUSY);
520  return 0;
521 }
522 
523 INDI_NEWCALLBACK_DEFN( zaberCtrl, m_indiP_rawPos)(const pcf::IndiProperty &ipRecv)
524 {
525  INDI_VALIDATE_CALLBACK_PROPS(m_indiP_rawPos, ipRecv);
526 
527  double target =-1;
528  if( ipRecv.find("target") ) //Just not our stage.
529  {
530  target = ipRecv["target"].get<double>();
531  }
532 
533  if(target < 0)
534  {
535  if( ipRecv.find("current") ) //Just not our stage.
536  {
537  target = ipRecv["current"].get<double>();
538  }
539 
540  if(target < 0 )
541  {
542  return log<text_log,-1>("no valid target position provided", logPrio::LOG_ERROR);
543  }
544  }
545 
546  if(m_moving != 0)
547  {
548  log<text_log>("rel move rejected due to already moving");
549  return 0;
550  }
551 
552  log<text_log>("moving stage by " + std::to_string(target));
553 
554  std::lock_guard<std::mutex> guard(m_indiMutex);
555 
556  pcf::IndiProperty indiP_stageTgtPos = pcf::IndiProperty(pcf::IndiProperty::Text);
557  indiP_stageTgtPos.setDevice(m_lowLevelName);
558  indiP_stageTgtPos.setName("tgt_pos");
559  indiP_stageTgtPos.setPerm(pcf::IndiProperty::ReadWrite);
560  indiP_stageTgtPos.setState(pcf::IndiProperty::Idle);
561  indiP_stageTgtPos.add(pcf::IndiElement(m_stageName));
562 
564 
565  if( sendNewProperty(indiP_stageTgtPos, m_stageName, target) < 0 ) return log<software_error,-1>({__FILE__,__LINE__});
566 
567 
568  m_tgtRawPos = target;
569  m_tgtPos = m_tgtRawPos / m_countsPerMillimeter;
570  updateIfChanged(m_indiP_pos, "target", m_tgtPos, INDI_BUSY);
571  updateIfChanged(m_indiP_rawPos, "target", m_tgtRawPos, INDI_BUSY);
572  return 0;
573 }
574 
575 
576 
577 INDI_SETCALLBACK_DEFN( zaberCtrl, m_indiP_stageState)(const pcf::IndiProperty &ipRecv)
578 {
579  INDI_VALIDATE_CALLBACK_PROPS(m_indiP_stageState, ipRecv);
580 
581  if( ipRecv.find(m_stageName) != true ) //Just not our stage.
582  {
583  return 0;
584  }
585 
586  m_indiP_stageState = ipRecv;
587 
588  std::string sstr = ipRecv[m_stageName].get<std::string>();
589 
590  std::lock_guard<std::mutex> guard(m_indiMutex);
591 
592  if(sstr == "POWEROFF")
593  {
594  state(stateCodes::POWEROFF);
595  m_moving = -2;
596  }
597  else if(sstr == "POWERON")
598  {
599  state(stateCodes::POWERON);
600  m_moving = -1;
601  }
602  else if(sstr == "NODEVICE")
603  {
604  state(stateCodes::NODEVICE);
605  m_moving = -2;
606  }
607  else if(sstr == "NOTCONNECTED")
608  {
610  m_moving = -2;
611  }
612  else if(sstr == "CONNECTED")
613  {
614  state(stateCodes::CONNECTED);
615  m_moving = -2;
616  }
617  else if(sstr == "NOTHOMED")
618  {
619  state(stateCodes::NOTHOMED);
620  m_moving = -1;
621  }
622  else if(sstr == "HOMING")
623  {
624  state(stateCodes::HOMING);
625  m_homingState = 1;
626  m_moving = 2;
627  }
628  else if(sstr == "READY")
629  {
630  if(m_homingState == 0)
631  {
632  state(stateCodes::READY);
633  }
634  else
635  {
636  m_homingState = 2;
637  }
638  m_moving = 0;
639  }
640  else if(sstr == "OPERATING")
641  {
642  state(stateCodes::OPERATING);
643  m_moving = 1;
644  }
645  else if(sstr == "SHUTDOWN")
646  {
648  m_moving = -2;
649  }
650  else if(sstr == "FAILURE")
651  {
652  state(stateCodes::FAILURE);
653  m_moving = -2;
654  }
655  else if(sstr == "ERROR")
656  {
657  state(stateCodes::ERROR);
658  m_moving = -2;
659  }
660  else
661  {
662  std::cerr << "else: " << sstr << "\n";
664  m_moving = -2;
665  }
666  return 0;
667 }
668 
669 INDI_SETCALLBACK_DEFN( zaberCtrl, m_indiP_stageMaxRawPos )(const pcf::IndiProperty &ipRecv)
670 {
671  INDI_VALIDATE_CALLBACK_PROPS(m_indiP_stageMaxRawPos, ipRecv);
672 
673  if( ipRecv.find(m_stageName) != true ) //Just not our stage.
674  {
675  return 0;
676  }
677 
678  std::lock_guard<std::mutex> guard(m_indiMutex);
679 
680  long maxRawPos = ipRecv[m_stageName].get<long>();
681 
682  if(maxRawPos > 10000000000000 || maxRawPos < 0) return 0; //Indicates a bad value
683 
684  if((unsigned long) maxRawPos != m_maxRawPos && (state() == stateCodes::CONNECTED|| state() == stateCodes::HOMING || state() == stateCodes::READY || state() == stateCodes::OPERATING))
685  {
686  log<text_log>("max position mismatch between config-ed value (" + std::to_string(m_maxRawPos) + ") and stage value (" + std::to_string(maxRawPos) + ")", logPrio::LOG_WARNING);
687  }
688 
689  return 0;
690 }
691 
692 INDI_SETCALLBACK_DEFN( zaberCtrl, m_indiP_stageRawPos )(const pcf::IndiProperty &ipRecv)
693 {
694  INDI_VALIDATE_CALLBACK_PROPS(m_indiP_stageRawPos, ipRecv);
695 
696  if( ipRecv.find(m_stageName) != true ) //Just not our stage.
697  {
698  return 0;
699  }
700 
701  std::lock_guard<std::mutex> guard(m_indiMutex);
702 
703  m_rawPos = ipRecv[m_stageName].get<double>();
704 
705  m_pos = m_rawPos / m_countsPerMillimeter;
706 
707  if(m_moving)
708  {
709  updateIfChanged(m_indiP_rawPos, "current", m_rawPos, INDI_BUSY);
710  updateIfChanged(m_indiP_pos, "current", m_pos, INDI_BUSY);
711  }
712  else
713  {
714  updateIfChanged(m_indiP_rawPos, "current", m_rawPos, INDI_IDLE);
715  updateIfChanged(m_indiP_pos, "current", m_pos, INDI_IDLE);
716  }
717 
719 
720  return 0;
721 }
722 
723 INDI_SETCALLBACK_DEFN( zaberCtrl, m_indiP_stageTgtPos )(const pcf::IndiProperty &ipRecv)
724 {
725  INDI_VALIDATE_CALLBACK_PROPS(m_indiP_stageTgtPos, ipRecv);
726 
727  if( ipRecv.find(m_stageName) != true ) //Just not our stage.
728  {
729  return 0;
730  }
731 
732  //Test for empty property to see if target reached
733  std::string test = ipRecv[m_stageName].get<std::string>();
734 
735  if(test == "")
736  {
737  return 0;
738  }
739 
740  std::lock_guard<std::mutex> guard(m_indiMutex);
741 
742  m_tgtRawPos = ipRecv[m_stageName].get<double>();
743  m_tgtPos = m_tgtRawPos / m_countsPerMillimeter;
744 
745  if(m_moving)
746  {
747  updateIfChanged(m_indiP_rawPos, "target", m_tgtRawPos, INDI_BUSY);
748  updateIfChanged(m_indiP_pos, "target", m_tgtPos, INDI_BUSY);
749  }
750  else
751  {
752  updateIfChanged(m_indiP_rawPos, "target", m_tgtRawPos, INDI_IDLE);
753  updateIfChanged(m_indiP_pos, "target", m_tgtPos, INDI_IDLE);
754  }
755 
756  return 0;
757 }
758 
759 INDI_SETCALLBACK_DEFN( zaberCtrl, m_indiP_stageTemp )(const pcf::IndiProperty &ipRecv)
760 {
761  INDI_VALIDATE_CALLBACK_PROPS(m_indiP_stageTemp, ipRecv);
762 
763  if( ipRecv.find(m_stageName) != true ) //Just not our stage.
764  {
765  return 0;
766  }
767 
768  std::lock_guard<std::mutex> guard(m_indiMutex);
769 
770  m_stageTemp = ipRecv[m_stageName].get<double>();
771 
772  updateIfChanged(m_indiP_temp, "current", m_stageTemp);
773 
774  return 0;
775 }
776 
778 {
780 }
781 
783 {
785 }
786 
788 {
789  return recordZaber(true);
790 }
791 
792 int zaberCtrl::recordZaber(bool force)
793 {
794  static double last_pos = m_pos - 1000;
795  static double last_rawPos = m_rawPos;
796  static double last_temp = m_stageTemp;
797 
798  if( m_pos != last_pos || m_rawPos != last_rawPos || m_stageTemp != last_temp || force)
799  {
800  telem<telem_zaber>({(float) m_pos, (float) m_rawPos, (float) m_stageTemp});
801 
802  last_pos = m_pos;
803  last_rawPos = m_rawPos;
804  last_temp = m_stageTemp;
805  }
806 
807 
808  return 0;
809 }
810 
811 } //namespace app
812 } //namespace MagAOX
813 
814 #endif //zaberCtrl_hpp
The base-class for MagAO-X applications.
Definition: MagAOXApp.hpp:75
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.
Definition: MagAOXApp.hpp:2877
std::string m_configName
The name of the configuration file (minus .conf).
Definition: MagAOXApp.hpp:88
stateCodes::stateCodeT state()
Get the current state code.
Definition: MagAOXApp.hpp:2082
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.
indiDriver< MagAOXApp > * m_indiDriver
The INDI driver wrapper. Constructed and initialized by execute, which starts and stops communication...
Definition: MagAOXApp.hpp:537
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.
Definition: MagAOXApp.hpp:2901
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
Definition: MagAOXApp.hpp:1590
int createROIndiNumber(pcf::IndiProperty &prop, const std::string &propName, const std::string &propLabel="", const std::string &propGroup="")
Create a ReadOnly INDI Number property.
Definition: MagAOXApp.hpp:2294
int registerIndiPropertyReadOnly(pcf::IndiProperty &prop)
Register an INDI property which is read only.
Definition: MagAOXApp.hpp:2437
std::mutex m_indiMutex
Mutex for locking INDI communications.
Definition: MagAOXApp.hpp:540
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)
Definition: MagAOXApp.hpp:3031
MagAO-X standard motion stage interface.
double m_preset
The current numerical preset position [1.0 is index 0 in the preset name vector].
int loadConfig(mx::app::appConfigurator &config)
load the configuration system results
std::vector< double > m_presetPositions
The positions, in arbitrary units, of each preset. If 0, then the integer position number (starting f...
std::vector< std::string > m_presetNames
The names of each position on the stage.
bool m_powerOnHome
If true, then the motor is homed at startup (by this software or actual power on)
pcf::IndiProperty m_indiP_home
Command the stage to home. .
bool m_defaultPositions
Flag controlling whether the default preset positions (the vector index) are set in loadConfig.
int updateINDI()
Update the INDI properties for this device controller.
int setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
int m_homePreset
If >=0, this preset position is moved to after homing.
int8_t m_moving
Whether or not the stage is moving. -2 means powered off, -1 means not homed, 0 means not moving,...
pcf::IndiProperty m_indiP_stop
Command the stage to halt.
pcf::IndiProperty m_indiP_preset
The position of the stage in presets.
double m_preset_target
The target numerical preset position [1.0 is index 0 in the preset name vector].
bool m_fractionalPresets
Flag to set in constructor determining if fractional presets are allowed. Used for INDI/GUIs.
int appStartup()
Startup function.
int8_t m_movingState
Used to track the type of command. If > 1 this is a command to move to a preset. If 0 then it is a mo...
The MagAO-X Zaber Stage Controller.
Definition: zaberCtrl.hpp:38
double m_pos
Current position in mm.
Definition: zaberCtrl.hpp:68
pcf::IndiProperty m_indiP_stageMaxRawPos
Definition: zaberCtrl.hpp:153
virtual int appLogic()
Implementation of the FSM for zaberCtrl.
Definition: zaberCtrl.hpp:288
virtual int appStartup()
Startup function.
Definition: zaberCtrl.hpp:228
std::string m_lowLevelName
Definition: zaberCtrl.hpp:53
virtual void setupConfig()
Setup the configuration of this stage controller.
Definition: zaberCtrl.hpp:188
friend class zaberCtrl_test
Definition: zaberCtrl.hpp:41
int moveTo(const double &pos)
Move to a new position in mm.
Definition: zaberCtrl.hpp:459
zaberCtrl()
Default c'tor.
Definition: zaberCtrl.hpp:180
pcf::IndiProperty m_indiP_maxPos
Definition: zaberCtrl.hpp:143
INDI_NEWCALLBACK_DECL(zaberCtrl, m_indiP_rawPos)
pcf::IndiProperty m_indiP_stageTemp
Definition: zaberCtrl.hpp:156
unsigned long m_maxRawPos
Maximum counts available on this stage.
Definition: zaberCtrl.hpp:59
double m_tgtRawPos
Target raw position in counts.
Definition: zaberCtrl.hpp:64
int stop()
Stop the stage motion immediately.
Definition: zaberCtrl.hpp:433
std::string m_stageName
The name of this stage used for accessing via zaberLowLevel.
Definition: zaberCtrl.hpp:55
double m_maxPos
Maximum position in mm available on this stage.
Definition: zaberCtrl.hpp:67
virtual int appShutdown()
Shutdown the app.
Definition: zaberCtrl.hpp:410
pcf::IndiProperty m_indiP_rawPos
Definition: zaberCtrl.hpp:142
int m_homingState
The homing state, tracks the stages of homing.
Definition: zaberCtrl.hpp:71
int startHoming()
Start a high-level homing sequence.
Definition: zaberCtrl.hpp:415
~zaberCtrl() noexcept
D'tor, declared and defined for noexcept.
Definition: zaberCtrl.hpp:78
pcf::IndiProperty m_indiP_temp
Definition: zaberCtrl.hpp:144
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
Definition: zaberCtrl.hpp:204
pcf::IndiProperty m_indiP_stageState
Definition: zaberCtrl.hpp:152
virtual void loadConfig()
Load the stage configuration.
Definition: zaberCtrl.hpp:223
pcf::IndiProperty m_indiP_stageTgtPos
Definition: zaberCtrl.hpp:155
INDI_NEWCALLBACK_DECL(zaberCtrl, m_indiP_pos)
int recordZaber(bool force=false)
Definition: zaberCtrl.hpp:792
double m_countsPerMillimeter
Counts per millimeter calibration of this stage.
Definition: zaberCtrl.hpp:57
double m_tgtPos
Target position in mm.
Definition: zaberCtrl.hpp:69
pcf::IndiProperty m_indiP_pos
Definition: zaberCtrl.hpp:141
INDI_SETCALLBACK_DECL(zaberCtrl, m_indiP_stageTgtPos)
double m_stageTemp
Temperature reported by the stage.
Definition: zaberCtrl.hpp:65
pcf::IndiProperty m_indiP_stageRawPos
Definition: zaberCtrl.hpp:154
double m_rawPos
Current raw position in counts.
Definition: zaberCtrl.hpp:63
INDI_SETCALLBACK_DECL(zaberCtrl, m_indiP_stageState)
INDI_SETCALLBACK_DECL(zaberCtrl, m_indiP_stageRawPos)
int recordTelem(const telem_stage *)
Definition: zaberCtrl.hpp:782
INDI_SETCALLBACK_DECL(zaberCtrl, m_indiP_stageTemp)
INDI_SETCALLBACK_DECL(zaberCtrl, m_indiP_stageMaxRawPos)
#define INDI_NEWCALLBACK(prop)
Get the name of the static callback wrapper for a new property.
Definition: indiMacros.hpp:207
#define REG_INDI_SETPROP(prop, devName, propName)
Register a SET INDI property with the class, using the standard callback name.
Definition: indiMacros.hpp:264
@ OPERATING
The device is operating, other than homing.
Definition: stateCodes.hpp:50
@ POWEROFF
The device power is off.
Definition: stateCodes.hpp:42
@ NODEVICE
No device exists for the application to control.
Definition: stateCodes.hpp:41
@ NOTHOMED
The device has not been homed.
Definition: stateCodes.hpp:48
@ HOMING
The device is homing.
Definition: stateCodes.hpp:49
@ FAILURE
The application has failed, should be used when m_shutdown is set for an error.
Definition: stateCodes.hpp:37
@ ERROR
The application has encountered an error, from which it is recovering (with or without intervention)
Definition: stateCodes.hpp:38
@ READY
The device is ready for operation, but is not operating.
Definition: stateCodes.hpp:51
@ CONNECTED
The application has connected to the device or service.
Definition: stateCodes.hpp:45
@ UNINITIALIZED
The application is unitialized, the default.
Definition: stateCodes.hpp:39
@ INITIALIZED
The application has been initialized, set just before calling appStartup().
Definition: stateCodes.hpp:40
@ NOTCONNECTED
The application is not connected to the device or service.
Definition: stateCodes.hpp:44
@ POWERON
The device power is on.
Definition: stateCodes.hpp:43
#define INDI_IDLE
Definition: indiUtils.hpp:28
#define INDI_BUSY
Definition: indiUtils.hpp:30
std::ostream & cerr()
void updateIfChanged(pcf::IndiProperty &p, const std::string &el, const T &newVal, indiDriverT *indiDriver, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update the value of the INDI element, but only if it has changed.
Definition: indiUtils.hpp:95
int addNumberElement(pcf::IndiProperty &prop, const std::string &name, const T &min, const T &max, const T &step, const std::string &format, const std::string &label="")
Add a standard INDI Number element.
Definition: indiUtils.hpp:63
const pcf::IndiProperty & ipRecv
INDI_VALIDATE_CALLBACK_PROPS(function, ipRecv)
INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_windspeed)(const pcf
Definition: acesxeCtrl.hpp:687
INDI_SETCALLBACK_DEFN(MagAOXApp< _useINDI >, m_indiP_powerChannel)(const pcf
Definition: MagAOXApp.hpp:3195
Definition: dm.hpp:24
constexpr static logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
Definition: logPriority.hpp:37
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
A device which saves telemetry.
Definition: telemeter.hpp:52
int loadConfig(appConfigurator &config)
Load the device section from an application configurator.
Definition: telemeter.hpp:208
int appLogic()
Perform telemeter application logic.
Definition: telemeter.hpp:253
int setupConfig(appConfigurator &config)
Setup an application configurator for the device section.
Definition: telemeter.hpp:195
int checkRecordTimes(const telT &tel, telTs... tels)
Check the time of the last record for each telemetry type and make an entry if needed.
Definition: telemeter.hpp:266
Software ERR log entry.
Log entry recording stdMotionStage status.
Definition: telem_stage.hpp:27
Log entry recording zaber stage specific status.
Definition: telem_zaber.hpp:27
A simple text log, a string-type log.
Definition: text_log.hpp:24