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>
32 #include "../common/environment.hpp"
33 #include "../common/paths.hpp"
34 #include "../common/defaults.hpp"
35 #include "../common/config.hpp"
37 #include "../logger/logFileRaw.hpp"
38 #include "../logger/logManager.hpp"
40 #include "../sys/thSetuid.hpp"
47 using namespace mx::app;
71 template <
bool _useINDI = true>
74 friend class MagAOXApp_test;
123 const bool git_modified
142 virtual
void setDefaults(
int argc,
154 virtual
void setupBasicConfig();
164 virtual
void loadBasicConfig();
170 virtual
void checkConfig();
200 virtual
int execute();
213 virtual
int appStartup() = 0;
224 virtual
int appLogic() = 0;
229 virtual
int appShutdown() = 0;
246 template <typename logT,
int retval = 0>
247 static
int log( const typename logT::messageT &
msg,
259 template <typename logT,
int retval = 0>
276 static
void configLog( const std::
string &name,
278 const std::
string &
value,
279 const std::
string &source
293 int setSigTermHandler();
296 static
void _handlerSigTerm(
int signum,
302 void handlerSigTerm(
int signum,
327 bool m_elevated{
false };
451 template <
class thisPtr,
class Function>
456 pcf::IndiProperty &thProp,
458 const std::string &cpuset,
459 const std::string &thrdName,
475 bool m_stateAlert{
false };
478 bool m_gitAlert{
false };
480 int m_stateLogged{ 0 };
496 bool stateAlert =
false
537 constexpr
static bool m_useINDI = _useINDI;
551 pcf::IndiProperty *
property{ 0 };
552 int ( *callBack )(
void *,
const pcf::IndiProperty & ){ 0 };
555 bool m_defReceived{
false };
582 bool m_allDefsReceived{
false };
602 const std::string &propName,
603 const std::string &label =
"",
605 const std::string &group =
""
615 const std::string &propName,
616 const std::string &elName,
617 const std::string &propLabel =
"",
618 const std::string &propGroup =
"",
619 const std::string &elLabel =
""
627 template <
typename T>
629 const std::string &name,
636 const std::string &format,
639 const std::string &label =
"",
641 const std::string &group =
""
650 const std::string &propName,
651 const std::string &propLabel =
"",
653 const std::string &propGroup =
""
663 const std::string &name,
664 const std::string &label =
"",
666 const std::string &group =
""
676 const std::string &name,
677 const std::string &label =
"",
679 const std::string &group =
""
689 const std::string &name,
690 const std::vector<std::string> &elements,
692 const std::vector<std::string> &elementLabels,
694 const std::string &label =
"",
696 const std::string &group =
""
707 const std::string &name,
708 const std::vector<std::string> &elements,
710 const std::string &label =
"",
712 const std::string &group =
""
735 const std::string &propName,
737 const pcf::IndiProperty::Type &
propType,
739 const pcf::IndiProperty::PropertyPermType &propPerm,
742 const pcf::IndiProperty::PropertyStateType &propState
755 int ( * )(
void *,
const pcf::IndiProperty & )
767 pcf::IndiProperty &prop,
768 const std::string &propName,
769 const pcf::IndiProperty::Type &
propType,
770 const pcf::IndiProperty::PropertyPermType &propPerm,
771 const pcf::IndiProperty::PropertyStateType &propState,
772 int ( * )(
void *,
const pcf::IndiProperty & )
783 pcf::IndiProperty &prop,
784 const std::string &propName,
785 const pcf::IndiProperty::Type &
propType,
786 const pcf::IndiProperty::PropertyPermType &propPerm,
787 const pcf::IndiProperty::PropertyStateType &propState,
788 const pcf::IndiProperty::SwitchRuleType &propRule,
789 int ( * )(
void *,
const pcf::IndiProperty & )
800 pcf::IndiProperty &prop,
801 const std::string &devName,
802 const std::string &propName,
803 int ( * )(
void *,
const pcf::IndiProperty & )
864 template <
typename T>
866 const std::string &el,
868 pcf::IndiProperty::PropertyStateType ipState = pcf::IndiProperty::Ok );
883 const std::string &el,
885 pcf::IndiProperty::PropertyStateType ipState = pcf::IndiProperty::Ok );
894 const std::string &el,
895 const pcf::IndiElement::SwitchStateType &newVal,
896 pcf::IndiProperty::PropertyStateType ipState = pcf::IndiProperty::Ok );
910 template <
typename T>
912 pcf::IndiProperty &p,
913 const std::string &el,
914 const std::vector<T> &newVals,
915 pcf::IndiProperty::PropertyStateType ipState = pcf::IndiProperty::Ok
927 template <
typename T>
929 const std::vector<std::string> &els,
930 const std::vector<T> &newVals,
931 pcf::IndiProperty::PropertyStateType newState =
932 pcf::IndiProperty::Ok
940 template <
typename T>
943 const pcf::IndiProperty &remoteProperty,
953 template <
typename T>
955 const std::string &el,
972 const std::string &property,
989 const pcf::IndiProperty &
ipRecv
1016 bool m_powerMgtEnabled{
false };
1023 std::string m_powerElement{
"state" };
1024 std::string m_powerTargetElement{
"target" };
1026 unsigned long m_powerOnWait{ 0 };
1029 int m_powerOnCounter{ -1 };
1033 int m_powerState{ -1 };
1034 int m_powerTargetState{ -1 };
1124 template <
bool _useINDI>
1128 template <
bool _useINDI>
1131 template <
bool _useINDI>
1134 if( m_self !=
nullptr )
1136 std::cerr <<
"Attempt to instantiate 2nd MagAOXApp. Exiting immediately.\n";
1143 getresuid( &m_euidReal, &m_euidCalled, &m_suid );
1146 m_log.parent(
this );
1149 config.m_sources =
true;
1150 config.configLog = configLog;
1162 if( MXLIB_UNCOMP_REPO_MODIFIED )
1168 log<git_state>(
git_state::messageT(
"mxlib", MXLIB_UNCOMP_CURRENT_SHA1, MXLIB_UNCOMP_REPO_MODIFIED ), gl );
1171 template <
bool _useINDI>
1175 delete m_indiDriver;
1176 m_log.parent(
nullptr );
1181 template <
bool _useINDI>
1187 template <
bool _useINDI>
1196 MagAOXPath = tmpstr;
1209 m_configDir = MagAOXPath +
"/" + tmpstr;
1210 m_configPathGlobal = m_configDir +
"/magaox.conf";
1218 m_calibDir = MagAOXPath +
"/" + tmpstr;
1223 m_log.logPath( tmpstr );
1231 secretsPath = tmpstr;
1237 m_cpusetPath = tmpstr;
1241 if( m_configBase !=
"" )
1244 m_configPathUser = m_configDir +
"/" + m_configBase +
".conf";
1256 "The name of the application and its device name in INDI (if used), specifies the config file in the XWC config directory." );
1258 config.parseCommandLine( argc, argv,
"name" );
1259 config( m_configName,
"name" );
1261 if( m_configName ==
"" )
1263 m_configName = mx::ioutils::pathStem( invokedName );
1266 log<text_log>(
"Configuration Error: Application name (-n --name) not set." );
1272 m_configPathLocal = m_configDir +
"/" + m_configName +
".conf";
1275 if( registerIndiPropertyNew(
1276 m_indiP_state,
"fsm", pcf::IndiProperty::Text, pcf::IndiProperty::ReadOnly, pcf::IndiProperty::Idle, 0 ) <
1279 log<software_error>( { __FILE__, __LINE__,
"failed to register read only fsm_state property" } );
1282 m_indiP_state.add( pcf::IndiElement(
"state" ) );
1284 createStandardIndiRequestSw( m_indiP_clearFSMAlert,
"fsm_clear_alert",
"Clear FSM Alert",
"FSM" );
1285 if( registerIndiPropertyNew( m_indiP_clearFSMAlert, st_newCallBack_clearFSMAlert ) < 0 )
1287 log<software_error>( { __FILE__, __LINE__,
"failed to register new fsm_alert property" } );
1293 template <
bool _useINDI>
1297 config.add(
"config.validate",
1305 "Validate the configuration. App will exit after loading the configuration, but before entering the event loop. Errors from configuratin processing will be shown. Always safe to run." );
1308 config.add(
"loopPause",
1316 "The main loop pause time in ns" );
1319 "ignore_git",
"",
"ignore-git", argType::True,
"",
"",
false,
"bool",
"set to true to ignore git status to prevent the fsm_alert" );
1322 m_log.setupConfig( config );
1324 if( m_powerMgtEnabled )
1326 if( _useINDI ==
false )
1329 log<software_critical>( { __FILE__, __LINE__,
"power management is enabled but we are not using INDI" } );
1334 config.add(
"power.device",
1342 "Device controlling power for this app's device (INDI name)." );
1343 config.add(
"power.channel",
1351 "Channel on device for this app's device (INDI name)." );
1352 config.add(
"power.element",
1360 "INDI power state element name. Default is \"state\", only need to specify if different." );
1361 config.add(
"power.targetElement",
1363 "power.targetElement",
1369 "INDI power target element name. Default is \"target\", only need to specify if different." );
1370 config.add(
"power.powerOnWait",
1372 "power.powerOnWait",
1378 "Time after power-on to wait before continuing [sec]. Default is 0 sec, max is 3600 sec." );
1382 template <
bool _useINDI>
1387 config( ig,
"ignore_git" );
1389 if( !ig && m_gitAlert )
1391 m_stateAlert =
true;
1395 if(config.isSet(
"config.validate"))
1397 m_configOnly =
true;
1401 m_log.logName( m_configName );
1402 m_log.loadConfig( config );
1405 config( m_loopPause,
"loopPause" );
1408 if( m_powerMgtEnabled )
1410 config( m_powerDevice,
"power.device" );
1411 config( m_powerChannel,
"power.channel" );
1412 config( m_powerElement,
"power.element" );
1413 config( m_powerTargetElement,
"power.targetElement" );
1415 if( m_powerDevice !=
"" && m_powerChannel !=
"" )
1417 log<text_log>(
"enabling power management: " + m_powerDevice +
"." + m_powerChannel +
"." + m_powerElement +
1418 "/" + m_powerTargetElement );
1419 if( registerIndiPropertySet(
1420 m_indiP_powerChannel, m_powerDevice, m_powerChannel,
INDI_SETCALLBACK( m_indiP_powerChannel ) ) <
1423 log<software_error>( { __FILE__, __LINE__,
"failed to register set property" } );
1432 config( m_powerOnWait,
"power.powerOnWait" );
1433 if( m_powerOnWait > 3600 )
1435 log<text_log>(
"powerOnWait longer than 1 hour. Setting to 0.",
logPrio::LOG_ERROR );
1440 template <
bool _useINDI>
1445 for(
auto it = config.m_targets.begin();
it != config.m_targets.end(); ++
it )
1447 if(
it->second.used ==
false )
1449 std::string
msg =
it->second.name;
1450 if( config.m_sources &&
it->second.sources.size() > 0 )
1452 msg +=
" [" +
it->second.sources[0] +
"]";
1460 if( config.m_unusedConfigs.size() > 0 )
1462 for(
auto it = config.m_unusedConfigs.begin();
it != config.m_unusedConfigs.end(); ++
it )
1464 if(
it->second.used ==
true )
1469 std::string
msg =
it->second.name;
1470 if( config.m_sources &&
it->second.sources.size() > 0 )
1472 msg +=
" [" +
it->second.sources[0] +
"]";
1481 if( config.nonOptions.size() > 0 )
1483 for(
size_t n = 0; n < config.nonOptions.size(); ++n )
1485 log<text_log>(
"Unrecognized command line argument: " + config.nonOptions[n],
logPrio::LOG_CRITICAL );
1492 if(m_shutdown ==
true)
1494 std::cerr <<
"\nThere were configuration errors.\n\n";
1498 std::cerr <<
"\nConfiguration is valid.\n\n";
1501 else if(m_shutdown ==
true)
1507 template <
bool _useINDI>
1513 #ifndef XWC_DISABLE_USER_CHECK
1514 struct stat logstat;
1516 if( stat( m_log.logPath().c_str(), &logstat ) < 0 )
1518 state( stateCodes::FAILURE );
1519 std::cerr <<
"\nCRITICAL: Can not stat the log path.\n\n";
1523 if( logstat.st_uid != geteuid() )
1525 state( stateCodes::FAILURE );
1526 std::cerr <<
"\nCRITICAL: You are running this app as the wrong user.\n\n";
1536 state( stateCodes::FAILURE );
1539 std::cerr <<
"\nCRITICAL: Failed to lock PID. Exiting.\n\n";
1548 m_log.logThreadStart();
1552 while( m_log.logThreadRunning() ==
false && w < 20 )
1555 std::this_thread::sleep_for( std::chrono::duration<unsigned long, std::nano>( 100000000 ) );
1559 if( m_log.logThreadRunning() ==
false )
1561 state( stateCodes::FAILURE );
1564 std::cerr <<
"\nCRITICAL: log thread not running. Exiting.\n\n";
1568 if( unlockPID() < 0 )
1570 log<software_error>( { __FILE__, __LINE__,
"error from unlockPID()" } );
1579 if( m_shutdown == 0 )
1581 if( setSigTermHandler() < 0 )
1583 state( stateCodes::FAILURE );
1585 log<software_critical>( { __FILE__, __LINE__,
"error from setSigTermHandler()" } );
1589 if( unlockPID() < 0 )
1591 log<software_error>( { __FILE__, __LINE__,
"error from unlockPID()" } );
1601 if( m_shutdown == 0 )
1603 state( stateCodes::INITIALIZED );
1605 if( appStartup() < 0 )
1607 state( stateCodes::FAILURE );
1609 log<software_critical>( { __FILE__, __LINE__,
"error from appStartup()" } );
1613 if( unlockPID() < 0 )
1615 log<software_error>( { __FILE__, __LINE__,
"error from unlockPID()" } );
1623 if( m_useINDI && m_shutdown == 0 )
1625 if( startINDI() < 0 )
1627 state( stateCodes::FAILURE );
1629 log<software_critical>( { __FILE__, __LINE__,
"INDI failed to start." } );
1634 if( appShutdown() < 0 )
1636 log<software_error>( { __FILE__, __LINE__,
"error from appShutdown()" } );
1639 if( unlockPID() < 0 )
1641 log<software_error>( { __FILE__, __LINE__,
"error from unlockPID()" } );
1649 if( m_powerMgtEnabled && m_shutdown == 0 )
1652 while( m_powerState < 0 && !m_shutdown )
1655 if( m_powerState < 0 )
1657 if( !stateLogged() )
1658 log<text_log>(
"waiting for power state" );
1665 state( stateCodes::ERROR );
1669 if( m_powerState > 0 )
1671 state( stateCodes::POWERON );
1675 m_powerOnCounter = 0;
1676 state( stateCodes::POWEROFF );
1677 if( onPowerOff() < 0 )
1679 log<software_error>( { __FILE__, __LINE__,
"error from onPowerOff()" } );
1694 while( m_shutdown == 0 )
1697 if( m_powerMgtEnabled )
1699 if( state() == stateCodes::POWEROFF )
1701 if( m_powerState == 1 )
1703 m_powerOnCounter = 0;
1704 state( stateCodes::POWERON );
1709 if( m_powerState == 0 )
1711 state( stateCodes::POWEROFF );
1712 if( onPowerOff() < 0 )
1714 log<software_error>( { __FILE__, __LINE__,
"error from onPowerOff()" } );
1724 if( !m_powerMgtEnabled || m_powerState > 0 )
1726 if( appLogic() < 0 )
1728 log<software_error>( { __FILE__, __LINE__,
"error from appLogic()" } );
1733 else if( m_powerState == 0 )
1735 if( whilePowerOff() < 0 )
1737 log<software_error>( { __FILE__, __LINE__,
"error from whilePowerOff()" } );
1752 sendGetPropertySetList(
false );
1760 if( m_shutdown == 0 )
1762 std::this_thread::sleep_for( std::chrono::duration<unsigned long, std::nano>( m_loopPause ) );
1766 if( appShutdown() < 0 )
1768 log<software_error>( { __FILE__, __LINE__,
"error from appShutdown()" } );
1771 state( stateCodes::SHUTDOWN );
1774 if( m_indiDriver !=
nullptr )
1776 pcf::IndiProperty ipSend;
1777 ipSend.setDevice( m_configName );
1780 m_indiDriver->sendDelProperty( ipSend );
1782 catch(
const std::exception &e )
1784 log<software_error>(
1785 { __FILE__, __LINE__, std::string(
"exception caught from sendDelProperty: " ) + e.what() } );
1788 m_indiDriver->quitProcess();
1789 m_indiDriver->deactivate();
1790 log<indidriver_stop>();
1793 if( unlockPID() < 0 )
1795 log<software_error>( { __FILE__, __LINE__,
"error from unlockPID()" } );
1802 template <
bool _useINDI>
1803 template <
typename logT,
int retval>
1806 m_log.template log<logT>(
msg, level );
1810 template <
bool _useINDI>
1811 template <
typename logT,
int retval>
1814 m_log.template log<logT>( level );
1818 template <
bool _useINDI>
1829 state( m_state,
true );
1832 if( _useINDI && m_indiDriver )
1834 pcf::IndiProperty
msg;
1835 msg.setDevice( m_configName );
1837 std::stringstream logstdf;
1838 logMinStdFormat( logstdf, b );
1840 msg.setMessage( logstdf.str() );
1843 timespecX ts = logHeader::timespec( b );
1846 tv.tv_usec = (
long int)( ( (
double)ts.
time_ns ) / 1e3 );
1848 msg.setTimeStamp( pcf::TimeStamp( tv ) );
1852 m_indiDriver->sendMessage(
msg );
1854 catch(
const std::exception &e )
1856 log<software_error>(
1857 { __FILE__, __LINE__, std::string(
"exception caught from sendMessage: " ) + e.what() } );
1862 template <
bool _useINDI>
1865 const std::string &
value,
1866 const std::string &source )
1868 m_log.template log<config_log>( { name, code,
value, source } );
1871 template <
bool _useINDI>
1874 struct sigaction act;
1878 act.sa_flags = SA_SIGINFO;
1879 sigemptyset( &set );
1883 if( sigaction( SIGTERM, &act, 0 ) < 0 )
1885 std::string logss =
"Setting handler for SIGTERM failed. Errno says: ";
1886 logss += strerror( errno );
1888 log<software_error>( { __FILE__, __LINE__, errno, 0, logss } );
1894 if( sigaction( SIGQUIT, &act, 0 ) < 0 )
1896 std::string logss =
"Setting handler for SIGQUIT failed. Errno says: ";
1897 logss += strerror( errno );
1899 log<software_error>( { __FILE__, __LINE__, errno, 0, logss } );
1905 if( sigaction( SIGINT, &act, 0 ) < 0 )
1907 std::string logss =
"Setting handler for SIGINT failed. Errno says: ";
1908 logss += strerror( errno );
1910 log<software_error>( { __FILE__, __LINE__, errno, 0, logss } );
1915 log<text_log>(
"Installed SIGTERM/SIGQUIT/SIGINT signal handler.",
logPrio::LOG_DEBUG );
1920 template <
bool _useINDI>
1926 template <
bool _useINDI>
1928 siginfo_t *siginf __attribute__( ( unused ) ),
1929 void *ucont __attribute__( ( unused ) ) )
1933 std::string signame;
1937 signame =
"SIGTERM";
1943 signame =
"SIGQUIT";
1949 std::string logss =
"Caught signal ";
1951 logss +=
". Shutting down.";
1953 std::cerr <<
"\n" << logss << std::endl;
1954 log<text_log>( logss );
1958 void sigUsr1Handler(
int signum, siginfo_t *siginf,
void *ucont );
1960 template <
bool _useINDI>
1966 std::string logss =
"Setting effective user id to euidCalled (";
1967 logss += mx::ioutils::convertToString<int>( m_euidCalled );
1968 logss +=
") failed. Errno says: ";
1969 logss += strerror( errno );
1971 log<software_error>( { __FILE__, __LINE__, errno, 0, logss } );
1979 template <
bool _useINDI>
1985 std::string logss =
"Setting effective user id to euidReal (";
1986 logss += mx::ioutils::convertToString<int>( m_euidReal );
1987 logss +=
") failed. Errno says: ";
1988 logss += strerror( errno );
1990 log<software_error>( { __FILE__, __LINE__, errno, 0, logss } );
1998 template <
bool _useINDI>
2003 std::string statusDir = sysPath;
2011 if( mkdir( statusDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH ) < 0 )
2013 if( errno != EEXIST )
2015 std::stringstream logss;
2016 logss <<
"Failed to create root of statusDir (" << statusDir <<
"). Errno says: " << strerror( errno );
2017 log<software_critical>( { __FILE__, __LINE__, errno, 0, logss.str() } );
2023 statusDir += m_configName;
2025 pidFileName = statusDir +
"/pid";
2030 if( mkdir( statusDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH ) < 0 )
2032 if( errno != EEXIST )
2034 std::stringstream logss;
2035 logss <<
"Failed to create statusDir (" << statusDir <<
"). Errno says: " << strerror( errno );
2036 log<software_critical>( { __FILE__, __LINE__, errno, 0, logss.str() } );
2042 std::ifstream pidIn;
2043 pidIn.open( pidFileName );
2053 std::stringstream procN;
2054 procN <<
"/proc/" << testPid <<
"/cmdline";
2056 std::ifstream procIn;
2057 std::string pidCmdLine;
2061 procIn.open( procN.str() );
2063 procIn >> pidCmdLine;
2068 log<software_critical>( { __FILE__, __LINE__, 0, 0,
"exception caught testing /proc/pid" } );
2076 size_t invokedPos = pidCmdLine.find( invokedName );
2079 size_t configPos = std::string::npos;
2080 if( invokedPos != std::string::npos )
2081 configPos = pidCmdLine.find( m_configName );
2084 if( invokedPos != std::string::npos && configPos != std::string::npos )
2087 std::stringstream logss;
2088 logss <<
"PID already locked (" << testPid <<
"). Time to die.";
2104 std::ofstream pidOut;
2105 pidOut.open( pidFileName );
2107 if( !pidOut.good() )
2109 log<software_critical>( { __FILE__, __LINE__, errno, 0,
"could not open pid file for writing." } );
2118 std::stringstream logss;
2119 logss <<
"PID (" << m_pid <<
") locked.";
2120 log<text_log>( logss.str() );
2132 template <
bool _useINDI>
2140 if( ::remove( pidFileName.c_str() ) < 0 )
2142 log<software_error>(
2143 { __FILE__, __LINE__, errno, 0, std::string(
"Failed to remove PID file: " ) + strerror( errno ) } );
2148 std::stringstream logss;
2149 logss <<
"PID (" << m_pid <<
") unlocked.";
2150 log<text_log>( logss.str() );
2155 template <
bool _useINDI>
2156 template <
class thisPtr,
class Function>
2160 pcf::IndiProperty &thProp,
2162 const std::string &cpuset,
2163 const std::string &thrdName,
2165 Function &&thrdStart )
2173 thrd = std::thread( thrdStart, thrdThis );
2175 catch(
const std::exception &e )
2177 log<software_error>(
2178 { __FILE__, __LINE__, std::string(
"Exception on " + thrdName +
" thread start: " ) + e.what() } );
2183 log<software_error>( { __FILE__, __LINE__,
"Unkown exception on " + thrdName +
" thread start" } );
2187 if( !thrd.joinable() )
2189 log<software_error>( { __FILE__, __LINE__, thrdName +
" thread did not start" } );
2201 sp.sched_priority = thrdPrio;
2215 rv = pthread_setschedparam( thrd.native_handle(), SCHED_OTHER, &sp );
2220 log<software_error>(
2224 "Setting " + thrdName +
" thread scheduler priority to " + std::to_string( thrdPrio ) +
" failed." } );
2228 log<text_log>( thrdName +
" thread scheduler priority set to " + std::to_string( thrdPrio ) );
2234 for(
int i = 0; i < 10; ++i )
2236 mx::sys::milliSleep( 100 );
2244 return log<
software_error, -1>( { __FILE__, __LINE__, errno,
"tpid for " + thrdName +
" not set." } );
2248 log<text_log>( thrdName +
" thread pid is " + std::to_string( tpid ) );
2252 thProp = pcf::IndiProperty( pcf::IndiProperty::Number );
2253 thProp.setDevice( configName() );
2254 thProp.setName( std::string(
"th-" ) + thrdName );
2255 thProp.setPerm( pcf::IndiProperty::ReadOnly );
2256 thProp.setState( pcf::IndiProperty::Idle );
2257 thProp.add( pcf::IndiElement(
"pid" ) );
2258 thProp[
"pid"] = tpid;
2259 thProp.add( pcf::IndiElement(
"prio" ) );
2260 thProp[
"prio"] = thrdPrio;
2261 registerIndiPropertyReadOnly( thProp );
2267 std::string cpuFile = m_cpusetPath;
2268 cpuFile +=
"/" + cpuset;
2269 cpuFile +=
"/tasks";
2270 int wfd = open( cpuFile.c_str(), O_WRONLY );
2273 return log<
software_error, -1>( { __FILE__, __LINE__, errno,
"error from open for " + cpuFile } );
2277 snprintf( pids,
sizeof( pids ),
"%d", tpid );
2279 int w = write( wfd, pids, strnlen( pids,
sizeof( pids ) ) );
2280 if( w != (
int)strlen( pids ) )
2282 return log<
software_error, -1>( { __FILE__, __LINE__, errno,
"error on write" } );
2296 template <
bool _useINDI>
2302 template <
bool _useINDI>
2309 if( s == stateCodes::ERROR )
2311 if( s == stateCodes::FAILURE )
2314 log<state_change>( { m_state, s }, lvl );
2320 if( m_stateAlert != stateAlert && stateAlert ==
true )
2322 m_stateAlert = stateAlert;
2327 std::unique_lock<std::mutex>
lock( m_indiMutex,
2331 if(
lock.owns_lock() )
2334 pcf::IndiProperty::PropertyStateType stst =
INDI_IDLE;
2337 if( m_stateAlert ==
true )
2343 if( m_state == stateCodes::READY )
2345 else if( m_state == stateCodes::OPERATING || m_state == stateCodes::HOMING ||
2346 m_state == stateCodes::CONFIGURING )
2348 else if( m_state < stateCodes::NODEVICE )
2350 else if( m_state <= stateCodes::LOGGEDIN )
2352 else if( m_state == stateCodes::NOTHOMED || m_state == stateCodes::SHUTDOWN )
2356 updateIfChanged( m_indiP_state,
"state", stateCodes::codeText( m_state ), stst );
2360 template <
bool _useINDI>
2363 if( m_stateLogged > 0 )
2366 return m_stateLogged - 1;
2375 template <
bool _useINDI>
2378 if( m_stateAlert ==
false )
2380 m_stateAlert =
false;
2383 pcf::IndiProperty::PropertyStateType stst =
INDI_IDLE;
2385 if( m_state == stateCodes::READY )
2387 else if( m_state == stateCodes::OPERATING || m_state == stateCodes::HOMING || m_state == stateCodes::CONFIGURING )
2389 else if( m_state < stateCodes::NODEVICE )
2391 else if( m_state <= stateCodes::LOGGEDIN )
2393 else if( m_state == stateCodes::NOTHOMED || m_state == stateCodes::SHUTDOWN )
2396 updateIfChanged( m_indiP_state,
"state", stateCodes::codeText( m_state ), stst );
2405 template <
bool _useINDI>
2407 const std::string &propName,
2408 const std::string &label,
2409 const std::string &group )
2411 prop = pcf::IndiProperty( pcf::IndiProperty::Text );
2412 prop.setDevice( configName() );
2413 prop.setName( propName );
2414 prop.setPerm( pcf::IndiProperty::ReadWrite );
2415 prop.setState( pcf::IndiProperty::Idle );
2416 prop.add( pcf::IndiElement(
"current" ) );
2417 prop.add( pcf::IndiElement(
"target" ) );
2422 prop.setLabel( label );
2427 prop.setGroup( group );
2433 template <
bool _useINDI>
2435 const std::string &propName,
2436 const std::string &elName,
2437 const std::string &propLabel,
2438 const std::string &propGroup,
2439 const std::string &elLabel )
2441 prop = pcf::IndiProperty( pcf::IndiProperty::Text );
2442 prop.setDevice( configName() );
2443 prop.setName( propName );
2444 prop.setPerm( pcf::IndiProperty::ReadOnly );
2445 prop.setState( pcf::IndiProperty::Idle );
2448 if( propLabel !=
"" )
2450 prop.setLabel( propLabel );
2453 if( propGroup !=
"" )
2455 prop.setGroup( propGroup );
2458 prop.add( pcf::IndiElement( elName ) );
2462 prop[elName].setLabel( elLabel );
2468 template <
bool _useINDI>
2469 template <
typename T>
2471 const std::string &name,
2475 const std::string &format,
2476 const std::string &label,
2477 const std::string &group )
2479 prop = pcf::IndiProperty( pcf::IndiProperty::Number );
2480 prop.setDevice( configName() );
2481 prop.setName( name );
2482 prop.setPerm( pcf::IndiProperty::ReadWrite );
2483 prop.setState( pcf::IndiProperty::Idle );
2484 prop.add( pcf::IndiElement(
"current" ) );
2485 prop[
"current"].setMin( min );
2486 prop[
"current"].setMax( max );
2487 prop[
"current"].setStep( step );
2490 prop[
"current"].setFormat( format );
2493 prop.add( pcf::IndiElement(
"target" ) );
2494 prop[
"target"].setMin( min );
2495 prop[
"target"].setMax( max );
2496 prop[
"target"].setStep( step );
2499 prop[
"target"].setFormat( format );
2505 prop.setLabel( label );
2510 prop.setGroup( group );
2516 template <
bool _useINDI>
2518 const std::string &propName,
2519 const std::string &propLabel,
2520 const std::string &propGroup )
2522 prop = pcf::IndiProperty( pcf::IndiProperty::Number );
2523 prop.setDevice( configName() );
2524 prop.setName( propName );
2525 prop.setPerm( pcf::IndiProperty::ReadOnly );
2526 prop.setState( pcf::IndiProperty::Idle );
2529 if( propLabel !=
"" )
2531 prop.setLabel( propLabel );
2534 if( propGroup !=
"" )
2536 prop.setGroup( propGroup );
2542 template <
bool _useINDI>
2544 const std::string &name,
2545 const std::string &label,
2546 const std::string &group )
2548 prop = pcf::IndiProperty( pcf::IndiProperty::Switch );
2549 prop.setDevice( configName() );
2550 prop.setName( name );
2551 prop.setPerm( pcf::IndiProperty::ReadWrite );
2552 prop.setState( pcf::IndiProperty::Idle );
2553 prop.setRule( pcf::IndiProperty::AtMostOne );
2556 prop.add( pcf::IndiElement(
"toggle", pcf::IndiElement::Off ) );
2561 prop.setLabel( label );
2566 prop.setGroup( group );
2572 template <
bool _useINDI>
2574 const std::string &name,
2575 const std::string &label,
2576 const std::string &group )
2578 prop = pcf::IndiProperty( pcf::IndiProperty::Switch );
2579 prop.setDevice( configName() );
2580 prop.setName( name );
2581 prop.setPerm( pcf::IndiProperty::ReadWrite );
2582 prop.setState( pcf::IndiProperty::Idle );
2583 prop.setRule( pcf::IndiProperty::AtMostOne );
2586 prop.add( pcf::IndiElement(
"request", pcf::IndiElement::Off ) );
2591 prop.setLabel( label );
2596 prop.setGroup( group );
2602 template <
bool _useINDI>
2604 const std::string &name,
2605 const std::vector<std::string> &elements,
2606 const std::vector<std::string> &elementLabels,
2607 const std::string &label,
2608 const std::string &group )
2610 if( elements.size() == 0 )
2612 return log<
software_error, -1>( { __FILE__, __LINE__,
"elements vector has zero size" } );
2615 prop = pcf::IndiProperty( pcf::IndiProperty::Switch );
2616 prop.setDevice( configName() );
2617 prop.setName( name );
2618 prop.setPerm( pcf::IndiProperty::ReadWrite );
2619 prop.setState( pcf::IndiProperty::Idle );
2620 prop.setRule( pcf::IndiProperty::OneOfMany );
2623 for(
size_t n = 0; n < elements.size(); ++n )
2625 pcf::IndiElement elem = pcf::IndiElement( elements[n], pcf::IndiElement::Off );
2626 elem.setLabel( elementLabels[n] );
2633 prop.setLabel( label );
2638 prop.setGroup( group );
2644 template <
bool _useINDI>
2646 const std::string &name,
2647 const std::vector<std::string> &elements,
2648 const std::string &label,
2649 const std::string &group )
2651 return createStandardIndiSelectionSw( prop, name, elements, elements, label, group );
2654 template <
bool _useINDI>
2661 m_indiNewCallBacks.insert(
callBackValueType( prop.createUniqueKey(), { &prop, nullptr } ) );
2665 if( !result.second )
2668 { __FILE__, __LINE__,
"failed to insert INDI property: " + prop.createUniqueKey() } );
2671 catch( std::exception &e )
2673 return log<
software_error, -1>( { __FILE__, __LINE__, std::string(
"Exception caught: " ) + e.what() } );
2677 return log<
software_error, -1>( { __FILE__, __LINE__,
"Unknown exception caught." } );
2683 template <
bool _useINDI>
2685 const std::string &propName,
2686 const pcf::IndiProperty::Type &
propType,
2687 const pcf::IndiProperty::PropertyPermType &propPerm,
2688 const pcf::IndiProperty::PropertyStateType &propState )
2693 prop = pcf::IndiProperty(
propType );
2694 prop.setDevice( m_configName );
2695 prop.setName( propName );
2696 prop.setPerm( propPerm );
2697 prop.setState( propState );
2703 if( !result.second )
2706 { __FILE__, __LINE__,
"failed to insert INDI property: " + prop.createUniqueKey() } );
2709 catch( std::exception &e )
2711 return log<
software_error, -1>( { __FILE__, __LINE__, std::string(
"Exception caught: " ) + e.what() } );
2715 return log<
software_error, -1>( { __FILE__, __LINE__,
"Unknown exception caught." } );
2720 template <
bool _useINDI>
2722 int ( *callBack )(
void *,
const pcf::IndiProperty &
ipRecv ) )
2729 callBackInsertResult result =
2730 m_indiNewCallBacks.insert( callBackValueType( prop.createUniqueKey(), { &prop, callBack } ) );
2732 if( !result.second )
2735 { __FILE__, __LINE__,
"failed to insert INDI property: " + prop.createUniqueKey() } );
2738 catch( std::exception &e )
2740 return log<
software_error, -1>( { __FILE__, __LINE__, std::string(
"Exception caught: " ) + e.what() } );
2744 return log<
software_error, -1>( { __FILE__, __LINE__,
"Unknown exception caught." } );
2750 template <
bool _useINDI>
2751 int MagAOXApp<_useINDI>::registerIndiPropertyNew( pcf::IndiProperty &prop,
2752 const std::string &propName,
2753 const pcf::IndiProperty::Type &
propType,
2754 const pcf::IndiProperty::PropertyPermType &propPerm,
2755 const pcf::IndiProperty::PropertyStateType &propState,
2756 int ( *callBack )(
void *,
const pcf::IndiProperty &
ipRecv ) )
2761 prop = pcf::IndiProperty(
propType );
2762 prop.setDevice( m_configName );
2763 prop.setName( propName );
2764 prop.setPerm( propPerm );
2765 prop.setState( propState );
2767 return registerIndiPropertyNew( prop, callBack );
2770 template <
bool _useINDI>
2771 int MagAOXApp<_useINDI>::registerIndiPropertyNew( pcf::IndiProperty &prop,
2772 const std::string &propName,
2773 const pcf::IndiProperty::Type &
propType,
2774 const pcf::IndiProperty::PropertyPermType &propPerm,
2775 const pcf::IndiProperty::PropertyStateType &propState,
2776 const pcf::IndiProperty::SwitchRuleType &propRule,
2777 int ( *callBack )(
void *,
const pcf::IndiProperty &
ipRecv ) )
2782 prop = pcf::IndiProperty(
propType );
2783 prop.setDevice( m_configName );
2784 prop.setName( propName );
2785 prop.setPerm( propPerm );
2786 prop.setState( propState );
2787 prop.setRule( propRule );
2788 return registerIndiPropertyNew( prop, callBack );
2791 template <
bool _useINDI>
2793 const std::string &devName,
2794 const std::string &propName,
2795 int ( *callBack )(
void *,
const pcf::IndiProperty &
ipRecv ) )
2800 prop = pcf::IndiProperty();
2801 prop.setDevice( devName );
2802 prop.setName( propName );
2805 m_indiSetCallBacks.insert(
callBackValueType( prop.createUniqueKey(), { &prop, callBack } ) );
2809 if( !result.second )
2812 { __FILE__, __LINE__,
"failed to insert INDI property: " + prop.createUniqueKey() } );
2815 catch( std::exception &e )
2817 return log<
software_error, -1>( { __FILE__, __LINE__, std::string(
"Exception caught: " ) + e.what() } );
2821 return log<
software_error, -1>( { __FILE__, __LINE__,
"Unknown exception caught." } );
2827 template <
bool _useINDI>
2835 driverFIFOPath +=
"/";
2838 m_driverInName = driverFIFOPath +
"/" + configName() +
".in";
2839 m_driverOutName = driverFIFOPath +
"/" + configName() +
".out";
2840 m_driverCtrlName = driverFIFOPath +
"/" + configName() +
".ctrl";
2846 mode_t prev = umask( 0 );
2849 if( mkfifo( m_driverInName.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP ) != 0 )
2851 if( errno != EEXIST )
2854 log<software_critical>( { __FILE__, __LINE__, errno, 0,
"mkfifo failed" } );
2861 if( mkfifo( m_driverOutName.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP ) != 0 )
2863 if( errno != EEXIST )
2867 log<software_critical>( { __FILE__, __LINE__, errno, 0,
"mkfifo failed" } );
2874 if( mkfifo( m_driverCtrlName.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP ) != 0 )
2876 if( errno != EEXIST )
2880 log<software_critical>( { __FILE__, __LINE__, errno, 0,
"mkfifo failed" } );
2891 template <
bool _useINDI>
2898 if( createINDIFIFOS() < 0 )
2906 if( m_indiDriver !=
nullptr )
2908 m_indiDriver->quitProcess();
2909 m_indiDriver->deactivate();
2910 log<indidriver_stop>();
2911 delete m_indiDriver;
2912 m_indiDriver =
nullptr;
2919 log<software_critical>( { __FILE__, __LINE__, 0, 0,
"INDI Driver construction exception." } );
2924 if( m_indiDriver ==
nullptr )
2926 log<software_critical>( { __FILE__, __LINE__, 0, 0,
"INDI Driver construction failed." } );
2931 if( m_indiDriver->good() ==
false )
2933 log<software_critical>( { __FILE__, __LINE__, 0, 0,
"INDI Driver failed to open FIFOs." } );
2934 delete m_indiDriver;
2935 m_indiDriver =
nullptr;
2940 m_indiDriver->activate();
2941 log<indidriver_start>();
2943 sendGetPropertySetList(
true );
2948 template <
bool _useINDI>
2952 if( !all && m_allDefsReceived )
2958 while(
it != m_indiSetCallBacks.end() )
2960 if( all ||
it->second.m_defReceived ==
false )
2962 if(
it->second.property )
2966 m_indiDriver->sendGetProperties( *(
it->second.property ) );
2968 catch(
const std::exception &e )
2970 log<software_error>( { __FILE__,
2972 "exception caught from sendGetProperties for " +
2973 it->second.property->getName() +
": " + e.what() } );
2977 it->second.m_defReceived =
false;
2983 m_allDefsReceived =
false;
2985 m_allDefsReceived =
true;
2988 template <
bool _useINDI>
2991 handleSetProperty(
ipRecv );
2994 template <
bool _useINDI>
2999 if( m_indiDriver ==
nullptr )
3003 if(
ipRecv.hasValidDevice() &&
ipRecv.getDevice() != m_indiDriver->getName() )
3009 if( !
ipRecv.hasValidName() )
3013 while(
it != m_indiNewCallBacks.end() )
3015 if(
it->second.property )
3019 m_indiDriver->sendDefProperty( *(
it->second.property ) );
3021 catch(
const std::exception &e )
3023 log<software_error>( { __FILE__,
3025 "exception caught from sendDefProperty for " +
3026 it->second.property->getName() +
": " + e.what() } );
3033 sendGetPropertySetList(
true );
3039 if( m_indiNewCallBacks.count(
ipRecv.createUniqueKey() ) == 0 )
3045 if( m_indiNewCallBacks[
ipRecv.createUniqueKey()].property )
3049 m_indiDriver->sendDefProperty( *( m_indiNewCallBacks[
ipRecv.createUniqueKey()].property ) );
3051 catch(
const std::exception &e )
3053 log<software_error>( { __FILE__,
3055 "exception caught from sendDefProperty for " +
3056 m_indiNewCallBacks[
ipRecv.createUniqueKey()].property->getName() +
": " +
3063 template <
bool _useINDI>
3068 if( m_indiDriver ==
nullptr )
3072 if( m_indiNewCallBacks.count(
ipRecv.createUniqueKey() ) == 0 )
3074 log<software_debug>( { __FILE__, __LINE__,
"invalid NewProperty request for " +
ipRecv.createUniqueKey() } );
3078 int ( *callBack )(
void *,
const pcf::IndiProperty & ) = m_indiNewCallBacks[
ipRecv.createUniqueKey()].callBack;
3081 callBack(
this,
ipRecv );
3083 log<software_debug>( { __FILE__, __LINE__,
"NewProperty callback null for " +
ipRecv.createUniqueKey() } );
3088 template <
bool _useINDI>
3093 if( m_indiDriver ==
nullptr )
3096 std::string key =
ipRecv.createUniqueKey();
3099 if( m_indiSetCallBacks.count( key ) > 0 )
3101 m_indiSetCallBacks[key].m_defReceived =
true;
3104 int ( *callBack )(
void *,
const pcf::IndiProperty & ) = m_indiSetCallBacks[key].callBack;
3106 callBack(
this,
ipRecv );
3118 template <
bool _useINDI>
3119 template <
typename T>
3121 const std::string &el,
3123 pcf::IndiProperty::PropertyStateType ipState )
3134 template <
bool _useINDI>
3136 const std::string &el,
3138 pcf::IndiProperty::PropertyStateType ipState )
3140 updateIfChanged<std::string>( p, el, std::string( newVal ), ipState );
3143 template <
bool _useINDI>
3145 const std::string &el,
3146 const pcf::IndiElement::SwitchStateType &newVal,
3147 pcf::IndiProperty::PropertyStateType ipState )
3158 template <
bool _useINDI>
3159 template <
typename T>
3161 const std::string &el,
3162 const std::vector<T> &newVals,
3163 pcf::IndiProperty::PropertyStateType ipState )
3171 std::vector<std::string> descriptors( newVals.size(), el );
3172 for(
size_t index = 0; index < newVals.size(); ++index )
3174 descriptors[index] += std::to_string( index );
3179 template <
bool _useINDI>
3180 template <
typename T>
3182 const std::vector<std::string> &els,
3183 const std::vector<T> &newVals,
3184 pcf::IndiProperty::PropertyStateType newState )
3195 template <
bool _useINDI>
3196 template <
typename T>
3199 const pcf::IndiProperty &remoteProperty,
3202 if( remoteProperty.createUniqueKey() != localProperty.createUniqueKey() )
3207 if( !( remoteProperty.find(
"target" ) || remoteProperty.find(
"current" ) ) )
3214 if( remoteProperty.find(
"target" ) )
3216 localTarget = remoteProperty[
"target"].get<T>();
3222 if( remoteProperty.find(
"current" ) )
3224 localTarget = remoteProperty[
"current"].get<T>();
3248 template <
typename T>
3251 return pcf::IndiProperty::Unknown;
3258 pcf::IndiProperty::Type propType<std::string>();
3266 template <
bool _useINDI>
3267 template <
typename T>
3275 log<software_error>( { __FILE__, __LINE__,
"INDI communications not initialized." } );
3278 pcf::IndiProperty ipToSend = ipSend;
3282 ipToSend[el].setValue( newVal );
3286 log<software_error>(
3287 { __FILE__, __LINE__,
"Exception caught setting " + ipSend.createUniqueKey() +
"." + el } );
3294 log<software_error>( { __FILE__, __LINE__ } );
3301 template <
bool _useINDI>
3309 return log<
software_error, -1>( { __FILE__, __LINE__,
"INDI communications not initialized." } );
3312 if( m_indiDriver->sendNewProperty( ipSend ) < 0 )
3320 template <
bool _useINDI>
3326 pcf::IndiProperty ipSend( pcf::IndiProperty::Switch );
3330 ipSend.setDevice( device );
3331 ipSend.setName( property );
3332 ipSend.add( pcf::IndiElement(
"toggle" ) );
3334 catch( std::exception &e )
3336 return log<
software_error, -1>( { __FILE__, __LINE__, std::string(
"exception: " ) + e.what() } );
3339 if( onoff ==
false )
3341 ipSend[
"toggle"].setSwitchState( pcf::IndiElement::Off );
3345 ipSend[
"toggle"].setSwitchState( pcf::IndiElement::On );
3348 if( sendNewProperty( ipSend ) < 0 )
3351 { __FILE__, __LINE__,
"sendNewProperty failed for " + device +
"." +
property } );
3357 template <
bool _useINDI>
3363 template <
bool _useINDI>
3367 if(
ipRecv.createUniqueKey() != m_indiP_clearFSMAlert.createUniqueKey() )
3369 return log<
software_error, -1>( { __FILE__, __LINE__,
"wrong indi property received" } );
3372 if( !
ipRecv.find(
"request" ) )
3375 if(
ipRecv[
"request"].getSwitchState() == pcf::IndiElement::On )
3384 template <
bool _useINDI>
3390 template <
bool _useINDI>
3396 template <
bool _useINDI>
3399 if( !m_powerMgtEnabled || m_powerOnWait == 0 || m_powerOnCounter < 0 )
3402 if( m_powerOnCounter * m_loopPause > ( (
double)m_powerOnWait ) * 1e9 )
3413 template <
bool _useINDI>
3416 if( !m_powerMgtEnabled )
3419 return m_powerState;
3422 template <
bool _useINDI>
3425 if( !m_powerMgtEnabled )
3428 return m_powerTargetState;
3431 template <
bool _useINDI>
3439 ps =
ipRecv[m_powerElement].get<std::string>();
3445 else if( ps ==
"Off" )
3457 ps =
ipRecv[m_powerTargetElement].get<std::string>();
3461 m_powerTargetState = 1;
3463 else if( ps ==
"Off" )
3465 m_powerTargetState = 0;
3469 m_powerTargetState = -1;
3476 template <
bool _useINDI>
3479 return m_configName;
3482 template <
bool _useINDI>
3488 template <
bool _useINDI>
3491 return m_driverInName;
3494 template <
bool _useINDI>
3497 return m_driverOutName;
3500 template <
bool _useINDI>
3503 return m_driverCtrlName;
3527 #define XWCAPP_THREAD_START( thrdSt, thrdInit, thrdId, thrdProp, thrdPrio, thrdCpuset, thrdName, thrdStart ) \
3528 if( threadStart( thrdSt, thrdInit, thrdId, thrdProp, thrdPrio, thrdCpuset, thrdName, this, thrdStart ) < 0 ) \
3530 log<software_error>( { __FILE__, __LINE__, "error from threadStart for " #thrdName } ); \
3541 #define XWCAPP_THREAD_CHECK( thrdSt, thrdName ) \
3544 if( pthread_tryjoin_np( thrdSt.native_handle(), 0 ) == 0 ) \
3546 log<software_error>( { __FILE__, __LINE__, #thrdName " thread has exited" } ); \
3552 log<software_error>( { __FILE__, __LINE__, #thrdName " thread has exited" } ); \
3561 #define XWCAPP_THREAD_STOP( thrdSt ) \
3562 if( thrdSt.joinable() ) \
3564 pthread_kill( thrdSt.native_handle(), SIGUSR1 ); \
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::string driverCtrlName()
Get the INDI control FIFO file name.
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.
std::unordered_map< std::string, indiCallBack > m_indiNewCallBacks
Map to hold the NewProperty indiCallBacks for this App, with fast lookup by property name.
int setEuidReal()
Set the effective user ID to the real value, i.e. the file owner.
void updateIfChanged(pcf::IndiProperty &p, const std::vector< std::string > &els, const std::vector< T > &newVals, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update an INDI property if values have changed.
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="")
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.
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.
std::pair< callBackIterator, bool > callBackInsertResult
Return type of insert on the indiCallBack map.
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.
int setEuidCalled()
Set the effective user ID to the called value, i.e. the highest possible.
std::unordered_map< std::string, indiCallBack > m_indiSetCallBacks
Map to hold the SetProperty indiCallBacks for this App, with fast lookup by property name.
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.
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 >()
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 >()
const pcf::IndiProperty & ipRecv
pcf::IndiProperty::Type propType()
std::unique_lock< std::mutex > lock(m_indiMutex)
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.