11 #include "../../libMagAOX/libMagAOX.hpp"
12 #include "../../magaox_git_version.h"
218 const std::string & arg
221 int getCom( std::string & resp,
222 const std::string & com,
244 int move_1(
float absPos );
247 int move_2(
float absPos );
250 int move_3(
float absPos );
277 config.add(
"stage.naxes",
"",
"stage.naxes", argType::Required,
"stage",
"naxes",
false,
"int",
"Number of axes. Default is 2. Max is 3.");
279 config.add(
"stage.homePos1",
"",
"stage.homePos1", argType::Required,
"stage",
"homePos1",
false,
"float",
"Home position of axis 1. Default is 17.5.");
280 config.add(
"stage.homePos2",
"",
"stage.homePos2", argType::Required,
"stage",
"homePos2",
false,
"float",
"Home position of axis 2. Default is 17.5.");
281 config.add(
"stage.homePos3",
"",
"stage.homePos3", argType::Required,
"stage",
"homePos3",
false,
"float",
"Home position of axis 3. Default is 17.5.");
283 config.add(
"dm.calibRelDir",
"",
"dm.calibRelDir", argType::Required,
"dm",
"calibRelDir",
false,
"string",
"Used to find the default calib directory.");
305 config(
m_naxes,
"stage.naxes");
419 elevatedPrivileges elPriv(
this);
439 std::stringstream logs;
441 log<text_log>(logs.str());
475 if(! (atz == 0 || atz == 1))
524 log<software_error>({__FILE__,__LINE__});
530 mx::sys::milliSleep(1);
532 if(fabs(
m_pos1-pos1) > 0.1)
544 log<software_error>({__FILE__,__LINE__});
551 mx::sys::milliSleep(1);
556 log<software_error>({__FILE__,__LINE__});
561 mx::sys::milliSleep(1);
563 if(fabs(
m_pos2 - pos2) > 0.1)
575 log<software_error>({__FILE__,__LINE__});
580 mx::sys::milliSleep(1);
589 log<software_error>({__FILE__,__LINE__});
594 mx::sys::milliSleep(1);
596 if(fabs(
m_pos3 - pos3) > 0.1)
608 log<software_error>({__FILE__,__LINE__});
613 mx::sys::milliSleep(1);
656 std::cerr <<
"idn response: " << resp <<
"\n";
659 if( (st = resp.find(
"E-727.3SDA")) == std::string::npos)
663 m_ctrl = mx::ioutils::removeWhiteSpace(resp.substr(st));
666 std::string resp1, resp2, resp3;
672 resp1 = mx::ioutils::removeWhiteSpace(resp1);
674 std::cerr <<
"CST? 1 response: " << resp1 <<
"\n";
680 resp2 = mx::ioutils::removeWhiteSpace(resp2);
682 std::cerr <<
"CST? 2 response: " << resp2 <<
"\n";
688 resp3 = mx::ioutils::removeWhiteSpace(resp3);
690 std::cerr <<
"CST? 3 response: " << resp3 <<
"\n";
698 if( resp1.find(
"1=S-335") == 0 && resp2.find(
"2=S-335") == 0 && resp3.find(
"3=0") == 0)
704 else if( resp1.find(
"1=S-325") == 0 && resp2.find(
"2=S-325") == 0 && resp3.find(
"3=S-325") == 0)
727 log<text_log>(
"Found " +
m_stage +
" with " + std::to_string(
m_naxes) +
" axes");
738 if((st = resp.find(
'=')) == std::string::npos)
743 m_min1 = mx::ioutils::convertFromString<float>(resp.substr(st+1));
744 log<text_log>(
"axis 1 min: " + std::to_string(
m_min1));
751 if((st = resp.find(
'=')) == std::string::npos)
756 m_max1 = mx::ioutils::convertFromString<float>(resp.substr(st+1));
757 log<text_log>(
"axis 1 max: " + std::to_string(
m_max1));
764 if((st = resp.find(
'=')) == std::string::npos)
769 m_min2 = mx::ioutils::convertFromString<float>(resp.substr(st+1));
770 log<text_log>(
"axis 2 min: " + std::to_string(
m_min2));
777 if((st = resp.find(
'=')) == std::string::npos)
782 m_max2 = mx::ioutils::convertFromString<float>(resp.substr(st+1));
783 log<text_log>(
"axis 2 max: " + std::to_string(
m_max2));
792 if((st = resp.find(
'=')) == std::string::npos)
797 m_min3 = mx::ioutils::convertFromString<float>(resp.substr(st+1));
798 log<text_log>(
"axis 3 min: " + std::to_string(
m_min3));
805 if((st = resp.find(
'=')) == std::string::npos)
810 m_max3 = mx::ioutils::convertFromString<float>(resp.substr(st+1));
811 log<text_log>(
"axis 3 max: " + std::to_string(
m_max3));
950 if(
getCom( resp,
"ATZ?", axis) < 0)
952 log<software_error>( {__FILE__, __LINE__});
958 size_t st = resp.find(
'=');
959 if(st == std::string::npos || st > resp.size()-2)
961 log<software_error>( {__FILE__, __LINE__,
"error parsing response"});
966 return mx::ioutils::convertFromString<double>(resp.substr(st));
984 log<text_log>(
"home_1 requested but not in correct homing state",
logPrio::LOG_ERROR);
1002 log<text_log>(
"commenced homing x");
1019 log<text_log>(
"home_2 requested but not in correct homing state",
logPrio::LOG_ERROR);
1036 log<text_log>(
"commenced homing y");
1053 log<text_log>(
"home_3 requested but not in correct homing state",
logPrio::LOG_ERROR);
1070 log<text_log>(
"commenced homing z");
1088 log<text_log>(
"finishInit requested but not in correct homing state",
logPrio::LOG_ERROR);
1093 log<text_log>(
"finishInit requested but not in correct homing state",
logPrio::LOG_ERROR);
1105 mx::sys::milliSleep(2000);
1115 mx::sys::milliSleep(2000);
1127 mx::sys::milliSleep(2000);
1170 mx::sys::milliSleep(250);
1182 mx::sys::milliSleep(250);
1197 mx::sys::milliSleep(1000);
1204 std::string com =
"MOV 1 " + std::to_string(
m_homePos1) +
"\n";
1216 com =
"MOV 2 " + std::to_string(
m_homePos2) +
"\n";
1230 com =
"MOV 3 " + std::to_string(
m_homePos3) +
"\n";
1294 log<text_log>(
"DM zeroed");
1301 float pos1 = ((
float *) curr_src)[0];
1302 float pos2 = ((
float *) curr_src)[1];
1305 if(
m_naxes == 3) pos3 = ((
float *) curr_src)[2];
1310 if( (rv =
move_1(pos1)) < 0)
return rv;
1312 if( (rv =
move_2(pos2)) < 0)
return rv;
1366 const std::string & com,
1370 std::string sendcom = com;
1371 if(axis == 1 || axis == 2)
1374 sendcom += std::to_string(axis);
1397 if(
getCom(resp,
"POS?", n) < 0)
1399 log<software_error>( {__FILE__, __LINE__});
1404 size_t st = resp.find(
'=');
1405 if(st == std::string::npos || st > resp.size()-2)
1407 log<software_error>( {__FILE__, __LINE__,
"error parsing response"});
1411 pos = mx::ioutils::convertFromString<double>(resp.substr(st));
1421 if(
getCom(resp,
"SVA?", n) < 0)
1423 log<software_error>( {__FILE__, __LINE__});
1427 size_t st = resp.find(
'=');
1428 if(st == std::string::npos || st > resp.size()-2)
1430 log<software_error>( {__FILE__, __LINE__,
"error parsing response"});
1434 sva = mx::ioutils::convertFromString<double>(resp.substr(st));
1462 if(absPos < m_min1 || absPos >
m_max1)
1470 std::string com =
"MOV 1 " + std::to_string(absPos) +
"\n";
1487 if(absPos < m_min2 || absPos >
m_max2)
1494 std::string com =
"MOV 2 " + std::to_string(absPos) +
"\n";
1511 return log<
software_error,-1>({__FILE__, __LINE__,
"tried to move axis 3 but we don't have that"});
1516 if(absPos < m_min3 || absPos >
m_max3)
1523 std::string com =
"MOV 3 " + std::to_string(absPos) +
"\n";
1540 if (
ipRecv.createUniqueKey() == m_indiP_pos1.createUniqueKey())
1542 float current = -999999, target = -999999;
1544 if(
ipRecv.find(
"current"))
1546 current =
ipRecv[
"current"].get<
float>();
1549 if(
ipRecv.find(
"target"))
1551 target =
ipRecv[
"target"].get<
float>();
1554 if(target == -999999) target = current;
1556 if(target == -999999)
return 0;
1561 std::unique_lock<std::mutex> lock(m_indiMutex);
1565 updateFlat(target, m_pos2, m_pos3);
1567 return move_1(target);
1571 return updateFlat(target, m_pos2, m_pos3);
1582 if (
ipRecv.createUniqueKey() == m_indiP_pos2.createUniqueKey())
1584 float current = -999999, target = -999999;
1586 if(
ipRecv.find(
"current"))
1588 current =
ipRecv[
"current"].get<
float>();
1591 if(
ipRecv.find(
"target"))
1593 target =
ipRecv[
"target"].get<
float>();
1596 std::cerr << current <<
" " << target <<
"\n";
1598 if(target == -999999) target = current;
1600 if(target == -999999)
return 0;
1605 std::unique_lock<std::mutex> lock(m_indiMutex);
1608 updateFlat(m_pos1, target, m_pos3);
1609 return move_2(target);
1613 return updateFlat(m_pos1, target, m_pos3);
1624 if (
ipRecv.getName() == m_indiP_pos3.getName())
1626 float current = -999999, target = -999999;
1628 if(
ipRecv.find(
"current"))
1630 current =
ipRecv[
"current"].get<
float>();
1633 if(
ipRecv.find(
"target"))
1635 target =
ipRecv[
"target"].get<
float>();
1638 if(target == -999999) target = current;
1640 if(target == -999999)
return 0;
1645 std::unique_lock<std::mutex> lock(m_indiMutex);
1649 updateFlat(m_pos1, m_pos2, target);
1650 return move_3(target);
1654 return updateFlat(m_pos1, m_pos2, target);
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.
bool m_powerMgtEnabled
Flag controls whether power mgt is used. Set this in the constructor of a derived app....
void setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
std::string m_calibRelDir
The directory relative to the calibPath. Set this before calling dm<derivedT,realT>::loadConfig().
void loadConfig(mx::app::appConfigurator &config)
load the configuration system results
int appShutdown()
DM shutdown.
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.
int appStartup()
Startup function.
int appLogic()
DM application logic.
int appStartup()
Startup function.
int appLogic()
Checks the shmimMonitor thread.
int appShutdown()
Shuts down the shmimMonitor thread.
virtual int appShutdown()
Shutdown the app.
INDI_NEWCALLBACK_DECL(pi335Ctrl, m_indiP_pos2)
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.
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)
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 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.
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)
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 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.
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.
const pcf::IndiProperty & ipRecv
INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_windspeed)(const pcf
constexpr static logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
constexpr static logPrioT LOG_ERROR
An error has occured which the software will attempt to correct.
constexpr static logPrioT LOG_NOTICE
A normal but significant condition.
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].
Software CRITICAL log entry.
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