11 #ifndef app_MagAOXApp_hpp
12 #define app_MagAOXApp_hpp
16 #include <sys/syscall.h>
24 #include <unordered_map>
26 #include <mx/mxlib.hpp>
27 #include <mx/app/application.hpp>
28 #include <mx/sys/environment.hpp>
29 #include <mx/sys/timeUtils.hpp>
30 #include <mx/ioutils/fileUtils.hpp>
33 #include "../common/environment.hpp"
34 #include "../common/paths.hpp"
35 #include "../common/defaults.hpp"
36 #include "../common/config.hpp"
38 #include "../logger/logFileRaw.hpp"
39 #include "../logger/logManager.hpp"
41 #include "../sys/thSetuid.hpp"
49 using namespace mx::app;
73 template<
bool _useINDI = true >
77 friend class MagAOXApp_test;
127 const bool git_modified
146 virtual
void setDefaults(
int argc,
158 virtual
void setupBasicConfig();
168 virtual
void loadBasicConfig();
174 virtual
void checkConfig();
204 virtual
int execute();
218 virtual
int appStartup() = 0;
229 virtual
int appLogic() = 0;
234 virtual
int appShutdown() = 0;
251 template<typename logT,
int retval=0>
252 static
int log( const typename logT::messageT &
msg,
263 template<typename logT,
int retval=0>
278 static
void configLog( const std::
string & name,
280 const std::
string &
value,
281 const std::
string & source
294 int setSigTermHandler();
297 static
void _handlerSigTerm(
int signum,
303 void handlerSigTerm(
int signum,
328 bool m_elevated {
false};
339 if(m_elevated)
return;
347 if(!m_elevated)
return;
449 template<
class thisPtr,
class Function>
453 pcf::IndiProperty & thProp,
455 const std::string & cpuset,
456 const std::string & thrdName,
470 bool m_stateAlert {
false};
472 bool m_gitAlert {
false};
474 int m_stateLogged {0} ;
489 bool stateAlert =
false
532 constexpr
static bool m_useINDI = _useINDI;
546 pcf::IndiProperty *
property {0};
547 int (*callBack)(
void *,
const pcf::IndiProperty &) {0};
548 bool m_defReceived {
false};
576 bool m_allDefsReceived {
false};
597 const std::string & propName,
598 const std::string & label =
"",
599 const std::string & group =
""
608 const std::string & propName,
609 const std::string & elName,
610 const std::string & propLabel =
"",
611 const std::string & propGroup =
"",
612 const std::string & elLabel =
""
622 const std::string & name,
626 const std::string & format,
627 const std::string & label =
"",
628 const std::string & group =
""
637 const std::string & propName,
638 const std::string & propLabel =
"",
639 const std::string & propGroup =
""
649 const std::string & name,
650 const std::string & label =
"",
651 const std::string & group =
""
661 const std::string & name,
662 const std::string & label =
"",
663 const std::string & group =
""
673 const std::string & name,
674 const std::vector<std::string> & elements,
675 const std::vector<std::string> & elementLabels,
676 const std::string & label =
"",
677 const std::string & group =
""
687 const std::string & name,
688 const std::vector<std::string> & elements,
689 const std::string & label =
"",
690 const std::string & group =
""
710 const std::string & propName,
711 const pcf::IndiProperty::Type &
propType,
712 const pcf::IndiProperty::PropertyPermType & propPerm,
713 const pcf::IndiProperty::PropertyStateType & propState
724 int (*)(
void *,
const pcf::IndiProperty &)
735 const std::string & propName,
736 const pcf::IndiProperty::Type &
propType,
737 const pcf::IndiProperty::PropertyPermType & propPerm,
738 const pcf::IndiProperty::PropertyStateType & propState,
739 int (*)(
void *,
const pcf::IndiProperty &)
750 const std::string & propName,
751 const pcf::IndiProperty::Type &
propType,
752 const pcf::IndiProperty::PropertyPermType & propPerm,
753 const pcf::IndiProperty::PropertyStateType & propState,
754 const pcf::IndiProperty::SwitchRuleType & propRule,
755 int (*)(
void *,
const pcf::IndiProperty &)
766 const std::string & devName,
767 const std::string & propName,
768 int (*)(
void *,
const pcf::IndiProperty &)
833 const std::string & el,
835 pcf::IndiProperty::PropertyStateType ipState = pcf::IndiProperty::Ok
851 const std::string & el,
853 pcf::IndiProperty::PropertyStateType ipState = pcf::IndiProperty::Ok
862 const std::string & el,
863 const pcf::IndiElement::SwitchStateType & newVal,
864 pcf::IndiProperty::PropertyStateType ipState = pcf::IndiProperty::Ok
881 const std::string & el,
882 const std::vector<T> & newVals,
883 pcf::IndiProperty::PropertyStateType ipState = pcf::IndiProperty::Ok
898 const std::vector<std::string> & els,
899 const std::vector<T> & newVals
910 const pcf::IndiProperty & remoteProperty,
922 const std::string & el,
939 const std::string & property,
956 const pcf::IndiProperty &
ipRecv
981 bool m_powerMgtEnabled {
false};
986 std::string m_powerElement {
"state"};
987 std::string m_powerTargetElement {
"target"};
989 unsigned long m_powerOnWait {0};
992 int m_powerOnCounter {-1};
995 int m_powerState {-1};
996 int m_powerTargetState {-1};
1093 template<
bool _useINDI>
1095 const bool git_modified
1098 if( m_self !=
nullptr )
1100 std::cerr <<
"Attempt to instantiate 2nd MagAOXApp. Exiting immediately.\n";
1107 getresuid(&m_euidReal, &m_euidCalled, &m_suid);
1113 config.m_sources =
true;
1114 config.configLog = configLog;
1126 if(MXLIB_UNCOMP_REPO_MODIFIED)
1132 log<git_state>(
git_state::messageT(
"mxlib", MXLIB_UNCOMP_CURRENT_SHA1, MXLIB_UNCOMP_REPO_MODIFIED), gl);
1136 template<
bool _useINDI>
1139 if(m_indiDriver)
delete m_indiDriver;
1140 m_log.parent(
nullptr);
1145 template<
bool _useINDI>
1151 template<
bool _useINDI>
1161 MagAOXPath = tmpstr;
1174 m_configDir = MagAOXPath +
"/" + tmpstr;
1175 m_configPathGlobal = m_configDir +
"/magaox.conf";
1183 m_calibDir = MagAOXPath +
"/" + tmpstr;
1190 m_log.logPath(tmpstr);
1198 secretsPath = tmpstr;
1204 m_cpusetPath = tmpstr;
1209 if(m_configBase !=
"")
1212 m_configPathUser = m_configDir +
"/" + m_configBase +
".conf";
1216 config.add(
"name",
"n",
"name",argType::Required,
"",
"name",
false,
"string",
"The name of the application, specifies config.");
1218 config.parseCommandLine(argc, argv,
"name");
1219 config(m_configName,
"name");
1221 if(m_configName ==
"")
1223 m_configName = mx::ioutils::pathStem(invokedName);
1224 log<text_log>(
"Application name (-n --name) not set. Using argv[0].");
1228 m_configPathLocal = m_configDir +
"/" + m_configName +
".conf";
1231 if( registerIndiPropertyNew( m_indiP_state,
"fsm", pcf::IndiProperty::Text, pcf::IndiProperty::ReadOnly, pcf::IndiProperty::Idle, 0) < 0)
1233 log<software_error>({__FILE__,__LINE__,
"failed to register read only fsm_state property"});
1236 m_indiP_state.add (pcf::IndiElement(
"state"));
1238 createStandardIndiRequestSw( m_indiP_clearFSMAlert,
"fsm_clear_alert",
"Clear FSM Alert",
"FSM");
1239 if(registerIndiPropertyNew(m_indiP_clearFSMAlert, st_newCallBack_clearFSMAlert) < 0)
1241 log<software_error>({__FILE__,__LINE__,
"failed to register new fsm_alert property"});
1248 template<
bool _useINDI>
1252 config.add(
"loopPause",
"p",
"loopPause", argType::Required,
"",
"loopPause",
false,
"unsigned long",
"The main loop pause time in ns");
1254 config.add(
"ignore_git",
"",
"ignore-git", argType::True,
"",
"",
false,
"bool",
"set to true to ignore git status");
1257 m_log.setupConfig(config);
1259 if( m_powerMgtEnabled)
1261 if(_useINDI ==
false)
1264 log<software_critical>({__FILE__,__LINE__,
"power management is enabled but we are not using INDI"});
1269 config.add(
"power.device",
"",
"power.device", argType::Required,
"power",
"device",
false,
"string",
"Device controlling power for this app's device (INDI name).");
1270 config.add(
"power.channel",
"",
"power.channel", argType::Required,
"power",
"channel",
false,
"string",
"Channel on device for this app's device (INDI name).");
1271 config.add(
"power.element",
"",
"power.element", argType::Required,
"power",
"element",
false,
"string",
"INDI power state element name. Default is \"state\", only need to specify if different.");
1272 config.add(
"power.targetElement",
"",
"power.targetElement", argType::Required,
"power",
"targetElement",
false,
"string",
"INDI power target element name. Default is \"target\", only need to specify if different.");
1273 config.add(
"power.powerOnWait",
"",
"power.powerOnWait", argType::Required,
"power",
"powerOnWait",
false,
"int",
"Time after power-on to wait before continuing [sec]. Default is 0 sec, max is 3600 sec.");
1277 template<
bool _useINDI>
1281 config(ig,
"ignore_git");
1283 if(!ig && m_gitAlert)
1285 m_stateAlert =
true;
1289 m_log.logName(m_configName);
1290 m_log.loadConfig(config);
1293 config(m_loopPause,
"loopPause");
1296 if( m_powerMgtEnabled)
1298 config(m_powerDevice,
"power.device");
1299 config(m_powerChannel,
"power.channel");
1300 config(m_powerElement,
"power.element");
1301 config(m_powerTargetElement,
"power.targetElement");
1303 if(m_powerDevice !=
"" && m_powerChannel !=
"")
1305 log<text_log>(
"enabling power management: " + m_powerDevice +
"." + m_powerChannel +
"." + m_powerElement +
"/" + m_powerTargetElement);
1306 if( registerIndiPropertySet( m_indiP_powerChannel,m_powerDevice, m_powerChannel,
INDI_SETCALLBACK(m_indiP_powerChannel)) < 0)
1308 log<software_error>({__FILE__,__LINE__,
"failed to register set property"});
1317 config(m_powerOnWait,
"power.powerOnWait");
1318 if(m_powerOnWait > 3600)
1326 template<
bool _useINDI>
1331 for(
auto it = config.m_targets.begin();
it != config.m_targets.end(); ++
it )
1333 if(
it->second.used ==
false)
1335 std::string
msg =
it->second.name;
1336 if(config.m_sources &&
it->second.sources.size() > 0)
msg +=
" [" +
it->second.sources[0] +
"]";
1341 if(config.m_unusedConfigs.size() > 0)
1343 for(
auto it = config.m_unusedConfigs.begin();
it != config.m_unusedConfigs.end(); ++
it )
1345 if(
it->second.used ==
true)
continue;
1347 std::string
msg =
it->second.name;
1348 if(config.m_sources &&
it->second.sources.size() > 0 )
msg +=
" [" +
it->second.sources[0] +
"]";
1356 if(config.nonOptions.size() > 0)
1358 for(
size_t n =0; n < config.nonOptions.size(); ++n)
1360 log<text_log>(
"Unrecognized command line argument: " + config.nonOptions[n],
logPrio::LOG_CRITICAL);
1369 template<
bool _useINDI>
1375 #ifndef XWC_DISABLE_USER_CHECK
1376 struct stat logstat;
1378 if( stat(m_log.logPath().c_str(), &logstat) < 0)
1383 if( logstat.st_uid != geteuid() )
1394 state(stateCodes::FAILURE);
1403 m_log.logThreadStart();
1407 while(m_log.logThreadRunning() ==
false && w < 20)
1410 std::this_thread::sleep_for( std::chrono::duration<unsigned long, std::nano>(100000000));
1414 if(m_log.logThreadRunning() ==
false)
1417 std::cerr <<
"\nCRITICAL: log thread not running. Exiting.\n\n";
1426 setSigTermHandler();
1430 if( m_shutdown == 0 )
1432 state(stateCodes::INITIALIZED);
1433 if(appStartup() < 0) m_shutdown = 1;
1437 if(m_useINDI && m_shutdown == 0)
1441 state(stateCodes::FAILURE);
1447 if(m_powerMgtEnabled && m_shutdown == 0)
1450 while(m_powerState < 0 && !m_shutdown)
1453 if(m_powerState < 0)
1455 if(!stateLogged()) log<text_log>(
"waiting for power state");
1462 state(stateCodes::ERROR);
1466 if(m_powerState > 0)
1468 state(stateCodes::POWERON);
1472 m_powerOnCounter = 0;
1473 state(stateCodes::POWEROFF);
1474 if(onPowerOff() < 0)
1490 while( m_shutdown == 0)
1493 if(m_powerMgtEnabled)
1495 if(state() == stateCodes::POWEROFF)
1497 if(m_powerState == 1)
1499 m_powerOnCounter = 0;
1500 state(stateCodes::POWERON);
1505 if(m_powerState == 0)
1507 state(stateCodes::POWEROFF);
1508 if(onPowerOff() < 0)
1519 if( !m_powerMgtEnabled || m_powerState > 0 )
1527 else if(m_powerState == 0)
1529 if( whilePowerOff() < 0)
1545 sendGetPropertySetList(
false);
1553 if( m_shutdown == 0)
1555 std::this_thread::sleep_for( std::chrono::duration<unsigned long, std::nano>(m_loopPause));
1561 state(stateCodes::SHUTDOWN);
1564 if(m_indiDriver !=
nullptr)
1566 pcf::IndiProperty ipSend;
1567 ipSend.setDevice(m_configName);
1570 m_indiDriver->sendDelProperty(ipSend);
1572 catch(
const std::exception & e)
1574 log<software_error>({__FILE__, __LINE__, std::string(
"exception caught from sendDelProperty: ") + e.what()});
1577 m_indiDriver->quitProcess();
1578 m_indiDriver->deactivate();
1579 log<indidriver_stop>();
1588 template<
bool _useINDI>
1589 template<
typename logT,
int retval>
1594 m_log.template log<logT>(
msg, level);
1598 template<
bool _useINDI>
1599 template<
typename logT,
int retval>
1602 m_log.template log<logT>(level);
1606 template<
bool _useINDI>
1617 state(m_state,
true);
1620 if(_useINDI && m_indiDriver)
1622 pcf::IndiProperty
msg;
1623 msg.setDevice(m_configName);
1625 std::stringstream logstdf;
1626 logMinStdFormat(logstdf, b);
1628 msg.setMessage(logstdf.str());
1634 tv.tv_usec = (
long int) ( ((
double) ts.
time_ns)/1e3 );
1636 msg.setTimeStamp(pcf::TimeStamp(tv));
1640 m_indiDriver->sendMessage(
msg);
1642 catch(
const std::exception & e)
1644 log<software_error>({__FILE__, __LINE__, std::string(
"exception caught from sendMessage: ") + e.what()});
1649 template<
bool _useINDI>
1652 const std::string &
value,
1653 const std::string & source
1656 m_log.template log<config_log>({name, code,
value, source});
1659 template<
bool _useINDI>
1662 struct sigaction act;
1666 act.sa_flags = SA_SIGINFO;
1671 if( sigaction(SIGTERM, &act, 0) < 0 )
1673 std::string logss =
"Setting handler for SIGTERM failed. Errno says: ";
1674 logss += strerror(errno);
1676 log<software_error>({__FILE__, __LINE__, errno, 0, logss});
1682 if( sigaction(SIGQUIT, &act, 0) < 0 )
1684 std::string logss =
"Setting handler for SIGQUIT failed. Errno says: ";
1685 logss += strerror(errno);
1687 log<software_error>({__FILE__, __LINE__, errno, 0,logss});
1693 if( sigaction(SIGINT, &act, 0) < 0 )
1695 std::string logss =
"Setting handler for SIGINT failed. Errno says: ";
1696 logss += strerror(errno);
1698 log<software_error>({__FILE__, __LINE__, errno, 0, logss});
1703 log<text_log>(
"Installed SIGTERM/SIGQUIT/SIGINT signal handler.",
logPrio::LOG_DEBUG);
1708 template<
bool _useINDI>
1717 template<
bool _useINDI>
1719 siginfo_t *siginf __attribute__((unused)),
1720 void *ucont __attribute__((unused))
1725 std::string signame;
1729 signame =
"SIGTERM";
1735 signame =
"SIGQUIT";
1741 std::string logss =
"Caught signal ";
1743 logss +=
". Shutting down.";
1745 std::cerr <<
"\n" << logss << std::endl;
1746 log<text_log>(logss);
1756 template<
bool _useINDI>
1762 std::string logss =
"Setting effective user id to euidCalled (";
1763 logss += mx::ioutils::convertToString<int>(m_euidCalled);
1764 logss +=
") failed. Errno says: ";
1765 logss += strerror(errno);
1767 log<software_error>({__FILE__, __LINE__, errno, 0, logss});
1775 template<
bool _useINDI>
1781 std::string logss =
"Setting effective user id to euidReal (";
1782 logss += mx::ioutils::convertToString<int>(m_euidReal);
1783 logss +=
") failed. Errno says: ";
1784 logss += strerror(errno);
1786 log<software_error>({__FILE__, __LINE__, errno, 0, logss});
1795 template<
bool _useINDI>
1800 std::string statusDir = sysPath;
1807 if( mkdir(statusDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0 )
1809 if( errno != EEXIST)
1811 std::stringstream logss;
1812 logss <<
"Failed to create root of statusDir (" << statusDir <<
"). Errno says: " << strerror(errno);
1813 log<software_critical>({__FILE__, __LINE__, errno, 0, logss.str()});
1820 statusDir += m_configName;
1822 pidFileName = statusDir +
"/pid";
1826 if( mkdir(statusDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0 )
1828 if( errno != EEXIST)
1830 std::stringstream logss;
1831 logss <<
"Failed to create statusDir (" << statusDir <<
"). Errno says: " << strerror(errno);
1832 log<software_critical>({__FILE__, __LINE__, errno, 0, logss.str()});
1838 std::ifstream pidIn;
1839 pidIn.open( pidFileName );
1849 std::stringstream procN;
1850 procN <<
"/proc/" << testPid <<
"/cmdline";
1852 std::ifstream procIn;
1853 std::string pidCmdLine;
1857 procIn.open(procN.str());
1858 if(procIn.good()) procIn >> pidCmdLine;
1863 log<software_critical>({__FILE__, __LINE__, 0, 0,
"exception caught testing /proc/pid"});
1871 size_t invokedPos = pidCmdLine.find( invokedName );
1874 size_t configPos = std::string::npos;
1875 if(invokedPos != std::string::npos) configPos = pidCmdLine.find( m_configName );
1878 if( invokedPos != std::string::npos && configPos != std::string::npos)
1881 std::stringstream logss;
1882 logss <<
"PID already locked (" << testPid <<
"). Time to die.";
1898 std::ofstream pidOut;
1899 pidOut.open(pidFileName);
1903 log<software_critical>({__FILE__, __LINE__, errno, 0,
"could not open pid file for writing."});
1912 std::stringstream logss;
1913 logss <<
"PID (" << m_pid <<
") locked.";
1914 log<text_log>(logss.str());
1926 template<
bool _useINDI>
1934 if( ::remove(pidFileName.c_str()) < 0)
1936 log<software_error>({__FILE__, __LINE__, errno, 0, std::string(
"Failed to remove PID file: ") + strerror(errno)});
1941 std::stringstream logss;
1942 logss <<
"PID (" << m_pid <<
") unlocked.";
1943 log<text_log>(logss.str());
1948 template<
bool _useINDI>
1949 template<
class thisPtr,
class Function>
1953 pcf::IndiProperty & thProp,
1955 const std::string & cpuset,
1956 const std::string & thrdName,
1958 Function&& thrdStart
1967 thrd = std::thread( thrdStart, thrdThis);
1969 catch(
const std::exception & e )
1971 log<software_error>({__FILE__,__LINE__, std::string(
"Exception on " + thrdName +
" thread start: ") + e.what()});
1976 log<software_error>({__FILE__,__LINE__,
"Unkown exception on " + thrdName +
" thread start"});
1980 if(!thrd.joinable())
1982 log<software_error>({__FILE__, __LINE__, thrdName +
" thread did not start"});
1988 if(thrdPrio < 0) thrdPrio = 0;
1989 if(thrdPrio > 99) thrdPrio = 99;
1992 sp.sched_priority = thrdPrio;
2004 else rv = pthread_setschedparam(thrd.native_handle(), SCHED_OTHER, &sp);
2009 log<software_error>({__FILE__, __LINE__, errno,
"Setting " + thrdName +
" thread scheduler priority to " + std::to_string(thrdPrio) +
" failed."});
2013 log<text_log>(thrdName +
" thread scheduler priority set to " + std::to_string(thrdPrio));
2019 for(
int i=0;i<10;++i)
2021 mx::sys::milliSleep(100);
2028 return log<
software_error,-1>({__FILE__, __LINE__, errno,
"tpid for " + thrdName +
" not set."});
2032 log<text_log>(thrdName +
" thread pid is " + std::to_string(tpid));
2036 thProp = pcf::IndiProperty(pcf::IndiProperty::Number);
2037 thProp.setDevice(configName());
2038 thProp.setName(std::string(
"th-") + thrdName);
2039 thProp.setPerm(pcf::IndiProperty::ReadOnly);
2040 thProp.setState(pcf::IndiProperty::Idle);
2041 thProp.add(pcf::IndiElement(
"pid"));
2042 thProp[
"pid"] = tpid;
2043 thProp.add(pcf::IndiElement(
"prio"));
2044 thProp[
"prio"] = thrdPrio;
2045 registerIndiPropertyReadOnly(thProp);
2051 std::string cpuFile = m_cpusetPath;
2052 cpuFile +=
"/" + cpuset;
2053 cpuFile +=
"/tasks";
2054 int wfd = open( cpuFile.c_str(), O_WRONLY);
2057 return log<
software_error,-1>({__FILE__, __LINE__, errno,
"error from open for " + cpuFile});
2061 snprintf(pids,
sizeof(pids),
"%d", tpid);
2063 int w = write(wfd, pids,strnlen(pids,
sizeof(pids)));
2064 if(w != (
int) strlen(pids))
2081 template<
bool _useINDI>
2087 template<
bool _useINDI>
2099 log<state_change>( {m_state, s}, lvl );
2105 if(m_stateAlert != stateAlert && stateAlert ==
true)
2107 m_stateAlert = stateAlert;
2113 std::unique_lock<std::mutex> lock(m_indiMutex, std::try_to_lock);
2116 if(lock.owns_lock())
2119 pcf::IndiProperty::PropertyStateType stst =
INDI_IDLE;
2122 if(m_stateAlert ==
true)
2128 if(m_state == stateCodes::READY) stst =
INDI_OK;
2129 else if(m_state == stateCodes::OPERATING || m_state == stateCodes::HOMING || m_state == stateCodes::CONFIGURING) stst =
INDI_BUSY;
2130 else if( m_state < stateCodes::NODEVICE ) stst =
INDI_ALERT;
2131 else if (m_state <= stateCodes::LOGGEDIN ) stst =
INDI_IDLE;
2132 else if (m_state == stateCodes::NOTHOMED || m_state == stateCodes::SHUTDOWN) stst =
INDI_IDLE;
2135 updateIfChanged(m_indiP_state,
"state", stateCodes::codeText(m_state), stst);
2139 template<
bool _useINDI>
2142 if(m_stateLogged > 0)
2145 return m_stateLogged - 1;
2154 template<
bool _useINDI>
2157 if(m_stateAlert ==
false)
return 0;
2158 m_stateAlert =
false;
2161 pcf::IndiProperty::PropertyStateType stst =
INDI_IDLE;
2163 if(m_state == stateCodes::READY) stst =
INDI_OK;
2164 else if(m_state == stateCodes::OPERATING || m_state == stateCodes::HOMING || m_state == stateCodes::CONFIGURING) stst =
INDI_BUSY;
2165 else if( m_state < stateCodes::NODEVICE ) stst =
INDI_ALERT;
2166 else if (m_state <= stateCodes::LOGGEDIN ) stst =
INDI_IDLE;
2167 else if (m_state == stateCodes::NOTHOMED || m_state == stateCodes::SHUTDOWN) stst =
INDI_IDLE;
2169 updateIfChanged(m_indiP_state,
"state", stateCodes::codeText(m_state), stst);
2179 template<
bool _useINDI>
2181 const std::string & propName,
2182 const std::string & label,
2183 const std::string & group
2186 prop = pcf::IndiProperty(pcf::IndiProperty::Text);
2187 prop.setDevice(configName());
2188 prop.setName(propName);
2189 prop.setPerm(pcf::IndiProperty::ReadWrite);
2190 prop.setState(pcf::IndiProperty::Idle);
2191 prop.add(pcf::IndiElement(
"current"));
2192 prop.add(pcf::IndiElement(
"target"));
2197 prop.setLabel(label);
2202 prop.setGroup(group);
2208 template<
bool _useINDI>
2210 const std::string & propName,
2211 const std::string & elName,
2212 const std::string & propLabel,
2213 const std::string & propGroup,
2214 const std::string & elLabel
2217 prop = pcf::IndiProperty(pcf::IndiProperty::Text);
2218 prop.setDevice(configName());
2219 prop.setName(propName);
2220 prop.setPerm(pcf::IndiProperty::ReadOnly);
2221 prop.setState(pcf::IndiProperty::Idle);
2226 prop.setLabel(propLabel);
2231 prop.setGroup(propGroup);
2234 prop.add(pcf::IndiElement(elName));
2238 prop[elName].setLabel(elLabel);
2244 template<
bool _useINDI>
2245 template<
typename T>
2247 const std::string & name,
2251 const std::string & format,
2252 const std::string & label,
2253 const std::string & group
2256 prop = pcf::IndiProperty(pcf::IndiProperty::Number);
2257 prop.setDevice(configName());
2259 prop.setPerm(pcf::IndiProperty::ReadWrite);
2260 prop.setState(pcf::IndiProperty::Idle);
2261 prop.add(pcf::IndiElement(
"current"));
2262 prop[
"current"].setMin(min);
2263 prop[
"current"].setMax(max);
2264 prop[
"current"].setStep(step);
2267 prop[
"current"].setFormat(format);
2270 prop.add(pcf::IndiElement(
"target"));
2271 prop[
"target"].setMin(min);
2272 prop[
"target"].setMax(max);
2273 prop[
"target"].setStep(step);
2276 prop[
"target"].setFormat(format);
2282 prop.setLabel(label);
2287 prop.setGroup(group);
2293 template<
bool _useINDI>
2295 const std::string & propName,
2296 const std::string & propLabel,
2297 const std::string & propGroup
2300 prop = pcf::IndiProperty(pcf::IndiProperty::Number);
2301 prop.setDevice(configName());
2302 prop.setName(propName);
2303 prop.setPerm(pcf::IndiProperty::ReadOnly);
2304 prop.setState(pcf::IndiProperty::Idle);
2309 prop.setLabel(propLabel);
2314 prop.setGroup(propGroup);
2320 template<
bool _useINDI>
2322 const std::string & name,
2323 const std::string & label,
2324 const std::string & group
2327 prop = pcf::IndiProperty(pcf::IndiProperty::Switch);
2328 prop.setDevice(configName());
2330 prop.setPerm(pcf::IndiProperty::ReadWrite);
2331 prop.setState(pcf::IndiProperty::Idle);
2332 prop.setRule(pcf::IndiProperty::AtMostOne);
2335 prop.add(pcf::IndiElement(
"toggle", pcf::IndiElement::Off));
2340 prop.setLabel(label);
2345 prop.setGroup(group);
2351 template<
bool _useINDI>
2353 const std::string & name,
2354 const std::string & label,
2355 const std::string & group
2358 prop = pcf::IndiProperty(pcf::IndiProperty::Switch);
2359 prop.setDevice(configName());
2361 prop.setPerm(pcf::IndiProperty::ReadWrite);
2362 prop.setState(pcf::IndiProperty::Idle);
2363 prop.setRule(pcf::IndiProperty::AtMostOne);
2366 prop.add(pcf::IndiElement(
"request", pcf::IndiElement::Off));
2371 prop.setLabel(label);
2376 prop.setGroup(group);
2382 template<
bool _useINDI>
2384 const std::string & name,
2385 const std::vector<std::string> & elements,
2386 const std::vector<std::string> & elementLabels,
2387 const std::string & label,
2388 const std::string & group
2391 if(elements.size() == 0)
2393 return log<
software_error,-1>({__FILE__,__LINE__,
"elements vector has zero size"});
2396 prop = pcf::IndiProperty(pcf::IndiProperty::Switch);
2397 prop.setDevice(configName());
2399 prop.setPerm(pcf::IndiProperty::ReadWrite);
2400 prop.setState(pcf::IndiProperty::Idle);
2401 prop.setRule(pcf::IndiProperty::OneOfMany);
2404 for(
size_t n=0; n < elements.size(); ++n)
2406 pcf::IndiElement elem = pcf::IndiElement(elements[n], pcf::IndiElement::Off);
2407 elem.setLabel(elementLabels[n]);
2414 prop.setLabel(label);
2419 prop.setGroup(group);
2425 template<
bool _useINDI>
2427 const std::string & name,
2428 const std::vector<std::string> & elements,
2429 const std::string & label,
2430 const std::string & group
2433 return createStandardIndiSelectionSw(prop, name, elements, elements, label, group);
2436 template<
bool _useINDI>
2439 if(!m_useINDI)
return 0;
2447 return log<
software_error,-1>({__FILE__, __LINE__,
"failed to insert INDI property: " + prop.createUniqueKey()});
2450 catch( std::exception & e)
2452 return log<
software_error, -1>({__FILE__, __LINE__, std::string(
"Exception caught: ") + e.what()});
2456 return log<
software_error, -1>({__FILE__, __LINE__,
"Unknown exception caught."});
2462 template<
bool _useINDI>
2464 const std::string & propName,
2465 const pcf::IndiProperty::Type &
propType,
2466 const pcf::IndiProperty::PropertyPermType & propPerm,
2467 const pcf::IndiProperty::PropertyStateType & propState
2470 if(!m_useINDI)
return 0;
2472 prop = pcf::IndiProperty (
propType);
2473 prop.setDevice(m_configName);
2474 prop.setName(propName);
2475 prop.setPerm(propPerm);
2476 prop.setState( propState);
2485 return log<
software_error,-1>({__FILE__, __LINE__,
"failed to insert INDI property: " + prop.createUniqueKey()});
2488 catch( std::exception & e)
2490 return log<
software_error, -1>({__FILE__, __LINE__, std::string(
"Exception caught: ") + e.what()});
2494 return log<
software_error, -1>({__FILE__, __LINE__,
"Unknown exception caught."});
2499 template<
bool _useINDI>
2501 int (*callBack)(
void *,
const pcf::IndiProperty &
ipRecv)
2504 if(!m_useINDI)
return 0;
2508 callBackInsertResult result = m_indiNewCallBacks.insert(callBackValueType( prop.createUniqueKey(), {&prop, callBack}));
2512 return log<
software_error,-1>({__FILE__, __LINE__,
"failed to insert INDI property: " + prop.createUniqueKey()});
2515 catch( std::exception & e)
2517 return log<
software_error, -1>({__FILE__, __LINE__, std::string(
"Exception caught: ") + e.what()});
2521 return log<
software_error, -1>({__FILE__, __LINE__,
"Unknown exception caught."});
2527 template<
bool _useINDI>
2528 int MagAOXApp<_useINDI>::registerIndiPropertyNew( pcf::IndiProperty & prop,
2529 const std::string & propName,
2530 const pcf::IndiProperty::Type &
propType,
2531 const pcf::IndiProperty::PropertyPermType & propPerm,
2532 const pcf::IndiProperty::PropertyStateType & propState,
2533 int (*callBack)(
void *,
const pcf::IndiProperty &
ipRecv)
2536 if(!m_useINDI)
return 0;
2538 prop = pcf::IndiProperty (
propType);
2539 prop.setDevice(m_configName);
2540 prop.setName(propName);
2541 prop.setPerm(propPerm);
2542 prop.setState( propState);
2544 return registerIndiPropertyNew(prop, callBack);
2547 template<
bool _useINDI>
2548 int MagAOXApp<_useINDI>::registerIndiPropertyNew( pcf::IndiProperty & prop,
2549 const std::string & propName,
2550 const pcf::IndiProperty::Type &
propType,
2551 const pcf::IndiProperty::PropertyPermType & propPerm,
2552 const pcf::IndiProperty::PropertyStateType & propState,
2553 const pcf::IndiProperty::SwitchRuleType & propRule,
2554 int (*callBack)(
void *,
const pcf::IndiProperty &
ipRecv)
2557 if(!m_useINDI)
return 0;
2559 prop = pcf::IndiProperty (
propType);
2560 prop.setDevice(m_configName);
2561 prop.setName(propName);
2562 prop.setPerm(propPerm);
2563 prop.setState( propState);
2564 prop.setRule( propRule);
2565 return registerIndiPropertyNew(prop, callBack);
2568 template<
bool _useINDI>
2570 const std::string & devName,
2571 const std::string & propName,
2572 int (*callBack)(
void *,
const pcf::IndiProperty &
ipRecv)
2575 if(!m_useINDI)
return 0;
2577 prop = pcf::IndiProperty();
2578 prop.setDevice(devName);
2579 prop.setName(propName);
2587 return log<
software_error,-1>({__FILE__, __LINE__,
"failed to insert INDI property: " + prop.createUniqueKey()});
2590 catch( std::exception & e)
2592 return log<
software_error, -1>({__FILE__, __LINE__, std::string(
"Exception caught: ") + e.what()});
2596 return log<
software_error, -1>({__FILE__, __LINE__,
"Unknown exception caught."});
2602 template<
bool _useINDI>
2605 if(!m_useINDI)
return 0;
2609 driverFIFOPath +=
"/";
2612 m_driverInName = driverFIFOPath +
"/" + configName() +
".in";
2613 m_driverOutName = driverFIFOPath +
"/" + configName() +
".out";
2614 m_driverCtrlName = driverFIFOPath +
"/" + configName() +
".ctrl";
2620 mode_t prev = umask(0);
2623 if(mkfifo(m_driverInName.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) !=0)
2628 log<software_critical>({__FILE__, __LINE__, errno, 0,
"mkfifo failed"});
2635 if(mkfifo(m_driverOutName.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) !=0 )
2641 log<software_critical>({__FILE__, __LINE__, errno, 0,
"mkfifo failed"});
2648 if(mkfifo(m_driverCtrlName.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) !=0 )
2654 log<software_critical>({__FILE__, __LINE__, errno, 0,
"mkfifo failed"});
2665 template<
bool _useINDI>
2668 if(!m_useINDI)
return 0;
2672 if(createINDIFIFOS() < 0)
2680 if(m_indiDriver !=
nullptr)
2682 m_indiDriver->quitProcess();
2683 m_indiDriver->deactivate();
2684 log<indidriver_stop>();
2685 delete m_indiDriver;
2686 m_indiDriver =
nullptr;
2693 log<software_critical>({__FILE__, __LINE__, 0, 0,
"INDI Driver construction exception."});
2698 if(m_indiDriver ==
nullptr)
2700 log<software_critical>({__FILE__, __LINE__, 0, 0,
"INDI Driver construction failed."});
2705 if(m_indiDriver->good() ==
false)
2707 log<software_critical>({__FILE__, __LINE__, 0, 0,
"INDI Driver failed to open FIFOs."});
2708 delete m_indiDriver;
2709 m_indiDriver =
nullptr;
2714 m_indiDriver->activate();
2715 log<indidriver_start>();
2717 sendGetPropertySetList(
true);
2722 template<
bool _useINDI>
2726 if(!all && m_allDefsReceived)
return;
2731 while(
it != m_indiSetCallBacks.end() )
2733 if(all ||
it->second.m_defReceived ==
false)
2735 if(
it->second.property )
2739 m_indiDriver->sendGetProperties( *(
it->second.property) );
2741 catch(
const std::exception & e)
2743 log<software_error>({__FILE__, __LINE__,
"exception caught from sendGetProperties for " +
2744 it->second.property->getName() +
": " + e.what()});
2748 it->second.m_defReceived =
false;
2754 if(nowFalse != 0) m_allDefsReceived =
false;
2755 if(nowFalse == 0) m_allDefsReceived =
true;
2758 template<
bool _useINDI>
2761 handleSetProperty(
ipRecv);
2764 template<
bool _useINDI>
2767 if(!m_useINDI)
return;
2768 if(m_indiDriver ==
nullptr)
return;
2771 if (
ipRecv.hasValidDevice() &&
ipRecv.getDevice() != m_indiDriver->getName())
2777 if( !
ipRecv.hasValidName() )
2781 while(
it != m_indiNewCallBacks.end() )
2783 if(
it->second.property )
2787 m_indiDriver->sendDefProperty( *(
it->second.property) );
2789 catch(
const std::exception & e)
2791 log<software_error>({__FILE__, __LINE__,
"exception caught from sendDefProperty for " +
2792 it->second.property->getName() +
": " + e.what()});
2799 sendGetPropertySetList(
true);
2805 if( m_indiNewCallBacks.count(
ipRecv.createUniqueKey()) == 0)
2811 if(m_indiNewCallBacks[
ipRecv.createUniqueKey() ].property)
2815 m_indiDriver->sendDefProperty( *(m_indiNewCallBacks[
ipRecv.createUniqueKey() ].property) );
2817 catch(
const std::exception & e)
2819 log<software_error>({__FILE__, __LINE__,
"exception caught from sendDefProperty for " +
2820 m_indiNewCallBacks[
ipRecv.createUniqueKey() ].property->getName() +
": " + e.what()});
2826 template<
bool _useINDI>
2829 if(!m_useINDI)
return;
2830 if(m_indiDriver ==
nullptr)
return;
2833 if( m_indiNewCallBacks.count(
ipRecv.createUniqueKey()) == 0 )
2835 log<software_debug>({__FILE__, __LINE__,
"invalid NewProperty request for " +
ipRecv.createUniqueKey()});
2839 int (*callBack)(
void *,
const pcf::IndiProperty &) = m_indiNewCallBacks[
ipRecv.createUniqueKey() ].callBack;
2841 if(callBack) callBack(
this,
ipRecv);
2843 log<software_debug>({__FILE__, __LINE__,
"NewProperty callback null for " +
ipRecv.createUniqueKey()});
2848 template<
bool _useINDI>
2851 if(!m_useINDI)
return;
2852 if(m_indiDriver ==
nullptr)
return;
2854 std::string key =
ipRecv.createUniqueKey();
2857 if( m_indiSetCallBacks.count(key) > 0 )
2859 m_indiSetCallBacks[ key ].m_defReceived =
true;
2862 int (*callBack)(
void *,
const pcf::IndiProperty &) = m_indiSetCallBacks[ key ].callBack;
2863 if(callBack) callBack(
this,
ipRecv);
2875 template<
bool _useINDI>
2876 template<
typename T>
2878 const std::string & el,
2880 pcf::IndiProperty::PropertyStateType ipState
2883 if(!_useINDI)
return;
2885 if(!m_indiDriver)
return;
2890 template<
bool _useINDI>
2892 const std::string & el,
2893 const char * newVal,
2894 pcf::IndiProperty::PropertyStateType ipState
2897 updateIfChanged<std::string>(p,el, std::string(newVal), ipState);
2900 template<
bool _useINDI>
2902 const std::string & el,
2903 const pcf::IndiElement::SwitchStateType & newVal,
2904 pcf::IndiProperty::PropertyStateType ipState
2907 if(!_useINDI)
return;
2909 if(!m_indiDriver)
return;
2914 template<
bool _useINDI>
2915 template<
typename T>
2917 const std::string & el,
2918 const std::vector<T> & newVals,
2919 pcf::IndiProperty::PropertyStateType ipState
2922 if(!_useINDI)
return;
2924 if(!m_indiDriver)
return;
2926 std::vector<std::string> descriptors(newVals.size(), el);
2927 for (
size_t index = 0; index < newVals.size(); ++index)
2929 descriptors[index] += std::to_string(index);
2934 template<
bool _useINDI>
2935 template<
typename T>
2937 const std::vector<std::string> & els,
2938 const std::vector<T> & newVals
2941 if(!_useINDI)
return;
2943 if(!m_indiDriver)
return;
2949 template<
bool _useINDI>
2950 template<
typename T>
2953 const pcf::IndiProperty & remoteProperty,
2957 if( remoteProperty.createUniqueKey() != localProperty.createUniqueKey())
2962 if( ! (remoteProperty.find(
"target") || remoteProperty.find(
"current") ) )
2969 if( remoteProperty.find(
"target") )
2971 localTarget = remoteProperty[
"target"].get<T>();
2977 if( remoteProperty.find(
"current") )
2979 localTarget = remoteProperty[
"current"].get<T>();
3011 template<
typename T>
3014 return pcf::IndiProperty::Unknown;
3021 pcf::IndiProperty::Type propType<std::string>();
3029 template<
bool _useINDI>
3030 template<
typename T>
3032 const std::string & el,
3036 if(!_useINDI)
return 0;
3040 log<software_error>({__FILE__, __LINE__,
"INDI communications not initialized."});
3043 pcf::IndiProperty ipToSend = ipSend;
3047 ipToSend[el].setValue(newVal);
3051 log<software_error>({__FILE__, __LINE__,
"Exception caught setting " + ipSend.createUniqueKey() +
"." + el});
3058 log<software_error>({__FILE__, __LINE__});
3065 template<
bool _useINDI>
3068 if(!_useINDI)
return 0;
3072 return log<
software_error, -1>({__FILE__, __LINE__,
"INDI communications not initialized."});
3075 if(m_indiDriver->sendNewProperty(ipSend) < 0)
3083 template<
bool _useINDI>
3085 const std::string & property,
3089 if(!_useINDI)
return 0;
3091 pcf::IndiProperty ipSend(pcf::IndiProperty::Switch);
3095 ipSend.setDevice(device);
3096 ipSend.setName(property);
3097 ipSend.add(pcf::IndiElement(
"toggle"));
3099 catch(std::exception & e)
3101 return log<
software_error,-1>({__FILE__,__LINE__, std::string(
"exception: ") + e.what()});
3106 ipSend[
"toggle"].setSwitchState(pcf::IndiElement::Off);
3110 ipSend[
"toggle"].setSwitchState(pcf::IndiElement::On);
3113 if(sendNewProperty(ipSend) < 0)
3115 return log<
software_error,-1>({__FILE__,__LINE__,
"sendNewProperty failed for " + device +
"." +
property});
3121 template<
bool _useINDI>
3123 const pcf::IndiProperty &
ipRecv
3129 template<
bool _useINDI>
3133 if(
ipRecv.createUniqueKey() != m_indiP_clearFSMAlert.createUniqueKey())
3135 return log<
software_error, -1>({__FILE__, __LINE__,
"wrong indi property received"});
3138 if(!
ipRecv.find(
"request"))
return 0;
3140 if(
ipRecv[
"request"].getSwitchState() == pcf::IndiElement::On )
3150 template<
bool _useINDI>
3156 template<
bool _useINDI>
3162 template<
bool _useINDI>
3165 if(!m_powerMgtEnabled || m_powerOnWait == 0 || m_powerOnCounter < 0)
return true;
3167 if(m_powerOnCounter*m_loopPause > ((
double) m_powerOnWait)*1e9)
3178 template<
bool _useINDI>
3181 if(!m_powerMgtEnabled)
return 1;
3183 return m_powerState;
3186 template<
bool _useINDI>
3189 if(!m_powerMgtEnabled)
return 1;
3191 return m_powerTargetState;
3194 template<
bool _useINDI>
3199 if(
ipRecv.find(m_powerElement))
3201 ps =
ipRecv[m_powerElement].get<std::string>();
3207 else if (ps ==
"Off")
3217 if(
ipRecv.find(m_powerTargetElement))
3219 ps =
ipRecv[m_powerTargetElement].get<std::string>();
3223 m_powerTargetState = 1;
3225 else if (ps ==
"Off")
3227 m_powerTargetState = 0;
3231 m_powerTargetState = -1;
3240 template<
bool _useINDI>
3243 return m_configName;
3246 template<
bool _useINDI>
3252 template<
bool _useINDI>
3255 return m_driverInName;
3258 template<
bool _useINDI>
3261 return m_driverOutName;
3264 template<
bool _useINDI>
3267 return m_driverCtrlName;
Internal class to manage setuid privilege escalation with RAII.
elevatedPrivileges(MagAOXApp *app)
The base-class for MagAO-X applications.
void handleDefProperty(const pcf::IndiProperty &ipRecv)
Handler for the DEF INDI properties notification.
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.
void handleSetProperty(const pcf::IndiProperty &ipRecv)
Handler for the set INDI property request.
int sendNewStandardIndiToggle(const std::string &device, const std::string &property, bool onoff)
Send a new property commmand for a standard toggle switch.
std::string m_configName
The name of the configuration file (minus .conf).
virtual int onPowerOff()
This method is called when the change to poweroff is detected.
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, const std::string &propName, const pcf::IndiProperty::Type &propType, const pcf::IndiProperty::PropertyPermType &propPerm, const pcf::IndiProperty::PropertyStateType &propState, int(*)(void *, const pcf::IndiProperty &))
Register an INDI property which is exposed for others to request a New Property for.
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.
void handlerSigTerm(int signum, siginfo_t *siginf, void *ucont)
Handles SIGTERM, SIGQUIT, and SIGINT. Sets m_shutdown to 1 and logs the signal.
std::pair< callBackIterator, bool > callBackInsertResult
Return type of insert on the indiCallBack map.
std::string driverCtrlName()
Get the INDI control FIFO file name.
void updateIfChanged(pcf::IndiProperty &p, const std::vector< std::string > &els, const std::vector< T > &newVals)
Update an INDI property if values have changed.
int createStandardIndiNumber(pcf::IndiProperty &prop, const std::string &name, const T &min, const T &max, const T &step, const std::string &format, const std::string &label="", const std::string &group="")
Create a standard R/W INDI Number property with target and current elements.
INDI_SETCALLBACK_DECL(MagAOXApp, m_indiP_powerChannel)
int powerState()
Returns the current power state.
std::string pidFileName
The name of the PID file.
void sendGetPropertySetList(bool all=false)
void updateIfChanged(pcf::IndiProperty &p, const std::string &el, const char *newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI property element value if it has changed.
int setEuidReal()
Set the effective user ID to the real value, i.e. the file owner.
pcf::IndiProperty m_indiP_powerChannel
INDI property used to communicate power state.
int createINDIFIFOS()
Create the INDI FIFOs.
int createStandardIndiSelectionSw(pcf::IndiProperty &prop, const std::string &name, const std::vector< std::string > &elements, const std::string &label="", const std::string &group="")
Create a standard R/W INDI selection (one of many) switch with vector of elements using the element s...
std::string m_powerDevice
The INDI device name of the power controller.
int sendNewProperty(const pcf::IndiProperty &ipSend)
Send a newProperty command to another device (using the INDI Client interface)
void state(const stateCodes::stateCodeT &s, bool stateAlert=false)
Set the current state code.
void handleNewProperty(const pcf::IndiProperty &ipRecv)
Handler for the new INDI property request.
int powerStateTarget()
Returns the target power state.
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.
std::pair< std::string, indiCallBack > callBackValueType
Value type of the indiCallBack map.
std::string m_calibDir
The path to calibration files for MagAOX.
std::string configDir()
Get the config directory.
static int st_newCallBack_clearFSMAlert(void *app, const pcf::IndiProperty &ipRecv)
The static callback function to be registered for requesting to clear the FSM alert.
int stateLogged()
Updates and returns the value of m_stateLogged. Will be 0 on first call after a state change,...
int newCallBack_clearFSMAlert(const pcf::IndiProperty &ipRecv)
The callback called by the static version, to actually process the FSM Alert Clear request.
int lockPID()
Attempt to lock the PID by writing it to a file. Fails if a process is already running with the same ...
MagAOXApp(const std::string &git_sha1, const bool git_modified)
Public c'tor. Handles uid, logs git repo status, and initializes static members.
void handleGetProperties(const pcf::IndiProperty &ipRecv)
Handler for the get INDI properties request.
std::string m_configDir
The path to configuration files for MagAOX.
MagAOXApp()=delete
Default c'tor is deleted.
int createROIndiNumber(pcf::IndiProperty &prop, const std::string &propName, const std::string &propLabel="", const std::string &propGroup="")
Create a ReadOnly INDI Number property.
int registerIndiPropertyReadOnly(pcf::IndiProperty &prop)
Register an INDI property which is read only.
void updateIfChanged(pcf::IndiProperty &p, const std::string &el, const std::vector< T > &newVals, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI property if values have changed.
std::string driverOutName()
Get the INDI output FIFO file name.
pcf::IndiProperty m_indiP_clearFSMAlert
indi Property to clear an FSM alert.
virtual int whilePowerOff()
This method is called while the power is off, once per FSM loop.
bool powerOnWaitElapsed()
This method tests whether the power on wait time has elapsed.
logger::logManager< MagAOXApp< _useINDI >, logFileRaw > logManagerT
The log manager type.
std::string m_powerChannel
The INDI property name of the channel controlling this device's power.
int createROIndiText(pcf::IndiProperty &prop, const std::string &propName, const std::string &elName, const std::string &propLabel="", const std::string &propGroup="", const std::string &elLabel="")
Create a standard ReadOnly INDI Text property, with at least one element.
std::string secretsPath
Path to the secrets directory, where passwords, etc, are stored.
int clearFSMAlert()
Clear the FSM alert state.
std::mutex m_indiMutex
Mutex for locking INDI communications.
std::string m_configBase
The name of a base config class for this app (minus .conf).
std::string configName()
Get the config name.
int createStandardIndiSelectionSw(pcf::IndiProperty &prop, const std::string &name, const std::vector< std::string > &elements, const std::vector< std::string > &elementLabels, const std::string &label="", const std::string &group="")
Create a standard R/W INDI selection (one of many) switch with vector of elements and element labels.
std::string m_driverOutName
Full path name of the INDI driver output FIFO.
int threadStart(std::thread &thrd, bool &thrdInit, pid_t &tpid, pcf::IndiProperty &thProp, int thrdPrio, const std::string &cpuset, const std::string &thrdName, thisPtr *thrdThis, Function &&thrdStart)
Start a thread, using this class's privileges to set priority, etc.
std::string sysPath
The path to the system directory, for PID file, etc.
int startINDI()
Start INDI Communications.
int sendNewProperty(const pcf::IndiProperty &ipSend, const std::string &el, const T &newVal)
Send a newProperty command to another device (using the INDI Client interface)
int createStandardIndiText(pcf::IndiProperty &prop, const std::string &propName, const std::string &label="", const std::string &group="")
Create a standard R/W INDI Text property with target and current elements.
~MagAOXApp() noexcept(true)
int registerIndiPropertySet(pcf::IndiProperty &prop, const std::string &devName, const std::string &propName, int(*)(void *, const pcf::IndiProperty &))
Register an INDI property which is monitored for updates from others.
int registerIndiPropertyNew(pcf::IndiProperty &prop, const std::string &propName, const pcf::IndiProperty::Type &propType, const pcf::IndiProperty::PropertyPermType &propPerm, const pcf::IndiProperty::PropertyStateType &propState, const pcf::IndiProperty::SwitchRuleType &propRule, int(*)(void *, const pcf::IndiProperty &))
Register an INDI property which is exposed for others to request a New Property for,...
int registerIndiPropertyReadOnly(pcf::IndiProperty &prop, const std::string &propName, const pcf::IndiProperty::Type &propType, const pcf::IndiProperty::PropertyPermType &propPerm, const pcf::IndiProperty::PropertyStateType &propState)
Register an INDI property which is read only.
std::string driverInName()
Get the INDI input FIFO file name.
int indiTargetUpdate(pcf::IndiProperty &localProperty, T &localTarget, const pcf::IndiProperty &remoteProperty, bool setBusy=true)
Get the target element value from an new property.
int unlockPID()
Remove the PID file.
std::string MagAOXPath
The base path of the MagAO-X system.
std::string m_driverCtrlName
Full path name of the INDI driver control FIFO.
pcf::IndiProperty m_indiP_state
indi Property to report the application state.
std::unordered_map< std::string, indiCallBack > m_indiSetCallBacks
Map to hold the SetProperty indiCallBacks for this App, with fast lookup by property name.
int setEuidCalled()
Set the effective user ID to the called value, i.e. the highest possible.
std::unordered_map< std::string, indiCallBack >::iterator callBackIterator
Iterator type of the indiCallBack map.
std::string m_driverInName
Full path name of the INDI driver input FIFO.
std::unordered_map< std::string, indiCallBack > m_indiNewCallBacks
Map to hold the NewProperty indiCallBacks for this App, with fast lookup by property name.
A class to manage raw binary log files.
#define MAGAOX_RT_SCHED_POLICY
The real-time scheduling policy.
#define MAGAOX_default_loopPause
The default application loopPause.
#define MAGAOX_calibRelPath
The relative path to the calibration files.
#define MAGAOX_driverFIFORelPath
The relative path to the INDI driver FIFOs.
#define MAGAOX_configRelPath
The relative path to the configuration files.
#define MAGAOX_logRelPath
The relative path to the log directory.
#define MAGAOX_sysRelPath
The relative path to the system directory.
#define MAGAOX_path
The path to the MagAO-X system files.
#define MAGAOX_secretsRelPath
The relative path to the secrets directory. Used for storing passwords, etc.
#define MAGAOX_cpusetPath
The absolute path the the cpuset mount point.
#define MAGAOX_env_path
Environment variable setting the MagAO-X path.
#define MAGAOX_env_calib
Environment variable setting the relative calib path.
#define MAGAOX_env_config
Environment variable setting the relative config path.
#define MAGAOX_env_cpuset
Environment variable setting the relative calib path.
#define INDI_SETCALLBACK_DEFN(class, prop)
Define the callback for a set property request.
#define INDI_SETCALLBACK(prop)
Get the name of the static callback wrapper for a set property.
int8_t logPrioT
The type of the log priority code.
std::shared_ptr< char > bufferPtrT
The log entry buffer smart pointer.
int th_seteuid(uid_t euid)
Sets the effective user id of the calling thread, rather than the whole process.
MagAO-X INDI Driver Wrapper.
GeneratorWrapper< T > value(T &&value)
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.
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.
pcf::IndiProperty::Type propType< int >()
const pcf::IndiProperty & ipRecv
pcf::IndiProperty::Type propType< char * >()
void sigUsr1Handler(int signum, siginfo_t *siginf, void *ucont)
Empty signal handler. SIGUSR1 is used to interrupt sleep in various threads.
pcf::IndiProperty::Type propType< double >()
pcf::IndiProperty::Type propType()
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_INFO
Informational. The info log level is the lowest level recorded during normal operations.
constexpr static logPrioT LOG_WARNING
A condition has occurred which may become an error, but the process continues.
constexpr static logPrioT LOG_DEFAULT
Used to denote "use the default level for this log type".
constexpr static logPrioT LOG_NOTICE
A normal but significant condition.
MagAO-X Application States.
Structure to hold the call-back details for handling INDI communications.
int16_t stateCodeT
The type of the state code.
The type of the input message.
The standard MagAOX log manager, used for both process logs and telemetry streams.
A simple text log, a string-type log.
A fixed-width timespec structure.
nanosecT time_ns
Nanoseconds.
secT time_s
Time since the Unix epoch.