11 #ifndef smc100ccCtrl_hpp
12 #define smc100ccCtrl_hpp
14 #include "../../libMagAOX/libMagAOX.hpp"
15 #include "../../magaox_git_version.h"
112 const std::string & com
159 int moveTo(
double position);
194 config.add(
"stage.homingOffset",
"",
"stage.homingOffset", argType::Required,
"stage",
"homingOffset",
false,
"float",
"Homing offset, a.k.a. default starting position.");
195 config.add(
"stage.opDelta",
"",
"stage.opDelta", argType::Required,
"stage",
"opDelta",
false,
"float",
"Threshold move size for switching to OPERATING.");
215 log<software_error>({ __FILE__, __LINE__,
"error loading USB device configs"});
223 log<software_error>({ __FILE__, __LINE__,
"error loading io device configs"});
230 log<software_error>({ __FILE__, __LINE__,
"error loading stdMotionStage configs"});
237 log<software_error>({ __FILE__, __LINE__,
"error loading telemeter configs"});
268 log<software_error>({ __FILE__, __LINE__,
"error starting up stdMotionStage"});
275 log<software_error>({ __FILE__, __LINE__,
"error starting up telemeter"});
292 log<software_error>({__FILE__, __LINE__});
309 std::stringstream logs;
311 log<text_log>(logs.str());
334 std::stringstream logs;
336 log<text_log>(logs.str());
345 std::stringstream logs;
347 log<text_log>(logs.str());
376 std::stringstream logs;
378 log<text_log>(logs.str());
396 std::string errorString;
399 log<software_error>({__FILE__, __LINE__,errorString});
408 std::stringstream logs;
410 log<text_log>(logs.str());
419 log<software_error>({__FILE__, __LINE__});
432 return log<software_error, 0>({__FILE__,__LINE__});
437 if(axState[0] ==
'0')
441 else if (axState[0] ==
'1' && axState[1] ==
'0')
444 log<text_log>(
"getting stage information");
448 log<software_error>({__FILE__, __LINE__,
"Error making command PW1" });
463 log<software_error>({__FILE__, __LINE__,
"Error making command ZX2" });
478 log<software_error>({__FILE__, __LINE__,
"Error making command PW0" });
491 log<text_log>(
"stage information loaded");
495 else if (axState[0] ==
'1' && (axState[1] ==
'E' || axState[1] ==
'F'))
501 else if (axState[0] ==
'2')
509 else if (axState[0] ==
'3' && isdigit(axState[1]))
524 else if (axState[0] ==
'3')
526 log<text_log>(
"Stage disabled. Enabling");
530 log<software_error>({__FILE__, __LINE__,
"Error making command PW1" });
541 else if( axState[0] ==
'\0' && axState[1] ==
'\0' )
553 log<software_error>({__FILE__,__LINE__,
"Invalid state: |" + std::to_string(axState[0]) +
"|" + std::to_string(axState[1]) +
"|"});
580 std::string errorString;
582 if (
getLastError(errorString) != 0 && errorString.size() != 0)
584 log<software_error>({__FILE__, __LINE__,errorString});
587 log<software_error>({__FILE__, __LINE__,
"There's been an error with getting current controller position."});
594 static int last_moving = -1;
596 bool changed =
false;
659 std::stringstream logs;
661 log<text_log>(logs.str());
672 log<text_log>(
"Error NOT due to loss of USB connection. I can't fix it myself.",
logPrio::LOG_CRITICAL);
682 std::string buffer{
"1TS\r\n"};
709 const std::string & com
716 snprintf(tmp, 10,
"%i", axis);
728 if(resp.length() < 3)
730 log<software_error>({__FILE__,__LINE__,
"Invalid response"});
736 log<software_error>({__FILE__,__LINE__,
"Invalid response"});
745 axis = resp[0] -
'0';
749 axis = atoi(resp.substr(0,2).c_str());
755 com = resp.substr(1,2);
756 if(resp.length() < 4 ) val =
"";
757 else val = resp.substr(3, resp.length()-3);
760 while(val[val.size()-1] ==
'\r' || val[val.size()-1] ==
'\n')
762 val.erase(val.size()-1);
763 if(val.size() < 1)
break;
769 if(resp.length() < 4)
771 log<software_error>({__FILE__,__LINE__,
"Invalid response"});
776 com = resp.substr(2,2);
777 if(resp.length() < 5) val =
"";
778 else val = resp.substr(4, resp.length()-4);
782 while(val[val.size()-1] ==
'\r' || val[val.size()-1] ==
'\n')
784 val.erase(val.size()-1);
785 if(val.size() < 1)
break;
795 std::string com, resp;
799 log<software_error>({__FILE__, __LINE__,
"Error making command TS" });
813 std::string rcom, rval;
819 log<software_error>({__FILE__, __LINE__,
"An Error occurred"});
825 log<software_error>({__FILE__, __LINE__,
"Wrong axis returned"});
831 log<software_error>({__FILE__, __LINE__,
"Wrong command returned"});
835 if(rval.length() != 6)
837 log<software_error>({__FILE__, __LINE__,
"Incorrect response length" });
841 state = rval.substr(4, 2);
849 std::string buffer{
"1TP\r\n"};
863 current = std::stod(output.substr(3));
867 log<software_error>({__FILE__, __LINE__,
"Error occured: Unexpected output in getPosition()"});
875 std::string buffer{
"1TE\r\n"};
882 log<software_error>({__FILE__, __LINE__});
883 std::cerr << __FILE__ <<
" " << __LINE__ <<
" " << rv <<
"\n";
892 status = output.at(3);
894 catch (
const std::out_of_range& oor)
896 log<software_error>({__FILE__, __LINE__});
897 errorString =
"Unknown output; controller not responding correctly.";
910 errorString =
"Unknown message code or floating point controller address.";
913 errorString =
"Controller address not correct.";
916 errorString =
"Parameter missing or out of range.";
919 errorString =
"Command not allowed.";
922 errorString =
"Home sequence already started.";
925 errorString =
"ESP stage name unknown.";
928 errorString =
"Displacement out of limits.";
931 errorString =
"Command not allowed in NOT REFERENCED state.";
934 errorString =
"Command not allowed in CONFIGURATION state.";
937 errorString =
"Command not allowed in DISABLE state.";
940 errorString =
"Command not allowed in READY state.";
943 errorString =
"Command not allowed in HOMING state.";
946 errorString =
"UCommand not allowed in MOVING state.";
949 errorString =
"Current position out of software limit.";
952 errorString =
"Communication Time Out.";
955 errorString =
"Error during EEPROM access.";
958 errorString =
"Error during command execution.";
961 errorString =
"Command not allowed for PP version.";
964 errorString =
"Command not allowed for CC version.";
967 errorString =
"unknown status";
968 std::cerr <<
"unkown status: " << status <<
"\n";
971 log<software_error>({__FILE__, __LINE__});
982 log<text_log>(
"can not command position in current state");
987 float current = -1e55, target = -1e55;
991 current =
ipRecv[
"current"].get<
float>();
997 target =
ipRecv[
"target"].get<
float>();
1001 if(target == -1e55) target = current;
1003 if(target == -1e55)
return 0;
1006 std::unique_lock<std::mutex>
lock(m_indiMutex);
1012 return moveTo(target);
1023 std::string buffer{
"1ST\r\n"};
1044 std::string buffer{
"1OR\r\n"};
1080 std::string buffer{
"1PA"};
1081 buffer = buffer + std::to_string(position) +
"\r\n";
1092 std::string errorString;
1104 log<software_error>({__FILE__, __LINE__,errorString});
1131 static float last_position = 1e30;
1135 if( fpos != last_position || force )
1137 telem<telem_position>(fpos);
1138 last_position = fpos;
Internal class to manage setuid privilege escalation with RAII.
The base-class for MagAO-X 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.
stateCodes::stateCodeT state()
Get the current state code.
int m_shutdown
Flag to signal it's time to shutdown. When not 0, the main loop exits.
int m_powerState
Current power state, 1=On, 0=Off, -1=Unk.
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.
int stateLogged()
Updates and returns the value of m_stateLogged. Will be 0 on first call after a state change,...
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
bool powerOnWaitElapsed()
This method tests whether the power on wait time has elapsed.
unsigned long m_powerOnWait
Time in sec to wait for device to boot after power on.
std::mutex m_indiMutex
Mutex for locking INDI communications.
int m_powerTargetState
Current target power state, 1=On, 0=Off, -1=Unk.
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.
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.
float m_preset
The current numerical preset position [1.0 is index 0 in the preset name vector].
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.
int getPosition(double &pos)
Verifies current status of controller.
int recordTelem(const telem_stage *)
std::vector< std::string > validStateCodes
int getLastError(std::string &errStr)
Returns any error controller has.
virtual int appLogic()
Changes device state based on testing connection and device status.
bool m_moveOp
Flag indicating that OPERATING should not be set for a move, because it's less than m_opDelta.
int testConnection()
Tests if device is cabale of recieving/executing IO commands.
INDI_NEWCALLBACK_DECL(smc100ccCtrl, m_indiP_position)
smc100ccCtrl()
Default c'tor.
double m_opDelta
The threshold for switching to OPERATING.
virtual void setupConfig()
Setup the configuration system (called by MagAOXApp::setup())
virtual void loadConfig()
Load the configuration system results (called by MagAOXApp::setup())
int moveTo(double position)
int recordStage(bool force=false)
virtual int appShutdown()
Do any needed shutdown tasks. Currently nothing in this app.
int recordPosition(bool force=false)
pcf::IndiProperty m_indiP_position
Indi variable for reporting the stage position.
int getCtrlState(std::string &state)
virtual int appStartup()
Checks if the device was found during loadConfig.
int makeCom(std::string &str, const std::string &com)
int splitResponse(int &axis, std::string &com, std::string &val, std::string &resp)
virtual int onPowerOff()
This method is called when the change to poweroff is detected.
#define REG_INDI_NEWPROP(prop, propName, type)
Register a NEW INDI property with the class, using the standard callback name.
@ OPERATING
The device is operating, other than homing.
@ 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.
int ttyWriteRead(std::string &strRead, const std::string &strWrite, const std::string &eot, bool swallowEcho, int fd, int timeoutWrite, int timeoutRead)
Write to a tty on an open file descriptor, then get the result.
std::string ttyErrorString(int ec)
Get a text explanation of a TTY_E_ error code.
int ttyWrite(const std::string &buffWrite, int fd, int timeoutWrite)
Write to the tty console indicated by a file descriptor.
INDI_VALIDATE_CALLBACK_PROPS(function, ipRecv)
const pcf::IndiProperty & ipRecv
updateIfChanged(m_indiP_angle, "target", m_angle)
INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_windspeed)(const pcf
std::unique_lock< std::mutex > lock(m_indiMutex)
constexpr static logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
An input/output capable device.
unsigned m_writeTimeout
The write timeout [msec].
int loadConfig(mx::app::appConfigurator &config)
Load the device section from an application configurator.
int setupConfig(mx::app::appConfigurator &config)
Setup an application configurator for the device section.
unsigned m_readTimeout
The read timeout [msec].
A device base class which saves telemetry.
int loadConfig(appConfigurator &config)
Load the device section from an application configurator.
int appLogic()
Perform telemeter application logic.
int setupConfig(appConfigurator &config)
Setup an application configurator for the device section.
int appStartup()
Starts the telemetry log thread.
int checkRecordTimes(const telT &tel, telTs... tels)
Check the time of the last record for each telemetry type and make an entry if needed.
Log entry recording position stage specific status.
Log entry recording stdMotionStage status.
A simple text log, a string-type log.
A USB device as a TTY device.
std::string m_deviceName
The device path name, e.g. /dev/ttyUSB0.
int m_fileDescrip
The file descriptor.
int connect()
Connect to the device.
int getDeviceName()
Get the device name from udev using the vendor, product, and serial number.
std::string m_idProduct
The product id 4-digit code.
int setupConfig(mx::app::appConfigurator &config)
Setup an application configurator for the USB section.
std::string m_serial
The serial number.
int loadConfig(mx::app::appConfigurator &config)
Load the USB section from an application configurator.
speed_t m_baudRate
The baud rate specification.
std::string m_idVendor
The vendor id 4-digit code.
#define TTY_E_DEVNOTFOUND