API
 
Loading...
Searching...
No Matches
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
27namespace MagAOX
28{
29namespace 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 */
37class 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
47protected:
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
73public:
74 /// Default c'tor.
75 zaberCtrl();
76
77 /// D'tor, declared and defined for noexcept.
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
138protected:
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
146public:
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
158public:
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
180zaberCtrl::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
204int 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
232 m_indiP_pos["current"].set(0);
233 m_indiP_pos["target"].set(0);
235 {
236 #ifndef ZABERCTRL_TEST_NOLOG
238 #endif
239 return -1;
240 }
241
243 m_indiP_rawPos["current"].set(0);
244 m_indiP_rawPos["target"].set(0);
246 {
247 #ifndef ZABERCTRL_TEST_NOLOG
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
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"));
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 {
301 }
302
303 recordStage();
304
305 //record telem if it's been longer than 10 sec:
307 {
309 }
310
311 return 0;
312 }
313
315 {
316 recordStage();
317 return 0;
318 }
319
321 {
323 }
324
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;
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 {
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);
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;
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);
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
445
446 return 0;
447}
448
450{
451 for( size_t n=1; n < m_presetPositions.size(); ++n)
452 {
454 }
455
456 return 0;
457}
458
459int 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);
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
477
478 return 0;
479}
480
481INDI_NEWCALLBACK_DEFN( zaberCtrl, m_indiP_pos)(const pcf::IndiProperty &ipRecv)
482{
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
523INDI_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
577INDI_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 {
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 {
605 m_moving = -2;
606 }
607 else if(sstr == "NOTCONNECTED")
608 {
610 m_moving = -2;
611 }
612 else if(sstr == "CONNECTED")
613 {
615 m_moving = -2;
616 }
617 else if(sstr == "NOTHOMED")
618 {
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 {
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
669INDI_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
692INDI_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
723INDI_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
759INDI_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
781
786
788{
789 return recordZaber(true);
790}
791
793{
794 static double last_pos = m_pos - 1000;
795 static double last_rawPos = m_rawPos;
796 static double last_temp = m_stageTemp;
797
799 {
801
802 last_pos = m_pos;
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: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.
std::string m_configName
The name of the configuration file (minus .conf).
Definition MagAOXApp.hpp:83
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.
indiDriver< MagAOXApp > * m_indiDriver
The INDI driver wrapper. Constructed and initialized by execute, which starts and stops communication...
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.
int createROIndiNumber(pcf::IndiProperty &prop, const std::string &propName, const std::string &propLabel="", const std::string &propGroup="")
Create a ReadOnly INDI Number property.
int registerIndiPropertyReadOnly(pcf::IndiProperty &prop)
Register an INDI property which is read only.
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)
MagAO-X standard motion stage interface.
int loadConfig(mx::app::appConfigurator &config)
load the configuration system results
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)
float m_preset_target
The target numerical preset position [1.0 is index 0 in the preset name vector].
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.
float m_preset
The current 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.
std::vector< float > m_presetPositions
The positions, in arbitrary units, of each preset. If 0, then the integer position number (starting f...
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
virtual int appLogic()
Implementation of the FSM for zaberCtrl.
virtual int appStartup()
Startup function.
std::string m_lowLevelName
Definition zaberCtrl.hpp:53
virtual void setupConfig()
Setup the configuration of this stage controller.
friend class zaberCtrl_test
Definition zaberCtrl.hpp:41
int moveTo(const double &pos)
Move to a new position in mm.
zaberCtrl()
Default c'tor.
pcf::IndiProperty m_indiP_maxPos
INDI_NEWCALLBACK_DECL(zaberCtrl, m_indiP_rawPos)
pcf::IndiProperty m_indiP_stageTemp
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.
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.
pcf::IndiProperty m_indiP_rawPos
int m_homingState
The homing state, tracks the stages of homing.
Definition zaberCtrl.hpp:71
int startHoming()
Start a high-level homing sequence.
~zaberCtrl() noexcept
D'tor, declared and defined for noexcept.
Definition zaberCtrl.hpp:78
pcf::IndiProperty m_indiP_temp
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
pcf::IndiProperty m_indiP_stageState
virtual void loadConfig()
Load the stage configuration.
pcf::IndiProperty m_indiP_stageTgtPos
INDI_NEWCALLBACK_DECL(zaberCtrl, m_indiP_pos)
int recordZaber(bool force=false)
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
INDI_SETCALLBACK_DECL(zaberCtrl, m_indiP_stageTgtPos)
double m_stageTemp
Temperature reported by the stage.
Definition zaberCtrl.hpp:65
pcf::IndiProperty m_indiP_stageRawPos
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 *)
INDI_SETCALLBACK_DECL(zaberCtrl, m_indiP_stageTemp)
INDI_SETCALLBACK_DECL(zaberCtrl, m_indiP_stageMaxRawPos)
#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.
@ OPERATING
The device is operating, other than homing.
@ POWEROFF
The device power is off.
@ NODEVICE
No device exists for the application to control.
@ NOTHOMED
The device has not been homed.
@ HOMING
The device is homing.
@ FAILURE
The application has failed, should be used when m_shutdown is set for an error.
@ ERROR
The application has encountered an error, from which it is recovering (with or without intervention)
@ READY
The device is ready for operation, but is not operating.
@ CONNECTED
The application has connected to the device or service.
@ UNINITIALIZED
The application is unitialized, the default.
@ INITIALIZED
The application has been initialized, set just before calling appStartup().
@ NOTCONNECTED
The application is not connected to the device or service.
@ POWERON
The device power is on.
#define INDI_VALIDATE_CALLBACK_PROPS(prop1, prop2)
Standard check for matching INDI properties in a callback.
#define INDI_IDLE
Definition indiUtils.hpp:28
#define INDI_BUSY
Definition indiUtils.hpp:30
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
updateIfChanged(m_indiP_angle, "target", m_angle)
Definition dm.hpp:24
static constexpr logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
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.
A device base class which saves telemetry.
Definition telemeter.hpp:69
int loadConfig(appConfigurator &config)
Load the device section from an application configurator.
int setupConfig(appConfigurator &config)
Setup an application configurator for the device section.
Software ERR log entry.
Log entry recording stdMotionStage status.
Log entry recording zaber stage specific status.
A simple text log, a string-type log.
Definition text_log.hpp:24