7 #ifndef observerCtrl_hpp
8 #define observerCtrl_hpp
12 #include "../../libMagAOX/libMagAOX.hpp"
13 #include "../../magaox_git_version.h"
165 config.add(
"stream.writers",
"",
"stream.writers", argType::Required,
"stream",
"writers",
false,
"string",
"The device names of the stream writers to control.");
174 std::vector<std::string> sections;
176 _config.unusedSections(sections);
178 if( sections.size() == 0 )
184 for(
size_t i=0; i< sections.size(); ++i)
186 bool pfoaSet = _config.isSetUnused(mx::app::iniFile::makeKey(sections[i],
"pfoa" ));
187 if( !pfoaSet )
continue;
189 std::string email = sections[i];
192 _config.configUnused(pfoa, mx::app::iniFile::makeKey(sections[i],
"pfoa" ));
194 std::string fullName;
195 _config.configUnused(fullName, mx::app::iniFile::makeKey(sections[i],
"full_name" ));
197 std::string institution;
198 _config.configUnused(institution, mx::app::iniFile::makeKey(sections[i],
"institution" ));
200 std::string sanitizedEmail =
"";
201 for(
size_t n = 0; n < email.size(); ++n)
205 sanitizedEmail = sanitizedEmail +
"-at-";
207 else if(email[n] ==
'.')
209 sanitizedEmail = sanitizedEmail +
"-dot-";
213 sanitizedEmail.push_back(email[n]);
242 std::vector<std::string> sanitizedEmails;
243 std::vector<std::string> emails;
246 sanitizedEmails.push_back(
it->second.m_sanitizedEmail);
247 emails.push_back(
it->second.m_email);
252 log<software_critical>({__FILE__, __LINE__});
260 if(
it.first.find(
"jrmales") != std::string::npos)
273 log<software_critical>({__FILE__, __LINE__});
280 log<software_critical>({__FILE__, __LINE__});
287 log<software_critical>({__FILE__, __LINE__});
297 m_indiP_sws = pcf::IndiProperty(pcf::IndiProperty::Switch);
311 log<software_critical>({__FILE__, __LINE__});
326 log<software_critical>({__FILE__, __LINE__});
361 log<software_error>({__FILE__, __LINE__});
382 pcf::IndiProperty ip(pcf::IndiProperty::Switch);
385 ip.setName(
"writing");
386 ip.add(pcf::IndiElement(
"toggle"));
387 ip[
"toggle"].setSwitchState(pcf::IndiElement::On);
408 pcf::IndiProperty ip(pcf::IndiProperty::Switch);
411 ip.setName(
"writing");
412 ip.add(pcf::IndiElement(
"toggle"));
413 ip[
"toggle"].setSwitchState(pcf::IndiElement::Off);
428 std::string newEmail =
"";
429 for(
auto it=m_observers.begin();
it != m_observers.end(); ++
it)
431 if(!
ipRecv.find(
it->second.m_sanitizedEmail))
continue;
433 if(
ipRecv[
it->second.m_sanitizedEmail].getSwitchState() == pcf::IndiElement::On)
441 newEmail =
it->first;
451 std::unique_lock<std::mutex>
lock(m_indiMutex);
453 m_currentObserver = m_observers[newEmail];
455 for(
auto it = m_observers.begin();
it!=m_observers.end();++
it)
461 log<logger::observer>({m_currentObserver.m_fullName,m_currentObserver.m_pfoa, m_currentObserver.m_email, m_currentObserver.m_institution});
472 std::unique_lock<std::mutex>
lock(m_indiMutex);
474 if( indiTargetUpdate( m_indiP_obsName, target,
ipRecv,
true) < 0)
476 log<software_error>({__FILE__,__LINE__});
489 if(!
ipRecv.find(
"toggle"))
return 0;
491 std::unique_lock<std::mutex>
lock(m_indiMutex);
493 recordObserver(
true);
494 if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::On)
499 else if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::Off)
512 if(m_observing ==
true)
518 for(
size_t n =0; n < m_streamWriters.size(); ++n)
520 if(!
ipRecv.find(m_streamWriters[n]))
continue;
539 email =
ipRecv[
"email"].get();
542 if(
ipRecv.find(
"message"))
544 message =
ipRecv[
"message"].get();
554 email = m_currentObserver.m_email;
562 if(
ipRecv.find(
"time_ns"))
573 log<user_log>({email, message});
594 static std::string last_email;
595 static std::string last_obsName;
596 static bool last_observing;
The base-class for MagAO-X applications.
void updateIfChanged(pcf::IndiProperty &p, const std::string &el, const T &newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI property element value if it has changed.
stateCodes::stateCodeT state()
Get the current state code.
int registerIndiPropertyNew(pcf::IndiProperty &prop, int(*)(void *, const pcf::IndiProperty &))
Register an INDI property which is exposed for others to request a New Property for.
int createStandardIndiToggleSw(pcf::IndiProperty &prop, const std::string &name, const std::string &label="", const std::string &group="")
Create a standard R/W INDI switch with a single toggle element.
int m_shutdown
Flag to signal it's time to shutdown. When not 0, the main loop exits.
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.
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
std::mutex m_indiMutex
Mutex for locking INDI communications.
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.
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.
The MagAO-X Observer Controller.
pcf::IndiProperty m_indiP_observer
pcf::IndiProperty m_indiP_obsName
int recordTelem(const telem_observer *)
std::string m_sanitizedEmail
virtual int appLogic()
Implementation of the FSM for observerCtrl.
INDI_NEWCALLBACK_DECL(observerCtrl, m_indiP_observing)
pcf::IndiProperty m_indiP_observers
int recordObserver(bool force=false)
std::string m_institution
INDI_NEWCALLBACK_DECL(observerCtrl, m_indiP_sws)
~observerCtrl() noexcept
D'tor, declared and defined for noexcept.
INDI_NEWCALLBACK_DECL(observerCtrl, m_indiP_obsName)
INDI_NEWCALLBACK_DECL(observerCtrl, m_indiP_observers)
virtual void loadConfig()
std::vector< std::string > m_streamWriters
The stream writers to stop and start.
virtual int appStartup()
Startup function.
INDI_NEWCALLBACK_DECL(observerCtrl, m_indiP_userlog)
pcf::IndiProperty m_indiP_userlog
pcf::IndiProperty m_indiP_observing
pcf::IndiProperty m_indiP_obslog
observerCtrl()
Default c'tor.
virtual int appShutdown()
Shutdown the app.
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
friend class observerCtrl_test
observer m_currentObserver
std::map< std::string, observer > observerMapT
pcf::IndiProperty m_indiP_sws
virtual void setupConfig()
#define REG_INDI_NEWPROP_NOCB(prop, propName, type)
Register a NEW INDI property with the class, with no callback.
#define INDI_NEWCALLBACK(prop)
Get the name of the static callback wrapper for a new property.
uint32_t secT
The type used for seconds.
@ READY
The device is ready for operation, but is not operating.
void updateSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, const pcf::IndiElement::SwitchStateType &newVal, indiDriverT *indiDriver, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update the value of the INDI element, but only if it has changed.
INDI_VALIDATE_CALLBACK_PROPS(function, ipRecv)
const pcf::IndiProperty & ipRecv
INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_windspeed)(const pcf
std::unique_lock< std::mutex > lock(m_indiMutex)
constexpr static logPrioT LOG_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.
uint32_t nanosecT
The type used for nanoseconds.
A device base class which saves telemetry.
int appShutdown()
Perform telemeter application shutdown.
int loadConfig(appConfigurator &config)
Load the device section from an application configurator.
int appLogic()
Perform telemeter application logic.
int setupConfig(appConfigurator &config)
Setup an application configurator for the device section.
int checkRecordTimes(const telT &tel, telTs... tels)
Check the time of the last record for each telemetry type and make an entry if needed.
Log entry recording the build-time git state.
A fixed-width timespec structure.