Line data Source code
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 :
12 : namespace MagAOX
13 : {
14 : namespace app
15 : {
16 : namespace 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 : */
51 : template <class derivedT>
52 : class stdMotionStage
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 :
73 : bool m_fractionalPresets{
74 : true }; ///< Flag to set in constructor determining if fractional presets are allowed. Used for INDI/GUIs.
75 :
76 : bool m_defaultPositions{
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]
86 : int m_presetNameIndex{
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 : */
124 : int appStartup();
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 : */
151 : int onPowerOff();
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 : */
164 : int whilePowerOff();
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 : */
177 : int appShutdown();
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 : */
206 : static int st_newCallBack_stdMotionStage(
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 : */
216 : int newCallBack_m_indiP_preset(
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 : */
224 : int newCallBack_m_indiP_presetName(
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 : */
232 : int newCallBack_m_indiP_home(
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 : */
240 : int newCallBack_m_indiP_stop(
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 : */
250 : int updateINDI();
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.
265 : void clearPresetNameTracking();
266 :
267 : /// Record the active preset-name alias index.
268 : int setPresetNameTracking(
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 1 : derivedT &derived()
284 : {
285 1 : return *static_cast<derivedT *>( this );
286 : }
287 :
288 : const derivedT &derived() const
289 : {
290 : return *static_cast<const derivedT *>( this );
291 : }
292 : };
293 :
294 : template <class derivedT>
295 61 : stdMotionStage<derivedT>::~stdMotionStage() noexcept
296 : {
297 61 : return;
298 61 : }
299 :
300 : template <class derivedT>
301 0 : int stdMotionStage<derivedT>::setupConfig( mx::app::appConfigurator &config )
302 : {
303 : static_cast<void>( config );
304 :
305 0 : 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 0 : 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 0 : config.add( m_presetNotation + "s.names",
326 : "",
327 0 : m_presetNotation + "s.names",
328 : argType::Required,
329 0 : m_presetNotation + "s",
330 : "names",
331 : false,
332 : "vector<string>",
333 0 : "The names of the " + m_presetNotation + "s." );
334 0 : config.add( m_presetNotation + "s.positions",
335 : "",
336 0 : m_presetNotation + "s.positions",
337 : argType::Required,
338 0 : m_presetNotation + "s",
339 : "positions",
340 : false,
341 : "vector<float>",
342 0 : "The positions of the " + m_presetNotation + "s. If omitted or 0 then order is used." );
343 :
344 0 : return 0;
345 : }
346 :
347 : template <class derivedT>
348 0 : int stdMotionStage<derivedT>::loadConfig( mx::app::appConfigurator &config )
349 : {
350 0 : config( m_powerOnHome, "stage.powerOnHome" );
351 0 : config( m_homePreset, "stage.homePreset" );
352 :
353 0 : config( m_presetNames, m_presetNotation + "s.names" );
354 :
355 0 : if( m_defaultPositions )
356 : {
357 0 : m_presetPositions.resize( m_presetNames.size(), 0 );
358 0 : for( size_t n = 0; n < m_presetPositions.size(); ++n )
359 0 : m_presetPositions[n] = n + 1;
360 : }
361 :
362 0 : config( m_presetPositions, m_presetNotation + "s.positions" );
363 :
364 0 : if( m_defaultPositions )
365 : {
366 0 : for( size_t n = 0; n < m_presetPositions.size(); ++n )
367 0 : if( m_presetPositions[n] == 0 )
368 0 : m_presetPositions[n] = n + 1;
369 : }
370 :
371 0 : return 0;
372 : }
373 :
374 : template <class derivedT>
375 0 : int stdMotionStage<derivedT>::appStartup()
376 : {
377 0 : double step = 0.0;
378 0 : std::string format = "%.4f";
379 0 : if( !m_fractionalPresets )
380 : {
381 0 : step = 1.0;
382 0 : format = "%d";
383 : }
384 :
385 0 : derived().createStandardIndiNumber(
386 0 : m_indiP_preset, m_presetNotation, 1.0, (double)m_presetNames.size(), step, format );
387 0 : m_indiP_preset["current"].set( 0 );
388 0 : m_indiP_preset["target"].set( 0 );
389 0 : if( derived().registerIndiPropertyNew( m_indiP_preset, st_newCallBack_stdMotionStage ) < 0 )
390 : {
391 : #ifndef STDFILTERWHEEL_TEST_NOLOG
392 0 : derivedT::template log<software_error>( { __FILE__, __LINE__ } );
393 : #endif
394 0 : return -1;
395 : }
396 :
397 0 : if( derived().createStandardIndiSelectionSw( m_indiP_presetName, m_presetNotation + "Name", m_presetNames ) < 0 )
398 : {
399 0 : derivedT::template log<software_critical>( { __FILE__, __LINE__ } );
400 0 : return -1;
401 : }
402 0 : if( derived().registerIndiPropertyNew( m_indiP_presetName, st_newCallBack_stdMotionStage ) < 0 )
403 : {
404 : #ifndef STDFILTERWHEEL_TEST_NOLOG
405 0 : derivedT::template log<software_error>( { __FILE__, __LINE__ } );
406 : #endif
407 0 : return -1;
408 : }
409 :
410 0 : derived().createStandardIndiRequestSw( m_indiP_home, "home" );
411 0 : if( derived().registerIndiPropertyNew( m_indiP_home, st_newCallBack_stdMotionStage ) < 0 )
412 : {
413 : #ifndef STDFILTERWHEEL_TEST_NOLOG
414 0 : derivedT::template log<software_error>( { __FILE__, __LINE__ } );
415 : #endif
416 0 : return -1;
417 : }
418 :
419 0 : derived().createStandardIndiRequestSw( m_indiP_stop, "stop" );
420 0 : if( derived().registerIndiPropertyNew( m_indiP_stop, st_newCallBack_stdMotionStage ) < 0 )
421 : {
422 : #ifndef STDFILTERWHEEL_TEST_NOLOG
423 0 : derivedT::template log<software_error>( { __FILE__, __LINE__ } );
424 : #endif
425 0 : return -1;
426 : }
427 :
428 0 : return 0;
429 0 : }
430 :
431 : template <class derivedT>
432 0 : int stdMotionStage<derivedT>::appLogic()
433 : {
434 0 : return 0;
435 : }
436 :
437 : template <class derivedT>
438 1 : int stdMotionStage<derivedT>::onPowerOff()
439 : {
440 1 : m_moving = -2;
441 :
442 1 : return 0;
443 : }
444 :
445 : template <class derivedT>
446 0 : int stdMotionStage<derivedT>::whilePowerOff()
447 : {
448 0 : return 0;
449 : }
450 :
451 : template <class derivedT>
452 : int stdMotionStage<derivedT>::appShutdown()
453 : {
454 : return 0;
455 : }
456 :
457 : template <class derivedT>
458 0 : int stdMotionStage<derivedT>::st_newCallBack_stdMotionStage( void *app, const pcf::IndiProperty &ipRecv )
459 : {
460 0 : std::string name = ipRecv.getName();
461 0 : derivedT *_app = static_cast<derivedT *>( app );
462 :
463 0 : if( name == "stop" )
464 0 : return _app->newCallBack_m_indiP_stop( ipRecv ); // Check this first to make sure it
465 0 : if( name == "home" )
466 0 : return _app->newCallBack_m_indiP_home( ipRecv );
467 0 : if( name == _app->m_presetNotation )
468 0 : return _app->newCallBack_m_indiP_preset( ipRecv );
469 0 : if( name == _app->m_presetNotation + "Name" )
470 0 : return _app->newCallBack_m_indiP_presetName( ipRecv );
471 :
472 0 : return -1;
473 0 : }
474 :
475 : template <class derivedT>
476 6 : int stdMotionStage<derivedT>::newCallBack_m_indiP_preset( const pcf::IndiProperty &ipRecv )
477 : {
478 6 : INDI_VALIDATE_CALLBACK_PROPS_DERIVED( m_indiP_preset, ipRecv );
479 :
480 : float target;
481 :
482 0 : if( derived().indiTargetUpdate( m_indiP_preset, target, ipRecv, true ) < 0 )
483 : {
484 0 : derivedT::template log<software_error>( { __FILE__, __LINE__ } );
485 0 : return -1;
486 : }
487 :
488 0 : m_preset_target = target;
489 :
490 0 : std::lock_guard<std::mutex> guard( derived().m_indiMutex );
491 0 : clearPresetNameTracking();
492 0 : m_movingState = 0; // this is not a preset move
493 0 : return derived().moveTo( target );
494 0 : }
495 :
496 : template <class derivedT>
497 6 : int stdMotionStage<derivedT>::newCallBack_m_indiP_presetName( const pcf::IndiProperty &ipRecv )
498 : {
499 6 : INDI_VALIDATE_CALLBACK_PROPS_DERIVED( m_indiP_presetName, ipRecv );
500 :
501 0 : std::string newName = "";
502 0 : int newn = -1;
503 :
504 : size_t i;
505 0 : for( i = 0; i < m_presetNames.size(); ++i )
506 : {
507 0 : if( !ipRecv.find( m_presetNames[i] ) )
508 0 : continue;
509 :
510 0 : if( ipRecv[m_presetNames[i]].getSwitchState() == pcf::IndiElement::On )
511 : {
512 0 : if( newName != "" )
513 : {
514 0 : derivedT::template log<text_log>( "More than one " + m_presetNotation + " selected",
515 : logPrio::LOG_ERROR );
516 0 : return -1;
517 : }
518 :
519 0 : newName = m_presetNames[i];
520 0 : newn = i;
521 : }
522 : }
523 :
524 0 : if( newName == "" || newn < 0 )
525 : {
526 0 : return 0; // This is just an reset of current probably
527 : }
528 :
529 0 : std::lock_guard<std::mutex> guard( derived().m_indiMutex );
530 :
531 0 : setPresetNameTracking( newn );
532 0 : m_preset_target = m_presetPositions[newn];
533 0 : derived().updateIfChanged( m_indiP_preset, "target", m_preset_target, INDI_BUSY );
534 :
535 0 : m_movingState = 1; // This is a preset move
536 0 : return derived().moveTo( m_preset_target );
537 0 : }
538 :
539 : template <class derivedT>
540 6 : int stdMotionStage<derivedT>::newCallBack_m_indiP_home( const pcf::IndiProperty &ipRecv )
541 : {
542 6 : INDI_VALIDATE_CALLBACK_PROPS_DERIVED( m_indiP_home, ipRecv );
543 :
544 0 : if( !ipRecv.find( "request" ) )
545 0 : return 0;
546 :
547 0 : if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
548 : {
549 0 : indi::updateSwitchIfChanged( m_indiP_home, "request", pcf::IndiElement::On, derived().m_indiDriver, INDI_BUSY );
550 :
551 0 : std::lock_guard<std::mutex> guard( derived().m_indiMutex );
552 0 : m_movingState = 0;
553 0 : return derived().startHoming();
554 0 : }
555 0 : return 0;
556 : }
557 :
558 : template <class derivedT>
559 6 : int stdMotionStage<derivedT>::newCallBack_m_indiP_stop( const pcf::IndiProperty &ipRecv )
560 : {
561 6 : INDI_VALIDATE_CALLBACK_PROPS_DERIVED( m_indiP_stop, ipRecv );
562 :
563 0 : if( ipRecv.getName() != m_indiP_stop.getName() )
564 : {
565 0 : derivedT::template log<software_error>( { __FILE__, __LINE__, "wrong INDI property received." } );
566 0 : return -1;
567 : }
568 :
569 0 : if( !ipRecv.find( "request" ) )
570 0 : return 0;
571 :
572 0 : if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
573 : {
574 0 : indi::updateSwitchIfChanged( m_indiP_stop, "request", pcf::IndiElement::On, derived().m_indiDriver, INDI_BUSY );
575 :
576 : //-->do not lock mutex!
577 0 : m_movingState = 0;
578 0 : return derived().stop();
579 : }
580 0 : return 0;
581 : }
582 :
583 : template <class derivedT>
584 0 : int stdMotionStage<derivedT>::updateINDI()
585 : {
586 0 : if( !derived().m_indiDriver )
587 0 : return 0;
588 :
589 0 : int n = derived().presetNumber();
590 :
591 : // Check for changes and update the filterNames
592 0 : bool changed = false;
593 :
594 : static int8_t last_moving = -1; // Initialize so we always update first time through.
595 0 : int activePresetIndex = activePresetNameIndex( n );
596 :
597 0 : if( last_moving != m_moving )
598 : {
599 0 : changed = true;
600 0 : last_moving = m_moving;
601 : }
602 :
603 0 : for( size_t i = 0; i < m_presetNames.size(); ++i )
604 : {
605 0 : if( static_cast<int>( i ) == activePresetIndex )
606 : {
607 0 : if( m_indiP_presetName[m_presetNames[i]] != pcf::IndiElement::On )
608 : {
609 0 : changed = true;
610 0 : m_indiP_presetName[m_presetNames[i]] = pcf::IndiElement::On;
611 : }
612 : }
613 : else
614 : {
615 0 : if( m_indiP_presetName[m_presetNames[i]] != pcf::IndiElement::Off )
616 : {
617 0 : changed = true;
618 0 : m_indiP_presetName[m_presetNames[i]] = pcf::IndiElement::Off;
619 : }
620 : }
621 : }
622 0 : if( changed )
623 : {
624 0 : if( m_moving > 0 )
625 : {
626 0 : m_indiP_presetName.setState( INDI_BUSY );
627 : }
628 : else
629 : {
630 0 : m_indiP_presetName.setState( INDI_IDLE );
631 : }
632 :
633 0 : m_indiP_presetName.setTimeStamp( pcf::TimeStamp() );
634 0 : derived().m_indiDriver->sendSetProperty( m_indiP_presetName );
635 : }
636 :
637 0 : if( m_moving && m_movingState < 1 )
638 : {
639 0 : indi::updateIfChanged( m_indiP_preset, "current", m_preset, derived().m_indiDriver, INDI_BUSY );
640 0 : indi::updateIfChanged( m_indiP_preset, "target", m_preset_target, derived().m_indiDriver, INDI_BUSY );
641 : }
642 : else
643 : {
644 0 : indi::updateIfChanged( m_indiP_preset, "current", m_preset, derived().m_indiDriver, INDI_IDLE );
645 0 : indi::updateIfChanged( m_indiP_preset, "target", m_preset_target, derived().m_indiDriver, INDI_IDLE );
646 : }
647 :
648 0 : return recordStage();
649 : }
650 :
651 : template <class derivedT>
652 0 : int stdMotionStage<derivedT>::recordStage( bool force )
653 : {
654 0 : static int8_t last_moving = m_moving + 100; // guarantee first run
655 : static float last_preset;
656 0 : static std::string last_presetName;
657 :
658 0 : std::string presetName = telemetryPresetName();
659 :
660 0 : if( m_moving != last_moving || m_preset != last_preset || presetName != last_presetName || force )
661 : {
662 0 : derived().template telem<telem_stage>( { m_moving, m_preset, presetName } );
663 0 : last_moving = m_moving;
664 0 : last_preset = m_preset;
665 0 : last_presetName = presetName;
666 : }
667 :
668 0 : return 0;
669 0 : }
670 :
671 : template <class derivedT>
672 1 : void stdMotionStage<derivedT>::clearPresetNameTracking()
673 : {
674 1 : m_presetNameIndex = -1;
675 1 : }
676 :
677 : template <class derivedT>
678 3 : int stdMotionStage<derivedT>::setPresetNameTracking( int presetNameIndex )
679 : {
680 3 : if( presetNameIndex < 0 || presetNameIndex >= static_cast<int>( m_presetNames.size() ) )
681 : {
682 0 : clearPresetNameTracking();
683 0 : return -1;
684 : }
685 :
686 3 : m_presetNameIndex = presetNameIndex;
687 3 : return 0;
688 : }
689 :
690 : template <class derivedT>
691 9 : int stdMotionStage<derivedT>::activePresetNameIndex( int presetIndex ) const
692 : {
693 9 : if( m_presetNameIndex >= 0 && m_presetNameIndex < static_cast<int>( m_presetPositions.size() ) )
694 : {
695 7 : if( m_moving != 0 && m_movingState == 1 )
696 : {
697 2 : return m_presetNameIndex;
698 : }
699 :
700 10 : if( presetIndex >= 0 && presetIndex < static_cast<int>( m_presetPositions.size() ) &&
701 5 : m_presetPositions[presetIndex] == m_presetPositions[m_presetNameIndex] )
702 : {
703 5 : return m_presetNameIndex;
704 : }
705 : }
706 :
707 2 : if( presetIndex >= 0 && presetIndex < static_cast<int>( m_presetNames.size() ) )
708 : {
709 2 : return presetIndex;
710 : }
711 :
712 0 : return -1;
713 : }
714 :
715 : template <class derivedT>
716 5 : std::string stdMotionStage<derivedT>::activePresetName( int presetIndex ) const
717 : {
718 5 : int presetNameIndex = activePresetNameIndex( presetIndex );
719 :
720 5 : if( presetNameIndex >= 0 && presetNameIndex < static_cast<int>( m_presetNames.size() ) )
721 : {
722 5 : return m_presetNames[presetNameIndex];
723 : }
724 :
725 0 : return "";
726 : }
727 :
728 : template <class derivedT>
729 1 : std::string stdMotionStage<derivedT>::telemetryPresetName()
730 : {
731 1 : if( m_preset <= 0 )
732 : {
733 0 : return "";
734 : }
735 :
736 1 : return activePresetName( derived().presetNumber() );
737 : }
738 :
739 : } // namespace dev
740 : } // namespace app
741 : } // namespace MagAOX
742 :
743 : #endif // stdMotionStage_hpp
|