API
 
Loading...
Searching...
No Matches
stdMotionStage.hpp
Go to the documentation of this file.
1/** \file stdMotionStage.hpp
2 * \brief Standard motion stage interface
3 *
4 * \author Jared R. Males (jaredmales@gmail.com)
5 *
6 * \ingroup app_files
7 */
8
9#ifndef stdMotionStage_hpp
10#define stdMotionStage_hpp
11
12namespace MagAOX
13{
14namespace app
15{
16namespace dev
17{
18
19/// MagAO-X standard motion stage interface
20/** Implements the standard interface to a MagAO-X motion stage.
21 * This includes the mcbl filter wheels, the zaber stages.
22 *
23 * The required interface to be implemented in derivedT is
24 * \code
25
26 int stop(); //Note that the INDI mutex will not be locked on this call
27
28 int startHoming(); //INDI mutex will be locked on this call.
29
30 float presetNumber();
31
32 int moveTo(float); //INDI mutex will be locked on this call.
33 \endcode
34 *
35 * In addition the derived class is responsible for setting m_moving and m_preset. m_preset_target should also be set
36 if the wheel
37 * is moved via a low-level position command.
38 *
39 * The derived class `derivedT` must be a MagAOXApp<true>, and should declare this class a friend like so:
40 \code
41 friend class dev::stdMotionStage<derivedT>;
42 \endcode
43 *
44 *
45 *
46 * Calls to this class's `setupConfig`, `loadConfig`, `appStartup`, `appLogic`, `appShutdown`
47 * `onPowerOff`, and `whilePowerOff`, must be placed in the derived class's functions of the same name.
48 *
49 * \ingroup appdev
50 */
51template <class derivedT>
53{
54 protected:
55 /** \name Configurable Parameters
56 * @{
57 */
58
59 bool m_powerOnHome{ false }; ///< If true, then the motor is homed at startup (by this software or actual power on)
60
61 int m_homePreset{ -1 }; ///< If >=0, this preset position is moved to after homing
62
63 std::vector<std::string> m_presetNames; ///< The names of each position on the stage.
64
65 std::vector<float> m_presetPositions; ///< The positions, in arbitrary units, of each preset. If 0, then the
66 ///< integer position number (starting from 1) is used to calculate.
67
68 ///@}
69
70 std::string m_presetNotation{
71 "preset" }; ///< Notation used to refer to a preset, should be singular, as in "preset" or "filter".
72
74 true }; ///< Flag to set in constructor determining if fractional presets are allowed. Used for INDI/GUIs.
75
77 true }; ///< Flag controlling whether the default preset positions (the vector index) are set in loadConfig.
78
79 int8_t m_moving{ 0 }; ///< Whether or not the stage is moving. -2 means powered off, -1 means not homed, 0 means
80 ///< not moving, 1 means moving, 2 means homing.
81 int8_t m_movingState{ 0 }; ///< Used to track the type of command. If 1 this is a command to move to a named
82 ///< preset. If 0 then it is a move to an arbitrary position.
83
84 float m_preset{ 0 }; ///< The current numerical preset position [1.0 is index 0 in the preset name vector]
85 float m_preset_target{ 0 }; ///< The target numerical preset position [1.0 is index 0 in the preset name vector]
87 -1 }; ///< The selected preset-name alias index when the active command identifies a specific preset name.
88
89 public:
90 /// Destructor
91 ~stdMotionStage() noexcept;
92
93 /// Setup the configuration system
94 /**
95 * This should be called in `derivedT::setupConfig` as
96 * \code
97 stdMotionStage<derivedT>::setupConfig(config);
98 \endcode
99 * with appropriate error checking.
100 */
101 int setupConfig( mx::app::appConfigurator &config /**< [out] the derived classes configurator*/ );
102
103 /// load the configuration system results
104 /**
105 * This should be called in `derivedT::loadConfig` as
106 * \code
107 stdMotionStage<derivedT>::loadConfig(config);
108 \endcode
109 * with appropriate error checking.
110 */
111 int loadConfig( mx::app::appConfigurator &config /**< [in] the derived classes configurator*/ );
112
113 /// Startup function
114 /**
115 * This should be called in `derivedT::appStartup` as
116 * \code
117 stdMotionStage<derivedT>::appStartup();
118 \endcode
119 * with appropriate error checking.
120 *
121 * \returns 0 on success
122 * \returns -1 on error, which is logged.
123 */
125
126 /// Application logic
127 /** Checks the stdMotionStage thread
128 *
129 * This should be called from the derived's appLogic() as in
130 * \code
131 stdMotionStage<derivedT>::appLogic();
132 \endcode
133 * with appropriate error checking.
134 *
135 * \returns 0 on success
136 * \returns -1 on error, which is logged.
137 */
138 int appLogic();
139
140 /// Actions on power off
141 /**
142 * This should be called from the derived's onPowerOff() as in
143 * \code
144 stdMotionStage<derivedT>::onPowerOff();
145 \endcode
146 * with appropriate error checking.
147 *
148 * \returns 0 on success
149 * \returns -1 on error, which is logged.
150 */
152
153 /// Actions while powered off
154 /**
155 * This should be called from the derived's whilePowerOff() as in
156 * \code
157 stdMotionStage<derivedT>::whilePowerOff();
158 \endcode
159 * with appropriate error checking.
160 *
161 * \returns 0 on success
162 * \returns -1 on error, which is logged.
163 */
165
166 /// Application the shutdown
167 /** Shuts down the stdMotionStage thread
168 *
169 * \code
170 stdMotionStage<derivedT>::appShutdown();
171 \endcode
172 * with appropriate error checking.
173 *
174 * \returns 0 on success
175 * \returns -1 on error, which is logged.
176 */
178
179 protected:
180 /** \name INDI
181 *
182 *@{
183 */
184 protected:
185 // declare our properties
186
187 /// The position of the stage in presets
188 pcf::IndiProperty m_indiP_preset;
189
190 /// The name of the active preset selection
191 pcf::IndiProperty m_indiP_presetName;
192
193 /// Command the stage to home. .
194 pcf::IndiProperty m_indiP_home;
195
196 /// Command the stage to halt.
197 pcf::IndiProperty m_indiP_stop;
198
199 public:
200 /// The static callback function to be registered for stdMotionStage properties
201 /** Dispatches to the relevant handler
202 *
203 * \returns 0 on success.
204 * \returns -1 on error.
205 */
207 void *app, ///< [in] a pointer to this, will be static_cast-ed to derivedT.
208 const pcf::IndiProperty &ipRecv ///< [in] the INDI property sent with the the new property request.
209 );
210
211 /// Callback to process a NEW preset position request
212 /**
213 * \returns 0 on success.
214 * \returns -1 on error.
215 */
217 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
218
219 /// Callback to process a NEW preset name request
220 /**
221 * \returns 0 on success.
222 * \returns -1 on error.
223 */
225 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
226
227 /// Callback to process a NEW home request switch toggle
228 /**
229 * \returns 0 on success.
230 * \returns -1 on error.
231 */
233 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
234
235 /// Callback to process a NEW stop request switch toggle
236 /**
237 * \returns 0 on success.
238 * \returns -1 on error.
239 */
241 const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/ );
242
243 /// Update the INDI properties for this device controller
244 /** You should call this once per main loop.
245 * It is not called automatically.
246 *
247 * \returns 0 on success.
248 * \returns -1 on error.
249 */
251
252 ///@}
253
254 /** \name Telemeter Interface
255 * @{
256 */
257
258 /// Record the stage telemetry state.
259 int recordStage( bool force /**< [in] force telemetry recording even when no stage state changed */ = false );
260
261 ///@}
262
263 protected:
264 /// Clear any tracked preset-name alias selection.
266
267 /// Record the active preset-name alias index.
269 int presetNameIndex /**< [in] the preset-name index to associate with the current command */ );
270
271 /// Resolve the preset-name alias index that should be reported.
272 int
273 activePresetNameIndex( int presetIndex /**< [in] the current preset index reported by the derived stage */ ) const;
274
275 /// Resolve the preset name that should be reported.
276 std::string
277 activePresetName( int presetIndex /**< [in] the current preset index reported by the derived stage */ ) const;
278
279 /// Resolve the preset name that should be recorded in telemetry.
280 std::string telemetryPresetName();
281
282 private:
283 derivedT &derived()
284 {
285 return *static_cast<derivedT *>( this );
286 }
287
288 const derivedT &derived() const
289 {
290 return *static_cast<const derivedT *>( this );
291 }
292};
293
294template <class derivedT>
296{
297 return;
298}
299
300template <class derivedT>
301int stdMotionStage<derivedT>::setupConfig( mx::app::appConfigurator &config )
302{
303 static_cast<void>( config );
304
305 config.add( "stage.powerOnHome",
306 "",
307 "stage.powerOnHome",
308 argType::Required,
309 "stage",
310 "powerOnHome",
311 false,
312 "bool",
313 "If true, home at startup/power-on. Default=false." );
314
315 config.add( "stage.homePreset",
316 "",
317 "stage.homePreset",
318 argType::Required,
319 "stage",
320 "homePreset",
321 false,
322 "int",
323 "If >=0, this preset number is moved to after homing." );
324
325 config.add( m_presetNotation + "s.names",
326 "",
327 m_presetNotation + "s.names",
328 argType::Required,
329 m_presetNotation + "s",
330 "names",
331 false,
332 "vector<string>",
333 "The names of the " + m_presetNotation + "s." );
334 config.add( m_presetNotation + "s.positions",
335 "",
336 m_presetNotation + "s.positions",
337 argType::Required,
338 m_presetNotation + "s",
339 "positions",
340 false,
341 "vector<float>",
342 "The positions of the " + m_presetNotation + "s. If omitted or 0 then order is used." );
343
344 return 0;
345}
346
347template <class derivedT>
348int stdMotionStage<derivedT>::loadConfig( mx::app::appConfigurator &config )
349{
350 config( m_powerOnHome, "stage.powerOnHome" );
351 config( m_homePreset, "stage.homePreset" );
352
353 config( m_presetNames, m_presetNotation + "s.names" );
354
355 if( m_defaultPositions )
356 {
357 m_presetPositions.resize( m_presetNames.size(), 0 );
358 for( size_t n = 0; n < m_presetPositions.size(); ++n )
359 m_presetPositions[n] = n + 1;
360 }
361
362 config( m_presetPositions, m_presetNotation + "s.positions" );
363
364 if( m_defaultPositions )
365 {
366 for( size_t n = 0; n < m_presetPositions.size(); ++n )
367 if( m_presetPositions[n] == 0 )
368 m_presetPositions[n] = n + 1;
369 }
370
371 return 0;
372}
373
374template <class derivedT>
376{
377 double step = 0.0;
378 std::string format = "%.4f";
379 if( !m_fractionalPresets )
380 {
381 step = 1.0;
382 format = "%d";
383 }
384
385 derived().createStandardIndiNumber(
386 m_indiP_preset, m_presetNotation, 1.0, (double)m_presetNames.size(), step, format );
387 m_indiP_preset["current"].set( 0 );
388 m_indiP_preset["target"].set( 0 );
389 if( derived().registerIndiPropertyNew( m_indiP_preset, st_newCallBack_stdMotionStage ) < 0 )
390 {
391#ifndef STDFILTERWHEEL_TEST_NOLOG
392 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
393#endif
394 return -1;
395 }
396
397 if( derived().createStandardIndiSelectionSw( m_indiP_presetName, m_presetNotation + "Name", m_presetNames ) < 0 )
398 {
399 derivedT::template log<software_critical>( { __FILE__, __LINE__ } );
400 return -1;
401 }
402 if( derived().registerIndiPropertyNew( m_indiP_presetName, st_newCallBack_stdMotionStage ) < 0 )
403 {
404#ifndef STDFILTERWHEEL_TEST_NOLOG
405 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
406#endif
407 return -1;
408 }
409
410 derived().createStandardIndiRequestSw( m_indiP_home, "home" );
411 if( derived().registerIndiPropertyNew( m_indiP_home, st_newCallBack_stdMotionStage ) < 0 )
412 {
413#ifndef STDFILTERWHEEL_TEST_NOLOG
414 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
415#endif
416 return -1;
417 }
418
419 derived().createStandardIndiRequestSw( m_indiP_stop, "stop" );
420 if( derived().registerIndiPropertyNew( m_indiP_stop, st_newCallBack_stdMotionStage ) < 0 )
421 {
422#ifndef STDFILTERWHEEL_TEST_NOLOG
423 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
424#endif
425 return -1;
426 }
427
428 return 0;
429}
430
431template <class derivedT>
433{
434 return 0;
435}
436
437template <class derivedT>
439{
440 m_moving = -2;
441
442 return 0;
443}
444
445template <class derivedT>
447{
448 return 0;
449}
450
451template <class derivedT>
453{
454 return 0;
455}
456
457template <class derivedT>
458int stdMotionStage<derivedT>::st_newCallBack_stdMotionStage( void *app, const pcf::IndiProperty &ipRecv )
459{
460 std::string name = ipRecv.getName();
461 derivedT *_app = static_cast<derivedT *>( app );
462
463 if( name == "stop" )
464 return _app->newCallBack_m_indiP_stop( ipRecv ); // Check this first to make sure it
465 if( name == "home" )
466 return _app->newCallBack_m_indiP_home( ipRecv );
467 if( name == _app->m_presetNotation )
468 return _app->newCallBack_m_indiP_preset( ipRecv );
469 if( name == _app->m_presetNotation + "Name" )
470 return _app->newCallBack_m_indiP_presetName( ipRecv );
471
472 return -1;
473}
474
475template <class derivedT>
477{
479
480 float target;
481
482 if( derived().indiTargetUpdate( m_indiP_preset, target, ipRecv, true ) < 0 )
483 {
484 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
485 return -1;
486 }
487
488 m_preset_target = target;
489
490 std::lock_guard<std::mutex> guard( derived().m_indiMutex );
491 clearPresetNameTracking();
492 m_movingState = 0; // this is not a preset move
493 return derived().moveTo( target );
494}
495
496template <class derivedT>
498{
499 INDI_VALIDATE_CALLBACK_PROPS_DERIVED( m_indiP_presetName, ipRecv );
500
501 static size_t s_presetNameCallbackSerial = 0;
502
503 std::vector<std::string> invalidSelections;
504 std::string onSelections;
505 for( auto &&el : ipRecv.getElements() )
506 {
507 if( el.second.getSwitchState() != pcf::IndiElement::On )
508 {
509 continue;
510 }
511
512 if( !onSelections.empty() )
513 {
514 onSelections += ", ";
515 }
516
517 onSelections += el.first;
518
519 bool knownPreset = false;
520 for( size_t i = 0; i < m_presetNames.size(); ++i )
521 {
522 if( el.first == m_presetNames[i] )
523 {
524 knownPreset = true;
525 break;
526 }
527 }
528
529 if( !knownPreset )
530 {
531 invalidSelections.push_back( el.first );
532 }
533 }
534
535 if( invalidSelections.size() > 0 )
536 {
537 std::string invalidNames;
538 for( size_t n = 0; n < invalidSelections.size(); ++n )
539 {
540 if( n > 0 )
541 {
542 invalidNames += ", ";
543 }
544
545 invalidNames += invalidSelections[n];
546 }
547
548 derivedT::template log<text_log>( "Unknown " + m_presetNotation + "Name selected: " + invalidNames,
549 logPrio::LOG_ERROR );
550 return -1;
551 }
552
553 std::string newName = "";
554 int newn = -1;
555
556 size_t i;
557 for( i = 0; i < m_presetNames.size(); ++i )
558 {
559 if( !ipRecv.find( m_presetNames[i] ) )
560 continue;
561
562 if( ipRecv[m_presetNames[i]].getSwitchState() == pcf::IndiElement::On )
563 {
564 if( newName != "" )
565 {
566 derivedT::template log<text_log>( "More than one " + m_presetNotation + " selected",
567 logPrio::LOG_ERROR );
568 return -1;
569 }
570
571 newName = m_presetNames[i];
572 newn = i;
573 }
574 }
575
576 if( newName == "" || newn < 0 )
577 {
578 return 0; // This is just an reset of current probably
579 }
580
581 std::lock_guard<std::mutex> guard( derived().m_indiMutex );
582
583 setPresetNameTracking( newn );
584 m_preset_target = m_presetPositions[newn];
585 derived().updateIfChanged( m_indiP_preset, "target", m_preset_target, INDI_BUSY );
586
587 ++s_presetNameCallbackSerial;
588 derivedT::template log<text_log>(
589 "stdMotionStage accepted " + m_presetNotation + "Name[" + std::to_string( s_presetNameCallbackSerial ) +
590 "] device=" + ipRecv.getDevice() + " property=" + ipRecv.getName() + " selection=" + newName + " on={" +
591 onSelections + "} target=" + std::to_string( m_preset_target ),
592 logPrio::LOG_NOTICE );
593
594 m_movingState = 1; // This is a preset move
595 return derived().moveTo( m_preset_target );
596}
597
598template <class derivedT>
600{
602
603 if( !ipRecv.find( "request" ) )
604 return 0;
605
606 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
607 {
608 indi::updateSwitchIfChanged( m_indiP_home, "request", pcf::IndiElement::On, derived().m_indiDriver, INDI_BUSY );
609
610 std::lock_guard<std::mutex> guard( derived().m_indiMutex );
611 m_movingState = 0;
612 return derived().startHoming();
613 }
614 return 0;
615}
616
617template <class derivedT>
619{
621
622 if( ipRecv.getName() != m_indiP_stop.getName() )
623 {
624 derivedT::template log<software_error>( { __FILE__, __LINE__, "wrong INDI property received." } );
625 return -1;
626 }
627
628 if( !ipRecv.find( "request" ) )
629 return 0;
630
631 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
632 {
633 indi::updateSwitchIfChanged( m_indiP_stop, "request", pcf::IndiElement::On, derived().m_indiDriver, INDI_BUSY );
634
635 //-->do not lock mutex!
636 m_movingState = 0;
637 return derived().stop();
638 }
639 return 0;
640}
641
642template <class derivedT>
644{
645 if( !derived().m_indiDriver )
646 return 0;
647
648 int n = derived().presetNumber();
649
650 // Check for changes and update the filterNames
651 bool changed = false;
652
653 static int8_t last_moving = -1; // Initialize so we always update first time through.
654 int activePresetIndex = activePresetNameIndex( n );
655
656 if( last_moving != m_moving )
657 {
658 changed = true;
659 last_moving = m_moving;
660 }
661
662 for( size_t i = 0; i < m_presetNames.size(); ++i )
663 {
664 if( static_cast<int>( i ) == activePresetIndex )
665 {
666 if( m_indiP_presetName[m_presetNames[i]] != pcf::IndiElement::On )
667 {
668 changed = true;
669 m_indiP_presetName[m_presetNames[i]] = pcf::IndiElement::On;
670 }
671 }
672 else
673 {
674 if( m_indiP_presetName[m_presetNames[i]] != pcf::IndiElement::Off )
675 {
676 changed = true;
677 m_indiP_presetName[m_presetNames[i]] = pcf::IndiElement::Off;
678 }
679 }
680 }
681 if( changed )
682 {
683 if( m_moving > 0 )
684 {
685 m_indiP_presetName.setState( INDI_BUSY );
686 }
687 else
688 {
689 m_indiP_presetName.setState( INDI_IDLE );
690 }
691
692 m_indiP_presetName.setTimeStamp( pcf::TimeStamp() );
693 derived().m_indiDriver->sendSetProperty( m_indiP_presetName );
694 }
695
696 if( m_moving && m_movingState < 1 )
697 {
698 indi::updateIfChanged( m_indiP_preset, "current", m_preset, derived().m_indiDriver, INDI_BUSY );
699 indi::updateIfChanged( m_indiP_preset, "target", m_preset_target, derived().m_indiDriver, INDI_BUSY );
700 }
701 else
702 {
703 indi::updateIfChanged( m_indiP_preset, "current", m_preset, derived().m_indiDriver, INDI_IDLE );
704 indi::updateIfChanged( m_indiP_preset, "target", m_preset_target, derived().m_indiDriver, INDI_IDLE );
705 }
706
707 return recordStage();
708}
709
710template <class derivedT>
712{
713 static int8_t last_moving = m_moving + 100; // guarantee first run
714 static float last_preset;
715 static std::string last_presetName;
716
717 std::string presetName = telemetryPresetName();
718
719 if( m_moving != last_moving || m_preset != last_preset || presetName != last_presetName || force )
720 {
721 derived().template telem<telem_stage>( { m_moving, m_preset, presetName } );
722 last_moving = m_moving;
723 last_preset = m_preset;
724 last_presetName = presetName;
725 }
726
727 return 0;
728}
729
730template <class derivedT>
732{
733 m_presetNameIndex = -1;
734}
735
736template <class derivedT>
738{
739 if( presetNameIndex < 0 || presetNameIndex >= static_cast<int>( m_presetNames.size() ) )
740 {
741 clearPresetNameTracking();
742 return -1;
743 }
744
745 m_presetNameIndex = presetNameIndex;
746 return 0;
747}
748
749template <class derivedT>
751{
752 if( m_presetNameIndex >= 0 && m_presetNameIndex < static_cast<int>( m_presetPositions.size() ) )
753 {
754 if( m_moving != 0 && m_movingState == 1 )
755 {
756 return m_presetNameIndex;
757 }
758
759 if( presetIndex >= 0 && presetIndex < static_cast<int>( m_presetPositions.size() ) &&
760 m_presetPositions[presetIndex] == m_presetPositions[m_presetNameIndex] )
761 {
762 return m_presetNameIndex;
763 }
764 }
765
766 if( presetIndex >= 0 && presetIndex < static_cast<int>( m_presetNames.size() ) )
767 {
768 return presetIndex;
769 }
770
771 return -1;
772}
773
774template <class derivedT>
775std::string stdMotionStage<derivedT>::activePresetName( int presetIndex ) const
776{
777 int presetNameIndex = activePresetNameIndex( presetIndex );
778
779 if( presetNameIndex >= 0 && presetNameIndex < static_cast<int>( m_presetNames.size() ) )
780 {
781 return m_presetNames[presetNameIndex];
782 }
783
784 return "";
785}
786
787template <class derivedT>
789{
790 if( m_preset <= 0 )
791 {
792 return "";
793 }
794
795 return activePresetName( derived().presetNumber() );
796}
797
798} // namespace dev
799} // namespace app
800} // namespace MagAOX
801
802#endif // stdMotionStage_hpp
MagAO-X standard motion stage interface.
int loadConfig(mx::app::appConfigurator &config)
load the configuration system results
std::string telemetryPresetName()
Resolve the preset name that should be recorded in telemetry.
int onPowerOff()
Actions on power off.
void clearPresetNameTracking()
Clear any tracked preset-name alias selection.
int setPresetNameTracking(int presetNameIndex)
Record the active preset-name alias index.
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)
std::string m_presetNotation
Notation used to refer to a preset, should be singular, as in "preset" or "filter".
int activePresetNameIndex(int presetIndex) const
Resolve the preset-name alias index that should be reported.
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. .
int newCallBack_m_indiP_stop(const pcf::IndiProperty &ipRecv)
Callback to process a NEW stop request switch toggle.
bool m_defaultPositions
Flag controlling whether the default preset positions (the vector index) are set in loadConfig.
int newCallBack_m_indiP_home(const pcf::IndiProperty &ipRecv)
Callback to process a NEW home request switch toggle.
int updateINDI()
Update the INDI properties for this device controller.
int setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
const derivedT & derived() const
pcf::IndiProperty m_indiP_presetName
The name of the active preset selection.
int whilePowerOff()
Actions while powered off.
std::string activePresetName(int presetIndex) const
Resolve the preset name that should be reported.
~stdMotionStage() noexcept
Destructor.
int newCallBack_m_indiP_presetName(const pcf::IndiProperty &ipRecv)
Callback to process a NEW preset name request.
int m_homePreset
If >=0, this preset position is moved to after homing.
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].
static int st_newCallBack_stdMotionStage(void *app, const pcf::IndiProperty &ipRecv)
The static callback function to be registered for stdMotionStage properties.
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
int recordStage(bool force=false)
Record the stage telemetry state.
int appLogic()
Application logic.
int appShutdown()
Application the shutdown.
int newCallBack_m_indiP_preset(const pcf::IndiProperty &ipRecv)
Callback to process a NEW preset position request.
int m_presetNameIndex
The selected preset-name alias index when the active command identifies a specific preset name.
#define protected
#define INDI_VALIDATE_CALLBACK_PROPS_DERIVED(prop1, prop2)
Standard check for matching INDI properties in a callback in a CRTP base class.
#define INDI_IDLE
Definition indiUtils.hpp:27
#define INDI_BUSY
Definition indiUtils.hpp:29
#define private
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:92
void updateSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, const pcf::IndiElement::SwitchStateType &newVal, indiDriverT *indiDriver, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update the value of the INDI element, but only if it has changed.
const pcf::IndiProperty & ipRecv
Definition dm.hpp:19