7 #ifndef zaberLowLevel_hpp
8 #define zaberLowLevel_hpp
13 #include "../../libMagAOX/libMagAOX.hpp"
14 #include "../../magaox_git_version.h"
22 #define ZC_CONNECTED (0)
24 #define ZC_NOT_CONNECTED (10)
57 std::vector<zaberStage<zaberLowLevel>>
m_stages;
160 std::vector<std::string> sections;
162 config.unusedSections(sections);
164 if(sections.size() == 0)
166 log<software_error>({__FILE__, __LINE__,
"No stages found"});
170 for(
size_t n=0; n<sections.size(); ++n)
172 if(config.isSetUnused(mx::app::iniFile::makeKey(sections[n],
"serial" )))
182 std::string tmp =
m_stages[idx].serial();
183 config.configUnused( tmp , mx::app::iniFile::makeKey(sections[n],
"serial" ) );
211 elevatedPrivileges elPriv(
this);
225 log<software_error>({__FILE__, __LINE__,
"can not connect to zaber stage(s)"});
245 log<software_error>({__FILE__,__LINE__, rv,
"error from za_drain"});
270 log<software_error>({__FILE__,__LINE__, rv,
"error from za_drain"});
286 std::string serialRes;
314 std::vector<int> addresses;
315 std::vector<std::string> serials;
320 log<software_error>({__FILE__, __LINE__, errno, rv,
"error in parseSystemSerial"});
326 log<text_log>(
"Found " + std::to_string(addresses.size()) +
" stages.");
328 for(
size_t n=0;n<addresses.size(); ++n)
335 log<text_log>(
"stage @" + std::to_string(addresses[n]) +
" with s/n " + serials[n] +
" corresponds to " +
m_stages[
m_stageSerial[serials[n]]].name());
339 log<text_log>(
"Unkown stage @" + std::to_string(addresses[n]) +
" with s/n " + serials[n],
logPrio::LOG_WARNING);
343 for(
size_t n=0; n <
m_stages.size(); ++n)
372 for(
size_t n=0; n<
m_stages.size(); ++n)
378 for(
size_t n=0; n<
m_stages.size(); ++n)
385 for(
size_t n=0; n<
m_stages.size(); ++n)
391 for(
size_t n=0; n<
m_stages.size(); ++n)
397 for(
size_t n=0; n<
m_stages.size(); ++n)
404 for(
size_t n=0; n<
m_stages.size(); ++n)
411 for(
size_t n=0; n<
m_stages.size(); ++n)
418 for(
size_t n=0; n<
m_stages.size(); ++n)
425 for(
size_t n=0; n<
m_stages.size(); ++n)
444 for(
size_t i=0; i <
m_stages.size();++i)
471 std::stringstream logs;
473 log<text_log>(logs.str());
479 std::stringstream logs;
481 log<text_log>(logs.str());
485 for(
size_t i=0; i <
m_stages.size();++i)
487 if(
m_stages[i].deviceAddress() < 1)
continue;
505 for(
size_t i=0; i <
m_stages.size();++i)
507 if(
m_stages[i].deviceAddress() < 1)
continue;
513 log<text_log>(
"Connected to stage(s) on " +
m_deviceName);
528 for(
size_t i=0; i <
m_stages.size();++i)
545 log<software_error>({__FILE__, __LINE__});
560 for(
size_t i=0; i <
m_stages.size();++i)
562 if(
m_stages[i].deviceAddress() < 1)
continue;
580 if(
m_stages[i].deviceStatus() ==
'B')
591 else if(
m_stages[i].deviceStatus() ==
'I')
595 std::cerr << __FILE__ <<
" " << __LINE__ <<
"\n";
615 log<software_error>({__FILE__, __LINE__});
630 for(
size_t i=0; i <
m_stages.size();++i)
645 for(
size_t i=0; i <
m_stages.size();++i)
652 std::stringstream logs;
654 log<text_log>(logs.str());
661 for(
size_t i=0; i <
m_stages.size();++i)
666 log<software_critical>({__FILE__, __LINE__});
667 log<text_log>(
"Error NOT due to loss of USB connection. I can't fix it myself.",
logPrio::LOG_CRITICAL);
696 for(
size_t i=0; i <
m_stages.size();++i)
720 for(
size_t i=0; i <
m_stages.size();++i)
722 if(
m_stages[i].deviceAddress() < 1)
continue;
733 for(
size_t n=0; n < m_stages.size(); ++n)
735 if(
ipRecv.find(m_stages[n].name()) )
737 long tgt =
ipRecv[m_stages[n].name()].get<
long>();
740 if(m_stages[n].deviceAddress() < 1)
742 return log<
software_error,-1>({__FILE__, __LINE__,
"stage " + m_stages[n].name() +
" with with s/n " + m_stages[n].serial() +
" not found in system."});
745 std::lock_guard<std::mutex> guard(m_indiMutex);
746 updateIfChanged(m_indiP_curr_state, m_stages[n].name(), std::string(
"OPERATING"));
747 return m_stages[n].moveAbs(m_port, tgt);
759 for(
size_t n=0; n < m_stages.size(); ++n)
761 if(
ipRecv.find(m_stages[n].name()) )
763 long tgt =
ipRecv[m_stages[n].name()].get<
long>();
764 tgt += m_stages[n].rawPos();
767 if(m_stages[n].deviceAddress() < 1)
769 return log<
software_error,-1>({__FILE__, __LINE__,
"stage " + m_stages[n].name() +
" with with s/n " + m_stages[n].serial() +
" not found in system."});
771 std::lock_guard<std::mutex> guard(m_indiMutex);
773 updateIfChanged(m_indiP_curr_state, m_stages[n].name(), std::string(
"OPERATING"));
774 return m_stages[n].moveAbs(m_port, tgt);
786 for(
size_t n=0; n < m_stages.size(); ++n)
788 if(
ipRecv.find(m_stages[n].name()) )
790 int tgt =
ipRecv[m_stages[n].name()].get<
int>();
793 if(m_stages[n].deviceAddress() < 1)
795 return log<
software_error,-1>({__FILE__, __LINE__,
"stage " + m_stages[n].name() +
" with with s/n " + m_stages[n].serial() +
" not found in system."});
797 std::lock_guard<std::mutex> guard(m_indiMutex);
798 return m_stages[n].home(m_port);
811 for(
size_t n=0; n < m_stages.size(); ++n)
813 if(
ipRecv.find(m_stages[n].name()) )
815 int tgt =
ipRecv[m_stages[n].name()].get<
int>();
818 if(m_stages[n].deviceAddress() < 1)
820 return log<
software_error,-1>({__FILE__, __LINE__,
"stage " + m_stages[n].name() +
" with with s/n " + m_stages[n].serial() +
" not found in system."});
823 std::lock_guard<std::mutex> guard(m_indiMutex);
824 return m_stages[n].stop(m_port);
836 for(
size_t n=0; n < m_stages.size(); ++n)
838 if(
ipRecv.find(m_stages[n].name()) )
840 int tgt =
ipRecv[m_stages[n].name()].get<
int>();
843 if(m_stages[n].deviceAddress() < 1)
845 return log<
software_error,-1>({__FILE__, __LINE__,
"stage " + m_stages[n].name() +
" with with s/n " + m_stages[n].serial() +
" not found in system."});
848 std::lock_guard<std::mutex> guard(m_indiMutex);
849 return m_stages[n].estop(m_port);
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 powerState()
Returns the current power state.
int powerStateTarget()
Returns the target power state.
int stateLogged()
Updates and returns the value of m_stateLogged. Will be 0 on first call after a state change,...
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....
zaberLowLevel()
Default c'tor.
INDI_NEWCALLBACK_DECL(zaberLowLevel, m_indiP_req_ehalt)
friend class zaberLowLevel_test
pcf::IndiProperty m_indiP_req_home
Command a stage to home.
INDI_NEWCALLBACK_DECL(zaberLowLevel, m_indiP_req_halt)
virtual int appLogic()
Implementation of the FSM for zaberLowLevel.
pcf::IndiProperty m_indiP_max_pos
Maximum raw position of the stage.
pcf::IndiProperty m_indiP_req_halt
Command a stage to safely halt.
virtual int onPowerOff()
Implementation of the on-power-off FSM logic.
pcf::IndiProperty m_indiP_tgt_pos
Target raw position of the stage.
pcf::IndiProperty m_indiP_temp
Current temperature of the stage.
std::unordered_map< std::string, size_t > m_stageSerial
INDI_NEWCALLBACK_DECL(zaberLowLevel, m_indiP_tgt_relpos)
std::unordered_map< int, size_t > m_stageAddress
pcf::IndiProperty m_indiP_curr_state
Current state of the stage.
int loadStages(std::string &serialRes)
virtual int whilePowerOff()
Implementation of the while-powered-off FSM.
virtual void loadConfig()
pcf::IndiProperty m_indiP_curr_pos
Current raw position of the stage.
INDI_NEWCALLBACK_DECL(zaberLowLevel, m_indiP_tgt_pos)
virtual int appStartup()
Startup functions.
virtual int appShutdown()
Do any needed shutdown tasks. Currently nothing in this app.
std::vector< zaberStage< zaberLowLevel > > m_stages
pcf::IndiProperty m_indiP_tgt_relpos
Target relative position of the stage.
~zaberLowLevel() noexcept
D'tor, declared and defined for noexcept.
std::unordered_map< std::string, size_t > m_stageName
INDI_NEWCALLBACK_DECL(zaberLowLevel, m_indiP_req_home)
pcf::IndiProperty m_indiP_req_ehalt
Command a stage to safely immediately halt.
virtual void setupConfig()
A class to manage the details of one stage in a Zaber system.
#define REG_INDI_NEWPROP_NOCB(prop, propName, type)
Register a NEW INDI property with the class, with no callback.
#define REG_INDI_NEWPROP(prop, propName, type)
Register a NEW INDI property with the class, using the standard callback name.
@ NODEVICE
No device exists for the application to control.
@ 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.
std::string ttyErrorString(int ec)
Get a text explanation of a TTY_E_ error code.
int parseSystemSerial(std::vector< int > &address, std::vector< std::string > &serial, const std::string &response)
Parse the system.serial query.
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_VALIDATE_CALLBACK_PROPS(function, ipRecv)
INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_windspeed)(const pcf
constexpr static logPrioT LOG_DEBUG
Used for debugging.
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_WARNING
A condition has occurred which may become an error, but the process continues.
A USB device as a TTY device.
std::string m_deviceName
The device path name, e.g. /dev/ttyUSB0.
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
int za_connect(z_port *port, const char *port_name)
int za_receive(z_port port, char *destination, int length)
int za_send(z_port port, const char *command)
int za_drain(z_port port)
int za_disconnect(z_port port)
Provides a set of functions for interacting with Zaber devices in the ASCII protocol.
MagAOX::app::MagAOXApp< true > MagAOXAppT
A class with details of a single zaber stage.
utilties for working with zaber stages