added eive-watchdog
This commit is contained in:
4
watchdog/CMakeLists.txt
Normal file
4
watchdog/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
target_sources(${TARGET_NAME} PRIVATE
|
||||
main.cpp
|
||||
Watchdog.cpp
|
||||
)
|
161
watchdog/Watchdog.cpp
Normal file
161
watchdog/Watchdog.cpp
Normal file
@ -0,0 +1,161 @@
|
||||
#include "Watchdog.h"
|
||||
#include "watchdogConf.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
|
||||
|
||||
|
||||
WatchdogTask::WatchdogTask (): fd(0) {
|
||||
|
||||
}
|
||||
|
||||
WatchdogTask::~WatchdogTask() {
|
||||
|
||||
}
|
||||
|
||||
int WatchdogTask::performOperation() {
|
||||
int result = 0;
|
||||
// Only create the FIFO if it does not exist yet
|
||||
if(not std::filesystem::exists(watchdog::FIFO_NAME)) {
|
||||
// Permission 666 or rw-rw-rw-
|
||||
mode_t mode = DEFFILEMODE;
|
||||
result = mkfifo(watchdog::FIFO_NAME.c_str(), mode);
|
||||
if(result != 0) {
|
||||
std::cerr << "eive-watchdog: Could not created named pipe at " <<
|
||||
watchdog::FIFO_NAME << ", error " << errno << ": " << strerror(errno) <<
|
||||
std::endl;
|
||||
return -2;
|
||||
}
|
||||
#if WATCHDOG_VERBOSE_LEVEL >= 1
|
||||
std::cout << "eive-watchdog: Pipe at " << watchdog::FIFO_NAME <<
|
||||
" created successfully" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Open FIFO read only and non-blocking
|
||||
fd = open(watchdog::FIFO_NAME.c_str(), O_RDONLY | O_NONBLOCK);
|
||||
if(fd < 0) {
|
||||
std::cerr << "eive-watchdog: Opening pipe " << watchdog::FIFO_NAME <<
|
||||
"read-only failed with " << errno << ": " << strerror(errno) << std::endl;
|
||||
}
|
||||
|
||||
while(true) {
|
||||
WatchdogTask::LoopResult loopResult = watchdogLoop();
|
||||
switch(loopResult) {
|
||||
case(LoopResult::OK): {
|
||||
break;
|
||||
}
|
||||
case(LoopResult::CANCEL_RQ): {
|
||||
if(state == States::RUNNING) {
|
||||
state = States::SUSPENDED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case(LoopResult::TIMEOUT): {
|
||||
std::cout << "eive-watchdog: The FIFO timed out!" << std::endl;
|
||||
break;
|
||||
}
|
||||
case(LoopResult::RESTART_RQ): {
|
||||
if(state == States::SUSPENDED) {
|
||||
state = States::RUNNING;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (close(fd) < 0) {
|
||||
std::cerr << "eive-watchdog: Closing named pipe at " << watchdog::FIFO_NAME <<
|
||||
"failed, error " << errno << ": " << strerror(errno) << std::endl;
|
||||
}
|
||||
std::cout << "eive-watchdog: Finished" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
WatchdogTask::LoopResult WatchdogTask::watchdogLoop() {
|
||||
using namespace std::chrono_literals;
|
||||
char readChar;
|
||||
struct pollfd waiter = {};
|
||||
waiter.fd = fd;
|
||||
waiter.events = POLLIN;
|
||||
|
||||
switch(state) {
|
||||
case(States::SUSPENDED): {
|
||||
// Sleep, then check whether a restart request was received
|
||||
std::this_thread::sleep_for(1000ms);
|
||||
break;
|
||||
}
|
||||
case(States::RUNNING): {
|
||||
// Continue as usual
|
||||
break;
|
||||
}
|
||||
case(States::NOT_STARTED): {
|
||||
// This should not happen
|
||||
std::cerr << "eive-watchdog: State is NOT_STARTED, configuration error" << std::endl;
|
||||
break;
|
||||
}
|
||||
case(States::FAULTY): {
|
||||
// TODO: Not sure what to do yet. Continue for now
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 10 seconds timeout, only poll one file descriptor
|
||||
switch(poll(&waiter, 1, watchdog::TIMEOUT_MS)) {
|
||||
case(0): {
|
||||
return LoopResult::TIMEOUT;
|
||||
}
|
||||
case(1): {
|
||||
if (waiter.revents & POLLIN) {
|
||||
ssize_t readLen = read(fd, buf.data(), buf.size());
|
||||
if (readLen < 0) {
|
||||
std::cerr << "eive-watchdog: Read error on pipe " << watchdog::FIFO_NAME <<
|
||||
", error " << errno << ": " << strerror(errno) << std::endl;
|
||||
break;
|
||||
}
|
||||
for(ssize_t idx = 0; idx < readLen; idx++) {
|
||||
readChar = buf[idx];
|
||||
// Cancel request
|
||||
if(readChar == 'c') {
|
||||
return LoopResult::CANCEL_RQ;
|
||||
}
|
||||
// Begin request. Does not work if the operation was not suspended before
|
||||
else if(readChar == 'b') {
|
||||
return LoopResult::RESTART_RQ;
|
||||
}
|
||||
// Everything else: All working as expected
|
||||
else {
|
||||
|
||||
}
|
||||
}
|
||||
#if WATCHDOG_VERBOSE_LEVEL == 2
|
||||
std::cout << "Read " << readLen << " byte(s) on the pipe " << FIFO_NAME
|
||||
<< std::endl;
|
||||
#endif
|
||||
}
|
||||
else if(waiter.revents & POLLERR) {
|
||||
std::cerr << "eive-watchdog: Poll error error on pipe " << watchdog::FIFO_NAME <<
|
||||
std::endl;
|
||||
}
|
||||
else if (waiter.revents & POLLHUP) {
|
||||
// Writer closed its end
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
std::cerr << "eive-watchdog: Unknown poll error at " << watchdog::FIFO_NAME << ", error " <<
|
||||
errno << ": " << strerror(errno) << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return LoopResult::OK;
|
||||
}
|
37
watchdog/Watchdog.h
Normal file
37
watchdog/Watchdog.h
Normal file
@ -0,0 +1,37 @@
|
||||
#ifndef WATCHDOG_WATCHDOG_H_
|
||||
#define WATCHDOG_WATCHDOG_H_
|
||||
|
||||
#include <array>
|
||||
|
||||
|
||||
class WatchdogTask {
|
||||
public:
|
||||
enum class States {
|
||||
NOT_STARTED,
|
||||
RUNNING,
|
||||
SUSPENDED,
|
||||
FAULTY
|
||||
};
|
||||
|
||||
enum class LoopResult {
|
||||
OK,
|
||||
CANCEL_RQ,
|
||||
RESTART_RQ,
|
||||
TIMEOUT
|
||||
};
|
||||
|
||||
WatchdogTask();
|
||||
|
||||
virtual ~WatchdogTask();
|
||||
|
||||
int performOperation();
|
||||
private:
|
||||
int fd = 0;
|
||||
|
||||
std::array<uint8_t, 64> buf;
|
||||
States state = States::NOT_STARTED;
|
||||
|
||||
LoopResult watchdogLoop();
|
||||
};
|
||||
|
||||
#endif /* WATCHDOG_WATCHDOG_H_ */
|
15
watchdog/main.cpp
Normal file
15
watchdog/main.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#include "Watchdog.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
/**
|
||||
* @brief This watchdog application uses a FIFO to check whether the OBSW is still running.
|
||||
* It checks whether the OBSW writes to the the FIFO regularly.
|
||||
*/
|
||||
int main() {
|
||||
std::cout << "Starting OBSW watchdog.." << std::endl;
|
||||
WatchdogTask watchdogTask;
|
||||
watchdogTask.performOperation();
|
||||
return 0;
|
||||
}
|
||||
|
16
watchdog/watchdogConf.h.in
Normal file
16
watchdog/watchdogConf.h.in
Normal file
@ -0,0 +1,16 @@
|
||||
#include <cstdint>
|
||||
|
||||
#define WATCHDOG_VERBOSE_LEVEL 1
|
||||
/**
|
||||
* This flag instructs the watchdog to create a special file in /tmp if the OBSW is running
|
||||
* or to delete it if it is not running
|
||||
*/
|
||||
#define WATCHDOG_CREATE_FILE_IF_RUNNING 1
|
||||
|
||||
namespace watchdog {
|
||||
|
||||
static constexpr int TIMEOUT_MS = 10 * 1000;
|
||||
const std::string FIFO_NAME = "/tmp/obsw-watchdog";
|
||||
const std::string RUNNING_FILE_NAME = "/tmp/obsw-running";
|
||||
|
||||
}
|
Reference in New Issue
Block a user