10#include "../../libMagAOX/libMagAOX.hpp"
11#include "../../magaox_git_version.h"
230 const std::string &
arg);
233 const std::string &
com,
300 config.add(
"stage.naxes",
"",
"stage.naxes", argType::Required,
"stage",
"naxes",
false,
"int",
"Number of axes. Default is 2. Max is 3.");
302 config.add(
"stage.homePos1",
"",
"stage.homePos1", argType::Required,
"stage",
"homePos1",
false,
"float",
"Home position of axis 1. Default is 17.5.");
303 config.add(
"stage.homePos2",
"",
"stage.homePos2", argType::Required,
"stage",
"homePos2",
false,
"float",
"Home position of axis 2. Default is 17.5.");
304 config.add(
"stage.homePos3",
"",
"stage.homePos3", argType::Required,
"stage",
"homePos3",
false,
"float",
"Home position of axis 3. Default is 17.5.");
306 config.add(
"dm.calibRelDir",
"",
"dm.calibRelDir", argType::Required,
"dm",
"calibRelDir",
false,
"string",
"Used to find the default calib directory.");
328 config(
m_naxes,
"stage.naxes");
447 elevatedPrivileges
elPriv(
this);
468 std::stringstream
logs;
503 if (!(
atz == 0 ||
atz == 1))
560 mx::sys::milliSleep(1);
582 mx::sys::milliSleep(1);
592 mx::sys::milliSleep(1);
612 mx::sys::milliSleep(1);
626 mx::sys::milliSleep(1);
646 mx::sys::milliSleep(1);
694 if ((
st =
resp.find(
"E-727.3SDA")) == std::string::npos)
698 m_ctrl = mx::ioutils::removeWhiteSpace(
resp.substr(
st));
727 if (
resp1.find(
"1=S-335") == 0 &&
resp2.find(
"2=S-335") == 0 &&
resp3.find(
"3=0") == 0)
733 else if (
resp1.find(
"1=S-325") == 0 &&
resp2.find(
"2=S-325") == 0 &&
resp3.find(
"3=S-325") == 0)
767 if ((
st =
resp.find(
'=')) == std::string::npos)
772 m_min1 = mx::ioutils::convertFromString<float>(
resp.substr(
st + 1));
780 if ((
st =
resp.find(
'=')) == std::string::npos)
785 m_max1 = mx::ioutils::convertFromString<float>(
resp.substr(
st + 1));
793 if ((
st =
resp.find(
'=')) == std::string::npos)
798 m_min2 = mx::ioutils::convertFromString<float>(
resp.substr(
st + 1));
806 if ((
st =
resp.find(
'=')) == std::string::npos)
811 m_max2 = mx::ioutils::convertFromString<float>(
resp.substr(
st + 1));
821 if ((
st =
resp.find(
'=')) == std::string::npos)
826 m_min3 = mx::ioutils::convertFromString<float>(
resp.substr(
st + 1));
834 if ((
st =
resp.find(
'=')) == std::string::npos)
839 m_max3 = mx::ioutils::convertFromString<float>(
resp.substr(
st + 1));
957 size_t st =
resp.find(
'=');
958 if (
st == std::string::npos ||
st >
resp.size() - 2)
965 return mx::ioutils::convertFromString<double>(
resp.substr(
st));
1098 mx::sys::milliSleep(2000);
1108 mx::sys::milliSleep(2000);
1120 mx::sys::milliSleep(2000);
1162 mx::sys::milliSleep(250);
1174 mx::sys::milliSleep(250);
1188 mx::sys::milliSleep(1000);
1193 std::string
com =
"MOV 1 " + std::to_string(
m_homePos1) +
"\n";
1251 float pos1 = ((
float *)
curr_src)[0];
1252 float pos2 = ((
float *)
curr_src)[1];
1320 const std::string &com,
1352 size_t st =
resp.find(
'=');
1353 if (
st == std::string::npos ||
st >
resp.size() - 2)
1359 pos = mx::ioutils::convertFromString<double>(
resp.substr(
st));
1374 size_t st =
resp.find(
'=');
1375 if (
st == std::string::npos ||
st >
resp.size() - 2)
1381 sva = mx::ioutils::convertFromString<double>(
resp.substr(
st));
1416 std::string
com =
"MOV 1 " + std::to_string(
absPos) +
"\n";
1439 std::string
com =
"MOV 2 " + std::to_string(
absPos) +
"\n";
1467 std::string
com =
"MOV 3 " + std::to_string(
absPos) +
"\n";
1480(
const pcf::IndiProperty &
ipRecv)
1482 if (
ipRecv.createUniqueKey() == m_indiP_pos1.createUniqueKey())
1484 float current = -999999, target = -999999;
1486 if (
ipRecv.find(
"current"))
1488 current =
ipRecv[
"current"].get<
float>();
1491 if (
ipRecv.find(
"target"))
1493 target =
ipRecv[
"target"].get<
float>();
1496 if (target == -999999)
1499 if (target == -999999)
1505 std::unique_lock<std::mutex>
lock(m_indiMutex);
1509 updateFlat(target, m_pos2Set, m_pos3Set);
1511 return move_1(target);
1515 return updateFlat(target, m_pos2Set, m_pos3Set);
1522(
const pcf::IndiProperty &
ipRecv)
1524 if (
ipRecv.createUniqueKey() == m_indiP_pos2.createUniqueKey())
1526 float current = -999999, target = -999999;
1528 if (
ipRecv.find(
"current"))
1530 current =
ipRecv[
"current"].get<
float>();
1533 if (
ipRecv.find(
"target"))
1535 target =
ipRecv[
"target"].get<
float>();
1538 if (target == -999999)
1541 if (target == -999999)
1547 std::unique_lock<std::mutex>
lock(m_indiMutex);
1550 updateFlat(m_pos1Set, target, m_pos3Set);
1551 return move_2(target);
1555 return updateFlat(m_pos1Set, target, m_pos3Set);
1562(
const pcf::IndiProperty &
ipRecv)
1565 if (
ipRecv.getName() == m_indiP_pos3.getName())
1567 float current = -999999, target = -999999;
1569 if (
ipRecv.find(
"current"))
1571 current =
ipRecv[
"current"].get<
float>();
1574 if (
ipRecv.find(
"target"))
1576 target =
ipRecv[
"target"].get<
float>();
1579 if (target == -999999)
1582 if (target == -999999)
1588 std::unique_lock<std::mutex>
lock(m_indiMutex);
1592 updateFlat(m_pos1Set, m_pos2Set, target);
1593 return move_3(target);
1597 return updateFlat(m_pos1Set, m_pos2Set, target);
1615 static float pos1Set = std::numeric_limits<float>::max();
1616 static float pos1 = std::numeric_limits<float>::max();
1617 static float sva1 = std::numeric_limits<float>::max();
1618 static float pos2Set = std::numeric_limits<float>::max();
1619 static float pos2 = std::numeric_limits<float>::max();
1620 static float sva2 = std::numeric_limits<float>::max();
1621 static float pos3Set = std::numeric_limits<float>::max();
1622 static float pos3 = std::numeric_limits<float>::max();
1623 static float sva3 = std::numeric_limits<float>::max();
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 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.
std::mutex m_indiMutex
Mutex for locking INDI communications.
std::string m_calibRelDir
The directory relative to the calibPath. Set this before calling dm<derivedT,realT>::loadConfig().
bool m_flatSet
Flag indicating whether the flat command has been set.
bool m_flatLoaded
Flag indicating whether a flat is loaded in memory.
int setFlat(bool update=false)
Send the current flat command to the DM.
mx::improc::eigenImage< float > m_flatCommand
Data storage for the flat command.
The MagAO-X PI 335 Controller Interface.
virtual int appShutdown()
Shutdown the app.
INDI_NEWCALLBACK_DECL(pi335Ctrl, m_indiP_pos2)
dev::shmimMonitor< pi335Ctrl > shmimMonitorT
int testConnection()
Test the connection to the device.
virtual void loadConfig()
int commandDM(void *curr_src)
Send a command to the DM.
int home()
Start the homing procedure.
int m_naxes
The number of axes, default is 2. Max is 3.
int setCom(const std::string &com)
float m_max1
The maximum value for axis 1.
float m_posTol
The tolerance for reporting a raw position rather than the setpoint.
pcf::IndiProperty m_indiP_pos3
int getSva(float &sva, int n)
Get the open loop control value.
INDI_NEWCALLBACK_DECL(pi335Ctrl, m_indiP_pos1)
int getPos(float &pos, int n)
int recordTelem(const telem_pi335 *)
float m_homePos1
Home position of axis 1. Default is 17.5.
INDI_NEWCALLBACK_DECL(pi335Ctrl, m_indiP_pos3)
~pi335Ctrl() noexcept
D'tor, declared and defined for noexcept.
friend class pi335Ctrl_test
int home_1()
Begin homing (ATZ) axis 1.
int move_3(float absPos)
Send command to device to move axis 3.
std::string m_stage
The stage connected.
int getCom(std::string &resp, const std::string &com, int axis)
virtual void setupConfig()
float m_max3
The maximum value for axis 3.
int recordPI335(bool force=false)
int setCom(const std::string &com, int axis, const std::string &arg)
int homeState(int axis)
Get the status of homing on an axiz.
int releaseDM()
Release the DM, making it safe to turn off power.
int home_3()
Begin homing (ATZ) axis 3.
int updateFlat(float absPos1, float absPos2, float absPos3)
Update the flat command and propagate.
float m_min2
The minimum value for axis 2.
float m_homePos2
Home position of axis 2. Default is 17.5.
dev::telemeter< pi335Ctrl > telemeterT
float m_min1
The minimum value for axis 1.
std::string m_ctrl
The controller connected.
int home_2()
Begin homing (ATZ) axis 2.
pi335Ctrl()
Default c'tor.
int move_1(float absPos)
Send command to device to move axis 1.
float m_min3
The minimum value for axis 3.
float m_homePos3
Home position of axis 2. Default is 17.5.
virtual int appLogic()
Implementation of the FSM for pi335Ctrl.
int zeroDM()
Zero all commands on the DM.
float m_max2
The maximum value for axis 2.
virtual int appStartup()
Startup function.
pcf::IndiProperty m_indiP_pos2
int setCom(const std::string &com, int axis)
dev::dm< pi335Ctrl, float > dmT
pcf::IndiProperty m_indiP_pos1
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
int move_2(float absPos)
Send command to device to move axis 2.
#define DM_SETUP_CONFIG(cfig)
Call dmT::setupConfig with error checking for dm.
#define DM_APP_SHUTDOWN
Call dmT::appShutdown with error checking for dm.
#define DM_LOAD_CONFIG(cfig)
Call dmT::loadConfig with error checking for dm.
#define DM_APP_STARTUP
Call shmimMonitorT::appStartup with error checking for dm.
#define DM_APP_LOGIC
Call dmT::appLogic with error checking for dm.
#define DM_UPDATE_INDI
Call dmT::updateINDI with error checking for dm.
#define INDI_NEWCALLBACK_DEFN(class, prop)
Define the callback for a new property request.
#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.
@ 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.
const pcf::IndiProperty & ipRecv
updateIfChanged(m_indiP_angle, "target", m_angle)
std::unique_lock< std::mutex > lock(m_indiMutex)
static constexpr logPrioT LOG_NOTICE
A normal but significant condition.
static constexpr logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
static constexpr logPrioT LOG_ERROR
An error has occured which the software will attempt to correct.
#define SHMIMMONITOR_APP_SHUTDOWN
Call shmimMonitorT::appShutdown with error checking for shmimMonitor.
#define SHMIMMONITOR_APP_LOGIC
Call shmimMonitorT::appLogic with error checking for shmimMonitor.
#define SHMIMMONITOR_APP_STARTUP
Call shmimMonitorT::appStartup with error checking for shmimMonitor.
#define SHMIMMONITOR_UPDATE_INDI
Call shmimMonitorT::updateINDI with error checking for shmimMonitor.
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 checkRecordTimes(const telT &tel, telTs... tels)
Check the time of the last record for each telemetry type and make an entry if needed.
Software CRITICAL log entry.
Log entry recording the build-time git state.
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 TELEMETER_APP_LOGIC
Call telemeter::appLogic with error checking.
#define TELEMETER_LOAD_CONFIG(cfig)
Call telemeter::loadConfig with error checking.
#define TELEMETER_APP_STARTUP
Call telemeter::appStartup with error checking.
#define TELEMETER_SETUP_CONFIG(cfig)
Call telemeter::setupConfig with error checking.
#define TELEMETER_APP_SHUTDOWN
Call telemeter::appShutdown with error checking.
#define TTY_E_DEVNOTFOUND