9 #ifndef stdMotionStage_hpp
10 #define stdMotionStage_hpp
52 template<
class derivedT>
205 const pcf::IndiProperty &
ipRecv
258 return *
static_cast<derivedT *
>(
this);
262 template<
class derivedT>
270 template<
class derivedT>
273 static_cast<void>(config);
275 config.add(
"stage.powerOnHome",
"",
"stage.powerOnHome", argType::Required,
"stage",
"powerOnHome",
false,
"bool",
"If true, home at startup/power-on. Default=false.");
277 config.add(
"stage.homePreset",
"",
"stage.homePreset", argType::Required,
"stage",
"homePreset",
false,
"int",
"If >=0, this preset number is moved to after homing.");
279 config.add(m_presetNotation +
"s.names",
"", m_presetNotation +
"s.names", argType::Required, m_presetNotation+
"s",
"names",
false,
"vector<string>",
"The names of the " + m_presetNotation+
"s.");
280 config.add(m_presetNotation +
"s.positions",
"", m_presetNotation +
"s.positions", argType::Required, m_presetNotation+
"s",
"positions",
false,
"vector<float>",
"The positions of the " + m_presetNotation +
"s. If omitted or 0 then order is used.");
285 template<
class derivedT>
288 config(m_powerOnHome,
"stage.powerOnHome");
289 config(m_homePreset,
"stage.homePreset");
291 config(m_presetNames, m_presetNotation +
"s.names");
293 if(m_defaultPositions)
295 m_presetPositions.resize(m_presetNames.size(), 0);
296 for(
size_t n=0;n<m_presetPositions.size();++n) m_presetPositions[n] = n+1;
299 config(m_presetPositions, m_presetNotation +
"s.positions");
301 if(m_defaultPositions)
303 for(
size_t n=0;n<m_presetPositions.size();++n)
if(m_presetPositions[n] == 0) m_presetPositions[n] = n+1;
311 template<
class derivedT>
315 std::string format =
"%.4f";
316 if(!m_fractionalPresets)
322 derived().createStandardIndiNumber( m_indiP_preset, m_presetNotation, 1.0, (
double) m_presetNames.size(), step, format);
323 m_indiP_preset[
"current"].set(0);
324 m_indiP_preset[
"target"].set(0);
325 if( derived().registerIndiPropertyNew( m_indiP_preset, st_newCallBack_stdMotionStage) < 0)
327 #ifndef STDFILTERWHEEL_TEST_NOLOG
328 derivedT::template log<software_error>({__FILE__,__LINE__});
333 if(derived().createStandardIndiSelectionSw( m_indiP_presetName, m_presetNotation +
"Name", m_presetNames) < 0)
335 derivedT::template log<software_critical>({__FILE__, __LINE__});
338 if( derived().registerIndiPropertyNew( m_indiP_presetName, st_newCallBack_stdMotionStage) < 0)
340 #ifndef STDFILTERWHEEL_TEST_NOLOG
341 derivedT::template log<software_error>({__FILE__,__LINE__});
346 derived().createStandardIndiRequestSw( m_indiP_home,
"home");
347 if( derived().registerIndiPropertyNew( m_indiP_home, st_newCallBack_stdMotionStage) < 0)
349 #ifndef STDFILTERWHEEL_TEST_NOLOG
350 derivedT::template log<software_error>({__FILE__,__LINE__});
355 derived().createStandardIndiRequestSw( m_indiP_stop,
"stop");
356 if( derived().registerIndiPropertyNew( m_indiP_stop, st_newCallBack_stdMotionStage) < 0)
358 #ifndef STDFILTERWHEEL_TEST_NOLOG
359 derivedT::template log<software_error>({__FILE__,__LINE__});
367 template<
class derivedT>
374 template<
class derivedT>
381 if( !derived().m_indiDriver )
return 0;
386 template<
class derivedT>
389 if( !derived().m_indiDriver )
return 0;
394 template<
class derivedT>
401 template<
class derivedT>
403 const pcf::IndiProperty &
ipRecv
406 std::string name =
ipRecv.getName();
407 derivedT * _app =
static_cast<derivedT *
>(app);
409 if(name ==
"stop")
return _app->newCallBack_m_indiP_stop(
ipRecv);
410 if(name ==
"home")
return _app->newCallBack_m_indiP_home(
ipRecv);
411 if(name == _app->m_presetNotation)
return _app->newCallBack_m_indiP_preset(
ipRecv);
412 if(name == _app->m_presetNotation +
"Name")
return _app->newCallBack_m_indiP_presetName (
ipRecv);
417 template<
class derivedT>
424 if( derived().indiTargetUpdate( m_indiP_preset, target,
ipRecv,
true) < 0)
426 derivedT::template log<software_error>({__FILE__,__LINE__});
430 m_preset_target = target;
432 std::lock_guard<std::mutex> guard(derived().m_indiMutex);
434 return derived().moveTo(target);
438 template<
class derivedT>
443 std::string newName =
"";
447 for(i=0; i< m_presetNames.size(); ++i)
449 if(!
ipRecv.find(m_presetNames[i]))
continue;
451 if(
ipRecv[m_presetNames[i]].getSwitchState() == pcf::IndiElement::On)
455 derivedT::template log<text_log>(
"More than one " + m_presetNotation +
" selected",
logPrio::LOG_ERROR);
459 newName = m_presetNames[i];
464 if(newName ==
"" || newn < 0)
469 std::lock_guard<std::mutex> guard(derived().m_indiMutex);
471 m_preset_target = m_presetPositions[newn];
472 derived().updateIfChanged(m_indiP_preset,
"target", m_preset_target,
INDI_BUSY);
475 return derived().moveTo(m_preset_target);
479 template<
class derivedT>
484 if(!
ipRecv.find(
"request"))
return 0;
486 if(
ipRecv[
"request"].getSwitchState() == pcf::IndiElement::On)
490 std::lock_guard<std::mutex> guard(derived().m_indiMutex);
492 return derived().startHoming();
497 template<
class derivedT>
502 if(
ipRecv.getName() != m_indiP_stop.getName())
504 derivedT::template log<software_error>({__FILE__,__LINE__,
"wrong INDI property received."});
508 if(!
ipRecv.find(
"request"))
return 0;
510 if(
ipRecv[
"request"].getSwitchState() == pcf::IndiElement::On)
516 return derived().stop();
521 template<
class derivedT>
524 if( !derived().m_indiDriver )
return 0;
526 int n = derived().presetNumber();
531 bool changed =
false;
533 static int8_t last_moving = -1;
535 if(last_moving != m_moving)
538 last_moving = m_moving;
541 for(
size_t i =0; i < m_presetNames.size(); ++i)
545 if(m_indiP_presetName[m_presetNames[i]] != pcf::IndiElement::On)
548 m_indiP_presetName[m_presetNames[i]] = pcf::IndiElement::On;
553 if(m_indiP_presetName[m_presetNames[i]] != pcf::IndiElement::Off)
556 m_indiP_presetName[m_presetNames[i]] = pcf::IndiElement::Off;
571 m_indiP_presetName.setTimeStamp(pcf::TimeStamp());
572 derived().m_indiDriver->sendSetProperty(m_indiP_presetName);
577 if(m_moving && m_movingState < 1)
588 return recordStage();
591 template<
class derivedT>
594 static int8_t last_moving = m_moving + 100;
595 static float last_preset;
596 static std::string last_presetName;
598 size_t n = derived().presetNumber();
600 std::string presetName;
601 if(n < m_presetNames.size()) presetName = m_presetNames[n];
603 if( m_moving != last_moving || m_preset != last_preset || presetName != last_presetName || force)
605 derived().template telem<telem_stage>({m_moving, m_preset, presetName});
606 last_moving = m_moving;
607 last_preset = m_preset;
608 last_presetName = presetName;
MagAO-X standard motion stage interface.
int loadConfig(mx::app::appConfigurator &config)
load the configuration system results
int onPowerOff()
Actions on power off.
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".
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.
pcf::IndiProperty m_indiP_presetName
The name of the nearest preset for this position.
int whilePowerOff()
Actions while powered off.
~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.
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].
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
The positions, in arbitrary units, of each preset. If 0, then the integer position number (starting f...
int recordStage(bool force=false)
int appLogic()
Application logic.
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...
int appShutdown()
Application the shutdown.
int newCallBack_m_indiP_preset(const pcf::IndiProperty &ipRecv)
Callback to process a NEW preset position request.
#define INDI_VALIDATE_CALLBACK_PROPS_DERIVED(prop1, prop2)
Standard check for matching INDI properties in a callback in a CRTP base class.
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.
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
constexpr static logPrioT LOG_ERROR
An error has occured which the software will attempt to correct.