58 delete (watchdogClient);
74 if (ShutdownTriggerS[TRIGGER_CLIENT].s ==
ISS_ON && HeartBeatN[0].value > 0)
76 LOGF_INFO(
"Client Watchdog is enabled. Shutdown is triggered after %.f seconds of communication loss with the client.",
78 if (m_WatchDogTimer > 0)
80 m_WatchDogTimer =
SetTimer(HeartBeatN[0].value * 1000);
83 if (ShutdownTriggerS[TRIGGER_WEATHER].s ==
ISS_ON)
85 if (WeatherThresholdN[0].value > 0)
86 LOGF_INFO(
"Weather Watchdog is enabled. Shutdown is triggered %.f seconds after Weather status enters DANGER zone.",
87 WeatherThresholdN[0].value);
89 LOG_INFO(
"Weather Watchdog is enabled. Shutdown is triggered when Weather status in DANGER zone.");
92 IDSnoopDevice(ActiveDeviceT[ACTIVE_WEATHER].text,
"WEATHER_STATUS");
93 IDSnoopDevice(ActiveDeviceT[ACTIVE_TELESCOPE].text,
"TELESCOPE_PARK");
104 if (m_WatchDogTimer > 0)
107 m_WatchDogTimer = -1;
109 if (m_WeatherAlertTimer > 0)
112 m_WeatherAlertTimer = -1;
129 IUFillNumber(&HeartBeatN[0],
"WATCHDOG_HEARTBEAT_VALUE",
"Threshold (s)",
"%.f", 0, 3600, 60, 0);
134 IUFillNumber(&WeatherThresholdN[0],
"WATCHDOG_WEATHER_VALUE",
"Threshold (s)",
"%.f", 0, 3600, 60, 0);
139 IUFillText(&SettingsT[INDISERVER_HOST],
"INDISERVER_HOST",
"indiserver host",
"localhost");
140 IUFillText(&SettingsT[INDISERVER_PORT],
"INDISERVER_PORT",
"indiserver port",
"7624");
141 IUFillText(&SettingsT[SHUTDOWN_SCRIPT],
"SHUTDOWN_SCRIPT",
"shutdown script",
nullptr);
165 IUFillText(&ActiveDeviceT[ACTIVE_TELESCOPE],
"ACTIVE_TELESCOPE",
"Telescope",
"Telescope Simulator");
166 IUFillText(&ActiveDeviceT[ACTIVE_DOME],
"ACTIVE_DOME",
"Dome",
"Dome Simulator");
167 IUFillText(&ActiveDeviceT[ACTIVE_WEATHER],
"ACTIVE_WEATHER",
"Weather",
"Weather Simulator");
200 if (!strcmp(SettingsTP.
name, name))
208 m_INDIServerPort = std::stoi(SettingsT[INDISERVER_PORT].text);
221 if (!strcmp(ActiveDeviceTP.
name, name))
223 if (watchdogClient->
isBusy())
227 LOG_ERROR(
"Cannot change devices names while shutdown is in progress...");
231 IDSnoopDevice(ActiveDeviceT[ACTIVE_WEATHER].text,
"WEATHER_STATUS");
232 IDSnoopDevice(ActiveDeviceT[ACTIVE_TELESCOPE].text,
"TELESCOPE_PARK");
253 if (!strcmp(WeatherThresholdNP.
name, name))
264 else if (!strcmp(HeartBeatNP.
name, name))
266 double prevHeartBeat = HeartBeatN[0].value;
268 if (watchdogClient->
isBusy())
272 LOG_ERROR(
"Cannot change heart beat while shutdown is in progress...");
280 if (ShutdownTriggerS[TRIGGER_CLIENT].s ==
ISS_OFF)
282 if (m_WatchDogTimer > 0)
285 m_WatchDogTimer = -1;
291 if (HeartBeatN[0].value == 0)
292 LOG_INFO(
"Client Watchdog is disabled.");
295 if (prevHeartBeat != HeartBeatN[0].value)
296 LOGF_INFO(
"Client Watchdog is enabled. Shutdown is triggered after %.f seconds of communication loss with the client.",
297 HeartBeatN[0].value);
299 LOG_DEBUG(
"Received heart beat from client.");
301 if (m_WatchDogTimer > 0)
304 m_WatchDogTimer = -1;
307 m_WatchDogTimer =
SetTimer(HeartBeatN[0].value * 1000);
326 if (!strcmp(ShutdownProcedureSP.
name, name))
333 LOG_ERROR(
"Error: shutdown script file is not set.");
338 ShutdownProcedureSP.
s =
IPS_OK;
343 else if (!strcmp(MountPolicySP.
name, name))
349 LOG_INFO(
"Mount is ignored. Dome can start parking without waiting for mount to complete parking.");
351 LOG_INFO(
"Mount locks. Dome must wait for mount to park before it can start the parking procedure.");
356 else if (!strcmp(ShutdownTriggerSP.
name, name))
358 std::vector<ISState> oldStates(ShutdownTriggerSP.
nsp,
ISS_OFF);
359 std::vector<ISState> newStates(ShutdownTriggerSP.
nsp,
ISS_OFF);
360 for (
int i = 0; i < ShutdownTriggerSP.
nsp; i++)
361 oldStates[i] = ShutdownTriggerS[i].s;
363 for (
int i = 0; i < ShutdownTriggerSP.
nsp; i++)
364 newStates[i] = ShutdownTriggerS[i].s;
368 if (oldStates[TRIGGER_CLIENT] != newStates[TRIGGER_CLIENT])
371 if (newStates[TRIGGER_CLIENT] ==
ISS_OFF)
373 LOG_INFO(
"Disabling client watchdog. Lost communication with client shall not trigger the shutdown procedure.");
374 if (m_WatchDogTimer > 0)
377 m_WatchDogTimer = -1;
384 if (HeartBeatN[0].value == 0)
386 LOG_ERROR(
"Heart beat timeout should be set first.");
388 for (
int i = 0; i < ShutdownTriggerSP.
nsp; i++)
389 ShutdownTriggerS[i].s = oldStates[i];
394 LOGF_INFO(
"Client Watchdog is enabled. Shutdown is triggered after %.f seconds of communication loss with the client.",
395 HeartBeatN[0].value);
396 if (m_WatchDogTimer > 0)
398 m_WatchDogTimer =
SetTimer(HeartBeatN[0].value * 1000);
403 if (oldStates[TRIGGER_WEATHER] != newStates[TRIGGER_WEATHER])
406 if (newStates[TRIGGER_WEATHER] ==
ISS_OFF)
409 if (m_WeatherAlertTimer > 0)
412 m_WeatherAlertTimer = -1;
415 LOG_INFO(
"Weather Watchdog is disabled.");
419 IDSnoopDevice(ActiveDeviceT[ACTIVE_WEATHER].text,
"WEATHER_STATUS");
420 LOG_INFO(
"Weather Watchdog is enabled.");
442 if (!strcmp(
"WEATHER_STATUS", propName))
451 LOG_INFO(
"Weather status is no longer in DANGER zone.");
452 if (m_WeatherAlertTimer > 0)
454 LOG_INFO(
"Shutdown procedure cancelled.");
456 m_WeatherAlertTimer = -1;
467 LOG_WARN(
"Weather is in DANGER zone.");
468 if (ShutdownTriggerS[TRIGGER_WEATHER].s ==
ISS_ON && m_WeatherAlertTimer == -1)
470 if (WeatherThresholdN[0].value > 0)
471 LOGF_INFO(
"Shutdown procedure shall commence in %.f seconds unless weather status improves.", WeatherThresholdN[0].value);
472 m_WeatherAlertTimer =
SetTimer(WeatherThresholdN[0].value * 1000);
476 m_WeatherState = newWeatherState;
479 else if (!strcmp(
"TELESCOPE_PARK", propName))
489 if ((!strcmp(elemName,
"PARK") && !strcmp(
pcdataXMLEle(ep),
"On")))
491 else if ((!strcmp(elemName,
"UNPARK") && !strcmp(
pcdataXMLEle(ep),
"On")))
494 if (parked != m_IsMountParked)
496 LOGF_INFO(
"Mount is %s", parked ?
"Parked" :
"Unparked");
497 m_IsMountParked = parked;
501 if (parked ==
false &&
502 ShutdownTriggerS[TRIGGER_WEATHER].s ==
ISS_ON &&
506 LOG_WARN(
"Mount unparked while weather alert is active! Parking mount...");
514 else if (!strcmp(
"DOME_PARK", propName))
524 if ((!strcmp(elemName,
"PARK") && !strcmp(
pcdataXMLEle(ep),
"On")))
526 else if ((!strcmp(elemName,
"UNPARK") && !strcmp(
pcdataXMLEle(ep),
"On")))
529 if (parked != m_IsDomeParked)
531 LOGF_INFO(
"Dome is %s", parked ?
"Parked" :
"Unparked");
532 m_IsDomeParked = parked;
536 if (parked ==
false &&
537 ShutdownTriggerS[TRIGGER_WEATHER].s ==
ISS_ON &&
541 LOG_WARN(
"Dome unparked while weather alert is active! Parking dome...");
582 switch (m_ShutdownStage)
591 LOG_WARN(
"Warning! Weather status in DANGER zone, executing shutdown procedure...");
593 LOG_WARN(
"Warning! Heartbeat threshold timed out, executing shutdown procedure...");
605 watchdogClient->
setMount(ActiveDeviceT[ACTIVE_TELESCOPE].text);
608 watchdogClient->
setDome(ActiveDeviceT[ACTIVE_DOME].text);
611 watchdogClient->
setServer(SettingsT[INDISERVER_HOST].text, m_INDIServerPort);
613 LOG_DEBUG(
"Connecting to INDI server...");
625 LOGF_DEBUG(
"Connected to INDI server %s @ %s", SettingsT[0].text,
636 LOG_DEBUG(
"Waiting for INDI server connection...");
676 LOG_INFO(
"Shutdown procedure complete.");
677 ShutdownProcedureSP.
s =
IPS_OK;
696 void WatchDog::parkDome()
698 if (watchdogClient->
parkDome() ==
false)
700 LOG_ERROR(
"Error: Unable to park dome! Shutdown procedure terminated.");
709 void WatchDog::parkMount()
711 if (watchdogClient->
parkMount() ==
false)
713 LOG_ERROR(
"Error: Unable to park mount! Shutdown procedure terminated.");
728 void WatchDog::executeScript()
743 LOGF_INFO(
"Waiting for script with PID %d to complete...", getpid());
745 if (WIFEXITED(statval))
747 int exit_code = WEXITSTATUS(statval);
748 LOGF_INFO(
"Script complete with exit code %d", exit_code);
754 LOGF_ERROR(
"Error: script %s failed. Shutdown procedure terminated.",
763 "Error: script %s did not terminate with exit. Shutdown procedure terminated.",
void setServer(const char *hostname, unsigned int port)
Set the server host name and port.
bool connectServer() override
Connect to INDI server.
const char * getDeviceName() const
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
void defineProperty(INumberVectorProperty *property)
virtual bool saveConfigItems(FILE *fp)
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
virtual bool initProperties()
Initilize properties initial state and value. The child class must implement this function.
void setDriverInterface(uint16_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
void RemoveTimer(int id)
Remove timer added with SetTimer.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
void addDebugControl()
Add Debug control to the driver.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process the client newSwitch command.
IPState getDomeParkState()
IPState getMountParkState()
void setMount(const std::string &value)
void setDome(const std::string &value)
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual bool Disconnect() override
Disconnect from device.
virtual bool ISSnoopDevice(XMLEle *root) override
Process a snoop event from INDI server. This function is called when a snooped property is updated in...
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
virtual const char * getDefaultName() override
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool Connect() override
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
@ WATCHDOG_CLIENT_STARTED
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Update the value of an existing switch vector property.
void ISGetProperties(const char *dev)
Get Device Properties.
void ISSnoopDevice(XMLEle *root)
Function defined by Drivers that is called when another Driver it is snooping (by having previously c...
void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL.
void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL.
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
void IUFillSwitch(ISwitch *sp, const char *name, const char *label, ISState s)
Assign attributes for a switch property. The switch's auxiliary elements will be set to NULL.
void IUFillText(IText *tp, const char *name, const char *label, const char *initialText)
Assign attributes for a text property. The text's auxiliary elements will be set to NULL.
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL.
void IUSaveConfigText(FILE *fp, const ITextVectorProperty *tvp)
Add a text vector property value to the configuration file.
int crackIPState(const char *str, IPState *ip)
Extract property state (Idle, OK, Busy, Alert) from the supplied string.
void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char *dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s)
Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL.
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
int IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
Update all text members in a text vector property.
void IDSnoopDevice(const char *snooped_device, const char *snooped_property)
Function a Driver calls to snoop on another Device. Snooped messages will then arrive via ISSnoopDevi...
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
#define LOGF_INFO(fmt,...)
#define LOGF_DEBUG(fmt,...)
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
#define LOGF_ERROR(fmt,...)
const char * findXMLAttValu(XMLEle *ep, const char *name)
Find an XML element's attribute value.
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
std::unique_ptr< WatchDog > juli(new WatchDog())