12#include "../../libMagAOX/libMagAOX.hpp"
25template <
class parentT>
109 if( parent ==
nullptr )
111 throw mx::exception( mx::error_t::invalidarg,
"parent was null on construction of zaberState" );
128 int name(
const std::string &n );
276 const std::string &repBuff
298 const std::string &command
303 const std::string &command
313 template <
typename valT>
316 const std::string command
401template <
class parentT>
407template <
class parentT>
414template <
class parentT>
420template <
class parentT>
427template <
class parentT>
430 return m_deviceAddress;
433template <
class parentT>
436 m_deviceAddress = da;
440template <
class parentT>
446template <
class parentT>
453template <
class parentT>
456 return m_commandStatus;
459template <
class parentT>
462 return m_deviceStatus;
465template <
class parentT>
471template <
class parentT>
474 return m_lastHomed.tv_sec;
477template <
class parentT>
483template <
class parentT>
486 return m_knobEnabled;
489template <
class parentT>
495template <
class parentT>
501template <
class parentT>
507template <
class parentT>
513template <
class parentT>
519template <
class parentT>
525template <
class parentT>
531template <
class parentT>
537template <
class parentT>
543template <
class parentT>
549template <
class parentT>
555template <
class parentT>
561template <
class parentT>
567template <
class parentT>
573template <
class parentT>
579template <
class parentT>
585template <
class parentT>
591template <
class parentT>
597template <
class parentT>
603template <
class parentT>
609template <
class parentT>
615template <
class parentT>
621template <
class parentT>
627template <
class parentT>
633template <
class parentT>
639template <
class parentT>
645template <
class parentT>
651template <
class parentT>
655 int rv =
za_decode( &rep, repBuff.c_str(), repBuff.size() );
658 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
667 return getResponse( response, rep );
670template <
class parentT>
677 m_commandStatus =
true;
681 m_commandStatus =
false;
686 if( m_deviceStatus ==
'I' && m_homing )
690 if( clock_gettime( CLOCK_ISIO, &m_lastHomed ) < 0 )
716template <
class parentT>
722template <
class parentT>
727 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
737 int rv =
za_send( port, command.c_str(), command.size() );
741 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
755 rv =
za_receive( port, buff,
sizeof( buff ) );
759 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
769 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
779 rv =
za_decode( &rep, buff,
static_cast<size_t>( rv ) );
782 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
791 if( isCommandReply( rep ) )
792 return getResponse( response, rep );
800template <
class parentT>
801template <
typename valT>
804 if( m_deviceAddress < 1 )
807 { std::format(
"stage {} with s/n {} not found in system.", m_name, m_serial ) } );
810 std::string response;
812 int rv = sendCommand( response, port, std::format(
"/{} {}", m_deviceAddress, command ) );
816 if( m_commandStatus )
820 val = mx::ioutils::stoT<valT>( response, &errc );
825 std::format(
"parsing [{}] response from {}: {}", command, m_name, mx::errorMessage( errc ) ) );
832 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
843 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
854template <
class parentT>
857 int rv = getValue( m_maxPos, port,
"get limit.max" );
861 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
872template <
class parentT>
875 int rv = getValue( m_parked, port,
"tools parking state" );
879 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
890template <
class parentT>
893 int rv = getValue( m_knobEnabled, port,
"get knob.enable" );
897 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
908template <
class parentT>
911 int rv = getValue( m_ledEnabled, port,
"get system.led.enable" );
915 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
926template <
class parentT>
929 int rv = getValue( m_rawPos, port,
"get pos" );
933 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
944template <
class parentT>
947 int rv = getValue( m_temp, port,
"get driver.temperature" );
951 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
962template <
class parentT>
965 if( m_deviceAddress < 1 )
968 std::format(
"stage {} with s/n {} not found in system.", m_name, m_serial ) );
971 std::string response;
973 int rv = sendCommand( response, port, std::format(
"/{} {}", m_deviceAddress, command ) );
977 if( m_commandStatus )
983 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
989 { rv, std::format(
"{} {} commmand rejected", m_name, command ) } );
994 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1004template <
class parentT>
1007 std::string cmd = std::format(
"set knob.enable {}", enable ?
"1" :
"0" );
1009 int rv = sendCommand( port, cmd );
1013 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1024template <
class parentT>
1027 std::string cmd = std::format(
"set system.led.enable {}", enable ?
"1" :
"0" );
1029 int rv = sendCommand( port, cmd );
1033 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1044template <
class parentT>
1047 int rv = sendCommand( port,
"stop" );
1051 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1062template <
class parentT>
1065 int rv = sendCommand( port,
"estop" );
1069 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1080template <
class parentT>
1083 int rv = sendCommand( port,
"home" );
1087 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1100template <
class parentT>
1103 int rv = sendCommand( port,
"tools parking park" );
1107 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1120template <
class parentT>
1123 int rv = sendCommand( port,
"tools parking unpark" );
1127 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1139template <
class parentT>
1146 if( unpark( port ) < 0 )
1148 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1157 int rv = sendCommand( port, std::format(
"move abs {}", rawPos ) );
1161 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1172template <
class parentT>
1201template <
class parentT>
1206 if( !m_warnFDreported )
1209 " Driver Disabled (FD): The driver has disabled itself due to overheating.",
1211 m_warnFDreported =
true;
1217 else if( warn ==
"FQ" )
1219 if( !m_warnFQreported )
1222 m_warnFQreported =
true;
1228 else if( warn ==
"FS" )
1230 if( !m_warnFSreported )
1233 m_name +
" Stalled and Stopped (FS): Stalling was detected and the axis has stopped itself. ",
1235 m_warnFSreported =
true;
1240 else if( warn ==
"FT" )
1242 if( !m_warnFTreported )
1245 m_name +
" Excessive Twist (FT): The lockstep group has exceeded allowable twist and has stopped. ",
1247 m_warnFTreported =
true;
1253 else if( warn ==
"FB" )
1255 if( !m_warnFBreported )
1258 "executed because it failed a precondition",
1260 m_warnFBreported =
true;
1266 else if( warn ==
"FP" )
1268 if( !m_warnFPreported )
1271 m_name +
" Interpolated Path Deviation (FP): Streamed or sinusoidal motion was terminated because an "
1272 "axis slipped and thus the device deviated from the requested path. ",
1274 m_warnFPreported =
true;
1280 else if( warn ==
"FE" )
1282 if( !m_warnFEreported )
1285 m_name +
" Limit Error (FE): The target limit sensor cannot be reached or is faulty. ",
1287 m_warnFEreported =
true;
1293 else if( warn ==
"WH" )
1295 if( m_warnWHreported ==
false )
1298 m_name +
" Device not homed (WH): The device has a position reference, but has not been homed.",
1300 m_warnWHreported =
true;
1306 else if( warn ==
"WL" )
1308 if( !m_warnWLreported )
1311 "complete due to a triggered limit sensor.",
1313 m_warnWLreported =
true;
1319 else if( warn ==
"WP" )
1321 if( !m_warnWPreported )
1324 m_name +
" Invalid calibration type (WP): The saved calibration data type is unsupported",
1326 m_warnWPreported =
true;
1332 else if( warn ==
"WV" )
1334 if( !m_warnWVreported )
1337 "recommended operating range of the device",
1339 m_warnWVreported =
true;
1345 else if( warn ==
"WT" )
1347 if( !m_warnWTreported )
1350 "controller has exceeded the recommended limit for the device.",
1352 m_warnWTreported =
true;
1358 else if( warn ==
"WM" )
1360 if( m_warnWMreported ==
false )
1363 "been forced out of its position.",
1365 m_warnWMreported =
true;
1371 else if( warn ==
"WR" )
1373 if( m_warnWRreported ==
false )
1377 " No Reference Position (WR): Axis has not had a reference position established. [homing required]",
1379 m_warnWRreported =
true;
1385 else if( warn ==
"NC" )
1387 if( !m_warnNCreported )
1390 " Manual Control (NC): Axis is busy due to manual control via the knob.",
1392 m_warnNCreported =
true;
1398 else if( warn ==
"NI" )
1400 if( m_homing ==
true || warnWR() )
1405 if( !m_warnNIreported )
1408 "(command or manual control) was requested "
1409 "while the axis was executing another movement command.",
1411 m_warnNIreported =
true;
1417 else if( warn ==
"ND" )
1419 if( !m_warnNDreported )
1423 "streamed motion path because it has run out of queued motions.",
1425 m_warnNDreported =
true;
1431 else if( warn ==
"NU" )
1433 if( !m_warnNUreported )
1436 "updated or a reset is pending.",
1438 m_warnNUreported =
true;
1444 else if( warn ==
"NJ" )
1446 if( !m_warnNJreported )
1451 m_warnNJreported =
true;
1469template <
class parentT>
1477 nwarn = std::stoi( response.substr( 0, 2 ) );
1489 for(
size_t n = 0; n < nwarn; ++n )
1491 if( response.size() < 5 + n * 3 )
1493 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1501 std::string warn = response.substr( 3 + n * 3, 2 );
1503 int rv = processWarning( warn );
1506 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1516 if( m_warnFDreported )
1520 m_warnFDreported =
false;
1524 if( m_warnFQreported )
1528 m_warnFQreported =
false;
1532 if( m_warnFSreported )
1536 m_warnFSreported =
false;
1540 if( m_warnFTreported )
1544 m_warnFTreported =
false;
1548 if( m_warnFBreported )
1552 m_warnFBreported =
false;
1556 if( m_warnFPreported )
1560 m_warnFPreported =
false;
1564 if( m_warnFEreported )
1568 m_warnFEreported =
false;
1572 if( m_warnWHreported )
1576 m_warnWHreported =
false;
1580 if( m_warnWLreported )
1584 m_warnWLreported =
false;
1588 if( m_warnWPreported )
1592 m_warnWPreported =
false;
1596 if( m_warnWVreported )
1600 m_warnWVreported =
false;
1604 if( m_warnWTreported )
1608 m_warnWTreported =
false;
1612 if( m_warnWMreported )
1616 m_warnWMreported =
false;
1620 if( m_warnWRreported )
1624 m_warnWRreported =
false;
1628 if( m_warnNCreported )
1632 m_warnNCreported =
false;
1636 if( m_warnNIreported )
1640 m_warnNIreported =
false;
1644 if( m_warnNDreported )
1648 m_warnNDreported =
false;
1652 if( m_warnNUreported )
1656 m_warnNUreported =
false;
1660 if( m_warnNJreported )
1664 m_warnNJreported =
false;
1671template <
class parentT>
1674 if( m_deviceAddress < 1 )
1677 {
"stage " + m_name +
" with with s/n " + m_serial +
" not found in system." } );
1680 std::string response;
1682 int rv = sendCommand( response, port, std::format(
"/{} warnings", m_deviceAddress ) );
1686 if( m_commandStatus )
1689 return parseWarnings( response );
1693 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1704 if( m_parent->powerState() != 1 || m_parent->powerStateTarget() != 1 )
1714template <
class parentT>
1717 m_commandStatus =
true;
1719 m_deviceStatus =
'U';
1728 m_warnWRreported =
false;
1733template <
class parentT>
1736 fout << m_rawPos <<
'\n';
1743 fout << m_parked <<
'\n';
1750 fout << m_maxPos <<
'\n';
1757 fout << m_lastHomed.tv_sec <<
'\n';
1767template <
class parentT>
1807 m_lastHomed.tv_sec = lastHomed;
1808 m_lastHomed.tv_nsec = 0;
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
A class to manage the details of one stage in a Zaber system.
long m_maxPos
The max position allowed for the device, set by config. Will be set to no larger m_maxPosHW.
int unpark(z_port port)
Unpark the stage.
int getMaxPos(z_port port)
Get the maximum position from the stage.
int serial(const std::string &s)
Set the device serial.
char deviceStatus()
Get the device status.
bool isCommandReply(const za_reply &rep)
Determine whether a decoded message is the awaited command reply.
int axisNumber(const int &an)
Set the axis number.
int getWarnings(z_port port)
Get warnings from the device.
float m_temp
The driver temperature, in C.
long rawPos()
Get the current raw position, in counts.
int processWarning(std::string &warn)
Process a single warning from the device, setting the appropriate flag.
int readStateFile(std::ifstream &fin)
bool warn()
Get the status of the warning flag.
std::string name()
Get the device name.
int home(z_port port)
Initiate homing.
time_t lastHomed()
Get the time of last homing.
int writeStateFile(std::ofstream &fout)
int getParked(z_port port)
Get the parked state from the stage.
int stop(z_port port)
Stop the stage.
int sendCommand(z_port port, const std::string &command)
Send a command for which no response is expected.
bool ledEnabled()
Get the LED status.
int enableKnob(z_port port, bool enable)
Enable/Disable the knob.
bool m_commandStatus
The status of the last command sent. true = OK, false = RJ (rejected)
long maxPos()
Get the max position, in counts.
bool homing()
Get the homing status.
long tgtPos()
Get the current tgt position, in counts.
int sendCommand(std::string &response, z_port port, const std::string &command)
Send a command and get the response.
int m_axisNumber
The axis number at the address (normally 0 in MagAO-X)
int deviceAddress(const int &da)
Set the device address.
int onPowerOff()
Clear all state so that when the system is powered back on we get the correct new state.
int moveAbs(z_port port, long rawPos)
Move to a new absolute position.
int axisNumber()
Get the axis number.
zaberStage(parentT *parent)
long m_rawPos
The raw position reported by the device, in microsteps.
int updatePos(z_port port)
Update the position of the stage.
timespec m_lastHomed
Time stamp of the last time the stage was homed.
int parseWarnings(std::string &response)
Parse the warning response from the device.
std::string serial()
Get the device serial number.
bool commandStatus()
Get the command status.
int parked()
Get the parked status.
long m_tgtPos
The tgt position last sent to the device, in microsteps.
int estop(z_port port)
Emergency stop the stage.
std::string m_serial
The stage's serial number.
int enableLED(z_port port, bool enable)
int updateTemp(z_port port)
Update the stage temperature.
int park(z_port port)
Park the stage.
int name(const std::string &n)
Set the device name.
bool knobEnabled()
Get the knob status.
int deviceAddress()
Get the device address.
int getResponse(std::string &response, const za_reply &rep)
Get a response from the device, after a command has been sent.
int m_deviceAddress
The device's address, a.k.a. its order in the chain.
char m_deviceStatus
Current status. Either 'I' for IDLE or 'B' for BUSY. Intializes to 'U' for UNKOWN.
float temp()
Get the temperature, in C.
int getResponse(std::string &response, const std::string &repBuff)
Get a response from the device, after a command has been sent.
int getValue(valT &val, z_port port, const std::string command)
Get a value for this device.
std::string m_name
The stage's name.
bool warningState()
Get the warning state.
int unsetWarnings()
Sets all warning flags to false.
static constexpr logPrioT LOG_WARNING
A condition has occurred which may become an error, but the process continues.
static constexpr logPrioT LOG_EMERGENCY
Normal operations of the entire system should be shut down immediately.
int za_receive(z_port port, char *destination, int length)
int za_decode(struct za_reply *destination, const char *reply, size_t sMaxSz)
int za_send(z_port port, const char *command, size_t sMaxSz)
Provides a set of functions for interacting with Zaber devices in the ASCII protocol.