10 #include "../../libMagAOX/libMagAOX.hpp"
11 #include "../../magaox_git_version.h"
13 #include "tmcController.hpp"
34 template<
class parentT>
43 const std::string &
msg,
45 const std::string & file,
49 std::stringstream logs;
50 logs << src <<
": " <<
msg <<
" [ libftdi1: " << ftdi_get_error_string(m_ftdi) <<
" ] ";
52 parentT::template log<software_error>({file.c_str(), ln, 0, rv, logs.str()});
59 const std::string &
msg,
60 const std::string & file,
65 parentT::template log<software_error>({file.c_str(), ln, src +
": " +
msg});
202 config.add(
"axis1.serial",
"",
"axis1.serial", argType::Required,
"axis1",
"serial",
false,
"string",
"USB serial number");
203 config.add(
"axis2.serial",
"",
"axis2.serial", argType::Required,
"axis2",
"serial",
false,
"string",
"USB serial number");
208 std::string ser =
m_kAxis1.serial();
209 _config(ser,
"axis1.serial");
213 _config(ser,
"axis2.serial");
229 log<software_error>({__FILE__,__LINE__ - 2});
236 log<software_error>({__FILE__,__LINE__ - 2});
240 createStandardIndiNumber<float>(
m_indiP_axis1_voltage,
"axis1_voltage", 0, 150, 1.0/32767,
"%0.4f");
243 log<software_error>({__FILE__,__LINE__ - 2});
252 log<software_error>({__FILE__,__LINE__ - 2});
259 log<software_error>({__FILE__,__LINE__ - 2});
266 log<software_error>({__FILE__,__LINE__ - 2});
275 log<software_error>({__FILE__,__LINE__ - 2});
290 elevatedPrivileges elPriv(
this);
296 elevatedPrivileges elPriv(
this);
300 if(rv1 == 0 && rv2 == 0)
304 std::stringstream logs1;
305 logs1 <<
"Axis-1 USB Device " <<
m_kAxis1.vendor() <<
":" <<
m_kAxis1.product() <<
":";
306 logs1 <<
m_kAxis1.serial() <<
" found";
307 log<text_log>(logs1.str());
309 std::stringstream logs2;
310 logs2 <<
"Axis-2 USB Device " <<
m_kAxis2.vendor() <<
":" <<
m_kAxis2.product() <<
":";
311 logs2 <<
m_kAxis2.serial() <<
" found";
312 log<text_log>(logs2.str());
317 else if(rv1 == -3 && rv2 == -3)
328 std::stringstream logs1;
329 logs1 <<
"Axis-1 USB Device " <<
m_kAxis1.vendor() <<
":" <<
m_kAxis1.product() <<
":";
330 logs1 <<
m_kAxis1.serial() <<
" found";
331 log<text_log>(logs1.str());
337 log<software_error>({__FILE__, __LINE__, 0, rv1,
"axis1 tmcController::open failed. "});
344 std::stringstream logs2;
345 logs2 <<
"Axis-2 USB Device " <<
m_kAxis2.vendor() <<
":" <<
m_kAxis2.product() <<
":";
346 logs2 <<
m_kAxis2.serial() <<
" found";
347 log<text_log>(logs2.str());
353 log<software_error>({__FILE__, __LINE__, 0, rv1,
"axis 2 tmcController::open failed. "});
367 elevatedPrivileges elPriv(
this);
377 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis1 tmcController::connect failed. "});
378 std::cerr <<
"tmcController::connectFailed\n";
384 elevatedPrivileges elPriv(
this);
394 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis 2 tmcController::connect failed. "});
409 return log<
software_error, -1>({__FILE__,__LINE__,
"error during axis 1 initialization"});
414 return log<
software_error, -1>({__FILE__,__LINE__,
"error during axis 2 initialization"});
427 if(!
lock.owns_lock())
return 0;
430 int rv =
m_kAxis1.pz_req_outputvolts(ov);
436 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis1 tmcController::pz_req_outputvolts failed. "});
459 if(!
lock.owns_lock())
return 0;
462 int rv =
m_kAxis2.pz_req_outputvolts(ov);
468 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis1 tmcController::pz_req_outputvolts failed. "});
489 if(!
lock.owns_lock())
return 0;
545 tmcController::HWInfo hwi;
553 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis1 tmcController::hw_req_info failed. "});
557 std::stringstream logs1;
560 log<text_log>(logs1.str());
562 rv =
m_kAxis1.mod_set_chanenablestate(0x01, tmcController::EnableState::disabled);
568 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis1 tmcController::mod_set_chanenablestate failed. "});
581 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis1 tmcController::hw_stop_updatemsgs failed. "});
585 tmcController::KMMIParams par;
586 rv =
m_kAxis1.kpz_req_kcubemmiparams(par);
592 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis1 tmcController::kpz_req_kcubemmiparams failed. "});
596 par.DispBrightness = 0;
598 rv =
m_kAxis1.kpz_set_kcubemmiparams(par);
604 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis1 tmcController::kpz_set_kcubemmiparams failed. "});
608 rv =
m_kAxis1.kpz_req_kcubemmiparams(par);
614 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis1 tmcController::kpz_req_kcubemmiparams failed. "});
621 log<text_log>(logs1.str());
625 tmcController::TPZIOSettings tios;
626 rv =
m_kAxis1.pz_req_tpz_iosettings(tios);
632 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis1 tmcController::pz_req_tpz_iosettings failed. "});
635 tios.VoltageLimit = tmcController::VoltLimit::V150;
637 rv =
m_kAxis1.pz_set_tpz_iosettings(tios);
643 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis1 tmcController::pz_set_tpz_iosettings failed. "});
647 rv =
m_kAxis1.pz_req_tpz_iosettings(tios);
653 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis1 tmcController::pz_req_tpz_iosettings failed. "});
660 log<text_log>(logs1.str());
667 int rv =
m_kAxis1.mod_set_chanenablestate(0x01, tmcController::EnableState::enabled);
673 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis1 tmcController::mod_set_chanenablestate failed. "});
686 int rv =
m_kAxis1.mod_set_chanenablestate(0x01, tmcController::EnableState::disabled);
692 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis1 tmcController::mod_set_chanenablestate failed. "});
713 log<text_log>(
"axis 1 voltage clamped at 150 (" + std::to_string(v) +
")",
logPrio::LOG_WARNING);
717 int rv =
m_kAxis1.pz_set_outputvolts(v/150.0);
723 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis1 tmcController::pz_set_outputvolts failed. "});
735 tmcController::HWInfo hwi;
743 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis 2 tmcController::hw_req_info failed. "});
747 std::stringstream logs1;
750 log<text_log>(logs1.str());
752 rv =
m_kAxis2.mod_set_chanenablestate(0x01, tmcController::EnableState::disabled);
758 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis 2 tmcController::mod_set_chanenablestate failed. "});
771 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis 2 tmcController::hw_stop_updatemsgs failed. "});
775 tmcController::KMMIParams par;
776 rv =
m_kAxis2.kpz_req_kcubemmiparams(par);
782 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis 2 tmcController::kpz_req_kcubemmiparams failed. "});
786 par.DispBrightness = 0;
788 rv =
m_kAxis2.kpz_set_kcubemmiparams(par);
795 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis 2 tmcController::kpz_set_kcubemmiparams failed. "});
799 rv =
m_kAxis2.kpz_req_kcubemmiparams(par);
805 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis 2 tmcController::kpz_req_kcubemmiparams failed. "});
812 log<text_log>(logs1.str());
816 tmcController::TPZIOSettings tios;
817 rv =
m_kAxis2.pz_req_tpz_iosettings(tios);
823 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis 2 tmcController::pz_req_tpz_iosettings failed. "});
826 tios.VoltageLimit = tmcController::VoltLimit::V150;
828 rv =
m_kAxis2.pz_set_tpz_iosettings(tios);
834 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis 2 tmcController::pz_set_tpz_iosettings failed. "});
838 rv =
m_kAxis2.pz_req_tpz_iosettings(tios);
844 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis 2 tmcController::pz_req_tpz_iosettings failed. "});
851 log<text_log>(logs1.str());
858 int rv =
m_kAxis2.mod_set_chanenablestate(0x01, tmcController::EnableState::enabled);
864 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis 2 tmcController::mod_set_chanenablestate failed. "});
877 int rv =
m_kAxis2.mod_set_chanenablestate(0x01, tmcController::EnableState::disabled);
883 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis 2 tmcController::mod_set_chanenablestate failed. "});
904 log<text_log>(
"axis 2 voltage clamped at 150 (" + std::to_string(v) +
")",
logPrio::LOG_WARNING);
908 int rv =
m_kAxis2.pz_set_outputvolts(v/150.0);
914 log<software_error>({__FILE__, __LINE__, 0, rv,
"axis 2 tmcController::pz_set_outputvolts failed. "});
932 return log<
software_error,-1>({__FILE__, __LINE__,
"axis 1 enable error in set"});
940 return log<
software_error,-1>({__FILE__, __LINE__,
"axis 1 enable voltage in set"});
948 return log<
software_error,-1>({__FILE__, __LINE__,
"axis 2 enable error in set"});
956 return log<
software_error,-1>({__FILE__, __LINE__,
"axis 2 enable voltage in set"});
977 return log<
software_error,-1>({__FILE__, __LINE__,
"axis 1 enable voltage in rest"});
985 return log<
software_error,-1>({__FILE__, __LINE__,
"axis 1 disable error in rest"});
993 return log<
software_error,-1>({__FILE__, __LINE__,
"axis 2 enable voltage in rest"});
1001 return log<
software_error,-1>({__FILE__, __LINE__,
"axis 2 disable error in rest"});
1018 if(
ipRecv[
"request"].getSwitchState() == pcf::IndiElement::On)
1020 std::lock_guard<std::mutex> guard(m_indiMutex);
1022 return m_kAxis1.mod_identify();
1035 if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::On)
1037 std::lock_guard<std::mutex> guard(m_indiMutex);
1038 if(axis1Enable() < 0)
1040 if(m_powerState == 0)
return 0;
1041 return log<
software_error,-1>({__FILE__, __LINE__,
"axis 1 enable error in INDI callback"});
1046 std::lock_guard<std::mutex> guard(m_indiMutex);
1047 if(axis1Disable() < 0)
1049 if(m_powerState == 0)
return 0;
1050 log<
software_error,-1>({__FILE__, __LINE__,
"axis 1 disable error in INDI callback"});
1065 indiTargetUpdate(m_indiP_axis1_voltage, target,
ipRecv,
true);
1067 std::lock_guard<std::mutex> guard(m_indiMutex);
1068 if(axis1Voltage(target) < 0)
1070 if(m_powerState == 0)
return 0;
1071 return log<
software_error,-1>({__FILE__, __LINE__,
"axis 1 voltage error in INDI callback"});
1084 if(
ipRecv[
"request"].getSwitchState() == pcf::IndiElement::On)
1086 std::lock_guard<std::mutex> guard(m_indiMutex);
1088 return m_kAxis2.mod_identify();
1101 if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::On)
1103 std::lock_guard<std::mutex> guard(m_indiMutex);
1104 if(axis2Enable() < 0)
1106 if(m_powerState == 0)
return 0;
1107 return log<
software_error,-1>({__FILE__, __LINE__,
"axis 2 enable error in INDI callback"});
1112 std::lock_guard<std::mutex> guard(m_indiMutex);
1113 if(axis2Disable() < 0)
1115 if(m_powerState == 0)
return 0;
1116 return log<
software_error,-1>({__FILE__, __LINE__,
"axis 2 disable error in INDI callback"});
1130 indiTargetUpdate(m_indiP_axis2_voltage, target,
ipRecv,
true);
1132 std::lock_guard<std::mutex> guard(m_indiMutex);
1133 if(axis2Voltage(target) < 0)
1135 if(m_powerState == 0)
return 0;
1136 return log<
software_error,-1>({__FILE__, __LINE__,
"axis 2 voltage error in INDI callback"});
1149 if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::On)
1151 std::lock_guard<std::mutex> guard(m_indiMutex);
1161 if(m_powerState == 0)
return 0;
1162 return log<
software_error,-1>({__FILE__, __LINE__,
"set error in INDI callback"});
1167 std::lock_guard<std::mutex> guard(m_indiMutex);
1177 if(m_powerState == 0)
return 0;
1178 return log<
software_error,-1>({__FILE__, __LINE__,
"rest error in INDI callback"});
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.
int createStandardIndiRequestSw(pcf::IndiProperty &prop, const std::string &name, const std::string &label="", const std::string &group="")
Create a standard R/W INDI switch with a single request element.
stateCodes::stateCodeT state()
Get the current state code.
int registerIndiPropertyNew(pcf::IndiProperty &prop, int(*)(void *, const pcf::IndiProperty &))
Register an INDI property which is exposed for others to request a New Property for.
int createStandardIndiToggleSw(pcf::IndiProperty &prop, const std::string &name, const std::string &label="", const std::string &group="")
Create a standard R/W INDI switch with a single toggle element.
int m_powerState
Current power state, 1=On, 0=Off, -1=Unk.
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.
std::mutex m_indiMutex
Mutex for locking INDI communications.
The MagAO-X K-Cube Controller.
kcubeCtrl()
Default c'tor.
pcf::IndiProperty m_indiP_axis2_identify
INDI_NEWCALLBACK_DECL(kcubeCtrl, m_indiP_axis1_enable)
virtual int appShutdown()
Shutdown the app.
pcf::IndiProperty m_indiP_axis1_enable
pcf::IndiProperty m_indiP_axis2_voltage
virtual int appStartup()
Startup function.
INDI_NEWCALLBACK_DECL(kcubeCtrl, m_indiP_axis2_enable)
tmcCon< kcubeCtrl > m_kAxis2
virtual void setupConfig()
INDI_NEWCALLBACK_DECL(kcubeCtrl, m_indiP_axis1_voltage)
~kcubeCtrl() noexcept
D'tor, declared and defined for noexcept.
pcf::IndiProperty m_indiP_axis2_enable
INDI_NEWCALLBACK_DECL(kcubeCtrl, m_indiP_set)
pcf::IndiProperty m_indiP_axis1_voltage
tmcCon< kcubeCtrl > m_kAxis1
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
INDI_NEWCALLBACK_DECL(kcubeCtrl, m_indiP_axis2_voltage)
INDI_NEWCALLBACK_DECL(kcubeCtrl, m_indiP_axis2_identify)
int axis1Voltage(float &v)
pcf::IndiProperty m_indiP_set
friend class kcubeCtrl_test
pcf::IndiProperty m_indiP_axis1_identify
virtual int appLogic()
Implementation of the FSM for kcubeCtrl.
virtual void loadConfig()
INDI_NEWCALLBACK_DECL(kcubeCtrl, m_indiP_axis1_identify)
int axis2Voltage(float &v)
Local derivation of tmcController to implement MagAO-X logging.
virtual void otherErrmsg(const std::string &src, const std::string &msg, const std::string &file, int line)
Print a message to MagAO-X logs describing an error.
virtual void ftdiErrmsg(const std::string &src, const std::string &msg, int rv, const std::string &file, int line)
Print a message to MagAO-X logs describing an error from an \libftdi1 function.
#define INDI_NEWCALLBACK(prop)
Get the name of the static callback wrapper for a new property.
@ OPERATING
The device is operating, other than homing.
@ NODEVICE
No device exists for the application to control.
@ 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.
@ NOTCONNECTED
The application is not connected to the device or service.
@ POWERON
The device power is on.
void updateSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, const pcf::IndiElement::SwitchStateType &newVal, indiDriverT *indiDriver, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update the value of the INDI element, but only if it has changed.
INDI_VALIDATE_CALLBACK_PROPS(function, ipRecv)
const pcf::IndiProperty & ipRecv
INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_windspeed)(const pcf
std::unique_lock< std::mutex > lock(m_indiMutex)
constexpr static logPrioT LOG_WARNING
A condition has occurred which may become an error, but the process continues.
constexpr static logPrioT LOG_NOTICE
A normal but significant condition.