11#include "../../libMagAOX/libMagAOX.hpp"
12#include "../../magaox_git_version.h"
93 mx::app::appConfigurator &
_config );
143 int moveTo(
const double &pos );
211 config.add(
"stage.lowLevelName",
213 "stage.lowLevelName",
219 "The name of the low-level control process actually controlling this stage. "
220 "Default is zaberLowLevel." );
222 config.add(
"stage.stageName",
230 "the name of this stage in the low-level process INDI properties. "
231 "Default is the configuration name." );
233 config.add(
"stage.countsPerMillimeter",
235 "stage.countsPerMillimeter",
238 "countsPerMillimeter",
241 "The counts per mm calibration of the stage. Default is 10078.74, "
242 "which applies tot he X-LRQ-DE." );
244 config.add(
"stage.maxCounts",
252 "The maximum counts possible for this stage." );
291#ifndef ZABERCTRL_TEST_NOLOG
302#ifndef ZABERCTRL_TEST_NOLOG
318 indi::addNumberElement<int>(
m_indiP_parked,
"current", 0, 1, 1,
"%d" );
323 indi::addNumberElement<time_t>(
m_indiP_lastHomed,
"time_sec", 0, std::numeric_limits<time_t>::max(), 1,
"%d" );
544 pcf::IndiProperty
indiP_stageHome = pcf::IndiProperty( pcf::IndiProperty::Switch );
567 pcf::IndiProperty
indiP_stageHalt = pcf::IndiProperty( pcf::IndiProperty::Switch );
605 pcf::IndiProperty
indiP_stageTgtPos = pcf::IndiProperty( pcf::IndiProperty::Number );
630 if(
ipRecv.find(
"target" ) )
642 log<text_log>(
"abs move to " + std::to_string(
target ) +
" rejected due to already moving" );
646 log<text_log>(
"moving stage to " + std::to_string(
target ) );
648 std::lock_guard<std::mutex> guard( m_indiMutex );
651 clearPresetNameTracking();
665 if(
ipRecv.find(
"target" ) )
672 if(
ipRecv.find(
"current" ) )
685 log<text_log>(
"rel move rejected due to already moving" );
689 log<text_log>(
"moving stage by " + std::to_string(
target ) );
691 std::lock_guard<std::mutex> guard( m_indiMutex );
692 clearPresetNameTracking();
695 pcf::IndiProperty indiP_stageTgtPos = pcf::IndiProperty( pcf::IndiProperty::Text );
696 indiP_stageTgtPos.setDevice( m_lowLevelName );
697 indiP_stageTgtPos.setName(
"tgt_pos" );
698 indiP_stageTgtPos.setPerm( pcf::IndiProperty::ReadWrite );
699 indiP_stageTgtPos.setState( pcf::IndiProperty::Idle );
700 indiP_stageTgtPos.add( pcf::IndiElement( m_stageName ) );
701 indiP_stageTgtPos[m_stageName].set(
target );
705 if( sendNewProperty( indiP_stageTgtPos ) < 0 )
711 m_tgtPos = m_tgtRawPos / m_countsPerMillimeter;
721 if(
ipRecv.find( m_stageName ) !=
true )
726 m_indiP_stageState =
ipRecv;
728 std::string sstr =
ipRecv[m_stageName].get<std::string>();
730 std::lock_guard<std::mutex> guard( m_indiMutex );
732 if( sstr ==
"POWEROFF" )
736 syncPowerOffStageTelemetry();
740 else if( sstr ==
"POWERON" )
745 else if( sstr ==
"NODEVICE" )
750 else if( sstr ==
"NOTCONNECTED" )
755 else if( sstr ==
"CONNECTED" )
760 else if( sstr ==
"NOTHOMED" )
765 else if( sstr ==
"HOMING" )
771 else if( sstr ==
"READY" )
773 if( m_homingState == 0 || m_homePreset < 0 )
784 else if( sstr ==
"OPERATING" )
789 else if( sstr ==
"SHUTDOWN" )
794 else if( sstr ==
"FAILURE" )
799 else if( sstr ==
"ERROR" )
806 std::cerr <<
"else: " << sstr <<
"\n";
817 if(
ipRecv.find( m_stageName ) !=
true )
822 std::lock_guard<std::mutex> guard( m_indiMutex );
824 long maxRawPos =
ipRecv[m_stageName].get<
long>();
826 if( maxRawPos > 10000000000000 || maxRawPos < 0 )
829 if( (
unsigned long)maxRawPos != m_maxRawPos &&
833 log<text_log>( std::format(
"max position mismatch between config-ed value ({}) and stage value ({})",
846 if(
ipRecv.find( m_stageName ) !=
true )
851 std::lock_guard<std::mutex> guard( m_indiMutex );
853 m_rawPos =
ipRecv[m_stageName].get<
double>();
855 m_pos = m_rawPos / m_countsPerMillimeter;
877 if(
ipRecv.find( m_stageName ) !=
true )
883 std::string test =
ipRecv[m_stageName].get<std::string>();
890 std::lock_guard<std::mutex> guard( m_indiMutex );
892 m_tgtRawPos =
ipRecv[m_stageName].get<
double>();
893 m_tgtPos = m_tgtRawPos / m_countsPerMillimeter;
913 if(
ipRecv.find( m_stageName ) !=
true )
918 std::lock_guard<std::mutex> guard( m_indiMutex );
920 m_stageTemp =
ipRecv[m_stageName].get<
double>();
931 if(
ipRecv.find( m_stageName ) !=
true )
936 std::lock_guard<std::mutex> guard( m_indiMutex );
938 m_parked = (
ipRecv[m_stageName].get<
int>() != 0 );
942 syncPowerOffStageTelemetry();
947 updateIfChanged( m_indiP_parked,
"current",
static_cast<int>( m_parked ) );
956 if(
ipRecv.find( m_stageName ) !=
true )
961 std::lock_guard<std::mutex> guard( m_indiMutex );
963 m_lastHomed =
ipRecv[m_stageName].get<
double>();
The base-class for XWCTk applications.
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).
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.
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
int recordStage(bool force=false)
Record the stage telemetry state.
The MagAO-X Zaber Stage Controller.
double m_pos
Current position in mm.
pcf::IndiProperty m_indiP_stageMaxRawPos
virtual int appLogic()
Implementation of the FSM for zaberCtrl.
virtual int appStartup()
Startup function.
int syncPowerOffStageTelemetry()
Update the stage telemetry values used while the low-level stage is powered off.
std::string m_lowLevelName
pcf::IndiProperty m_indiP_stageLastHomed
virtual void setupConfig()
Setup the configuration of this stage controller.
friend class zaberCtrl_test
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.
INDI_SETCALLBACK_DECL(zaberCtrl, m_indiP_stageParked)
double m_tgtRawPos
Target raw position in counts.
int stop()
Stop the stage motion immediately.
std::string m_stageName
The name of this stage used for accessing via zaberLowLevel.
double m_maxPos
Maximum position in mm available on this stage.
virtual int appShutdown()
Shutdown the app.
pcf::IndiProperty m_indiP_rawPos
int m_homingState
The homing state, tracks the stages of homing.
int startHoming()
Start a high-level homing sequence.
INDI_SETCALLBACK_DECL(zaberCtrl, m_indiP_stageLastHomed)
~zaberCtrl() noexcept
D'tor, declared and defined for noexcept.
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
pcf::IndiProperty m_indiP_lastHomed
pcf::IndiProperty m_indiP_parked
INDI_NEWCALLBACK_DECL(zaberCtrl, m_indiP_pos)
int recordZaber(bool force=false)
bool m_wason
Whether the stage was in state power on before power off.
double m_countsPerMillimeter
Counts per millimeter calibration of this stage.
time_t m_lastHomed
Time stamp of the last time the stage was homed.
pcf::IndiProperty m_indiP_stageParked
bool m_parked
Whether the low-level Zaber stage reports a parked state.
double m_tgtPos
Target position in mm.
pcf::IndiProperty m_indiP_pos
INDI_SETCALLBACK_DECL(zaberCtrl, m_indiP_stageTgtPos)
double m_stageTemp
Temperature reported by the stage.
pcf::IndiProperty m_indiP_stageRawPos
double m_rawPos
Current raw position in counts.
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.
#define INDI_VALIDATE_CALLBACK_PROPS(prop1, prop2)
Standard check for matching INDI properties in a callback.
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.
const pcf::IndiProperty & ipRecv
updateIfChanged(m_indiP_angle, "target", m_angle)
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.
int loadConfig(appConfigurator &config)
Load the device section from an application configurator.
int setupConfig(appConfigurator &config)
Setup an application configurator for the device section.
@ 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.
Log entry recording stdMotionStage status.
Log entry recording zaber stage specific status.
A simple text log, a string-type log.