From ff86c8af7385a13cd64141a27e7d1de4fe0eb051 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 29 Jul 2021 16:31:04 +0200 Subject: [PATCH] watchdog handling finished --- CMakeLists.txt | 13 +-- bsp_q7s/core/CoreController.cpp | 41 ++++++++++ bsp_q7s/core/CoreController.h | 2 + bsp_q7s/core/obsw.cpp | 12 ++- linux/fsfwconfig/OBSWConfig.h.in | 4 + watchdog/Watchdog.cpp | 133 ++++++++++++++++++++++--------- watchdog/Watchdog.h | 11 ++- watchdog/watchdogConf.h.in | 8 ++ 8 files changed, 179 insertions(+), 45 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e49dd9a..7e5e4482 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,17 +96,20 @@ if(TGT_BSP) endif() endif() - if(${TGT_BSP} MATCHES "arm/raspberrypi") - add_definitions(-DRASPBERRY_PI) + if(${TGT_BSP} MATCHES "arm/raspberrypi") + # Used by configure file + set(RASPBERRY_PI ON) set(FSFW_HAL_ADD_RASPBERRY_PI ON) endif() - if(${TGT_BSP} MATCHES "arm/beagleboneblack") - add_definitions(-DBEAGLEBONEBLACK) + if(${TGT_BSP} MATCHES "arm/beagleboneblack") + # Used by configure file + set(BEAGLEBONEBLACK ON) endif() if(${TGT_BSP} MATCHES "arm/q7s") - add_definitions(-DXIPHOS_Q7S) + # Used by configure file + set(XIPHOS_Q7S ON) endif() else() # Required by FSFW library diff --git a/bsp_q7s/core/CoreController.cpp b/bsp_q7s/core/CoreController.cpp index a37db440..bdfac5f8 100644 --- a/bsp_q7s/core/CoreController.cpp +++ b/bsp_q7s/core/CoreController.cpp @@ -1,6 +1,7 @@ #include "CoreController.h" #include "OBSWConfig.h" #include "OBSWVersion.h" +#include "watchdogConf.h" #include "fsfw/FSFWVersion.h" #include "fsfw/serviceinterface/ServiceInterface.h" @@ -13,6 +14,9 @@ #include "bsp_q7s/memory/scratchApi.h" #include "bsp_q7s/memory/SdCardManager.h" +#include +#include + #include CoreController::Chip CoreController::currentChip = Chip::NO_CHIP; @@ -22,6 +26,11 @@ CoreController::CoreController(object_id_t objectId): ExtendedControllerBase(objectId, objects::NO_OBJECT, 5) { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; try { + result = initWatchdogFifo(); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::warning << "CoreController::CoreController: Watchdog FIFO init failed" << + std::endl; + } result = initSdCard(); if(result != HasReturnvaluesIF::RETURN_OK) { sif::warning << "CoreController::CoreController: SD card init failed" << std::endl; @@ -30,6 +39,7 @@ CoreController::CoreController(object_id_t objectId): if(result != HasReturnvaluesIF::RETURN_OK) { sif::warning << "CoreController::CoreController: Boot copy init" << std::endl; } + } catch(const std::filesystem::filesystem_error& e) { sif::error << "CoreController::CoreController: Failed with exception " << @@ -42,6 +52,16 @@ ReturnValue_t CoreController::handleCommandMessage(CommandMessage *message) { } void CoreController::performControlOperation() { + if(watchdogFifoFd != 0) { + // Write to OBSW watchdog FIFO here + const char writeChar = 'a'; + std::cout << "Writing to FIFO.." << std::endl; + ssize_t writtenBytes = write(watchdogFifoFd, &writeChar, 1); + if(writtenBytes < 0) { + sif::error << "Errors writing to watchdog FIFO, code " << errno << ": " << + strerror(errno) << std::endl; + } + } } ReturnValue_t CoreController::initializeLocalDataPool(localpool::DataPool &localDataPoolMap, @@ -406,6 +426,23 @@ void CoreController::getCurrentBootCopy(Chip &chip, Copy ©) { copy = currentCopy; } +ReturnValue_t CoreController::initWatchdogFifo() { + if(not std::filesystem::exists(watchdog::FIFO_NAME)) { + // Still return RETURN_OK for now + sif::info << "Watchdog FIFO " << watchdog::FIFO_NAME << " does not exist, can't initiate" << + " watchdog" << std::endl; + return HasReturnvaluesIF::RETURN_OK; + } + // Open FIFO write only and non-blocking + watchdogFifoFd = open(watchdog::FIFO_NAME.c_str(), O_WRONLY); + if(watchdogFifoFd < 0) { + std::cerr << "Opening pipe " << watchdog::FIFO_NAME << "write-only failed with " << + errno << ": " << strerror(errno) << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + void CoreController::initPrint() { #if OBSW_VERBOSE_LEVEL >= 1 #if OBSW_USE_TMTC_TCP_BRIDGE == 0 @@ -415,5 +452,9 @@ void CoreController::initPrint() { sif::info << "Created TCP server for TMTC commanding with listener port " << TcpTmTcBridge::DEFAULT_SERVER_PORT << std::endl; #endif + + if(watchdogFifoFd != 0) { + sif::info << "Opened watchdog FIFO successfully.." << std::endl; + } #endif } diff --git a/bsp_q7s/core/CoreController.h b/bsp_q7s/core/CoreController.h index 34d72be4..ea212a16 100644 --- a/bsp_q7s/core/CoreController.h +++ b/bsp_q7s/core/CoreController.h @@ -63,12 +63,14 @@ private: ReturnValue_t initVersionFile(); ReturnValue_t initBootCopy(); + ReturnValue_t initWatchdogFifo(); ReturnValue_t actionListDirectoryIntoFile(ActionId_t actionId, MessageQueueId_t commandedBy, const uint8_t *data, size_t size); void initPrint(); + int watchdogFifoFd = 0; }; diff --git a/bsp_q7s/core/obsw.cpp b/bsp_q7s/core/obsw.cpp index 64b0b422..47b7b9d2 100644 --- a/bsp_q7s/core/obsw.cpp +++ b/bsp_q7s/core/obsw.cpp @@ -2,11 +2,15 @@ #include "OBSWVersion.h" #include "OBSWConfig.h" #include "InitMission.h" +#include "watchdogConf.h" #include "fsfw/tasks/TaskFactory.h" #include "fsfw/FSFWVersion.h" #include +#include + +static int OBSW_ALREADY_RUNNING = -2; int obsw::obsw() { std::cout << "-- EIVE OBSW --" << std::endl; @@ -21,7 +25,13 @@ int obsw::obsw() { std::cout << "-- " << __DATE__ << " " << __TIME__ << " --" << std::endl; #if Q7S_CHECK_FOR_ALREADY_RUNNING_IMG == 1 - // Check special file here + // Check special file here. This file is created or deleted by the eive-watchdog application + // or systemd service! + if(std::filesystem::exists(watchdog::RUNNING_FILE_NAME)) { + sif::warning << "File " << watchdog::RUNNING_FILE_NAME << " exists so the software might " + "already be running. Aborting.." << std::endl; + return OBSW_ALREADY_RUNNING; + } #endif initmission::initMission(); diff --git a/linux/fsfwconfig/OBSWConfig.h.in b/linux/fsfwconfig/OBSWConfig.h.in index 16eacccf..778a1611 100644 --- a/linux/fsfwconfig/OBSWConfig.h.in +++ b/linux/fsfwconfig/OBSWConfig.h.in @@ -6,6 +6,10 @@ #ifndef FSFWCONFIG_OBSWCONFIG_H_ #define FSFWCONFIG_OBSWCONFIG_H_ +#cmakedefine RASPBERRY_Pi +#cmakedefine XIPHOS_Q7S +#cmakedefine BEAGLEBONEBLACK + #ifdef RASPBERRY_PI #include "rpiConfig.h" #elif defined(XIPHOS_Q7S) diff --git a/watchdog/Watchdog.cpp b/watchdog/Watchdog.cpp index f4f8c03c..21be1e1d 100644 --- a/watchdog/Watchdog.cpp +++ b/watchdog/Watchdog.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -54,21 +55,34 @@ int WatchdogTask::performOperation() { break; } case(LoopResult::CANCEL_RQ): { - if(state == States::RUNNING) { + std::cout << "eive-watchdog: Received cancel request, closing watchdog.." << std::endl; + return 0; + } + case(LoopResult::SUSPEND_RQ): { + std::cout << "eive-watchdog: Suspending watchdog operations" << std::endl; + if(state == States::RUNNING or state == States::FAULTY) { + watchdogRunning = false; state = States::SUSPENDED; } break; } case(LoopResult::TIMEOUT): { std::cout << "eive-watchdog: The FIFO timed out!" << std::endl; + performTimeoutOperation(); break; } case(LoopResult::RESTART_RQ): { - if(state == States::SUSPENDED) { + if(state == States::SUSPENDED or state == States::FAULTY) { state = States::RUNNING; + watchdogRunning = true; + performRunningOperation(); } break; } + case(LoopResult::FAULT): { + // Configuration error + std::cerr << "Fault has occured in watchdog loop" << std::endl; + } } } if (close(fd) < 0) { @@ -81,7 +95,6 @@ int WatchdogTask::performOperation() { WatchdogTask::LoopResult WatchdogTask::watchdogLoop() { using namespace std::chrono_literals; - char readChar; struct pollfd waiter = {}; waiter.fd = fd; waiter.events = POLLIN; @@ -113,41 +126,7 @@ WatchdogTask::LoopResult WatchdogTask::watchdogLoop() { 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; + return pollEvent(waiter); } default: { std::cerr << "eive-watchdog: Unknown poll error at " << watchdog::FIFO_NAME << ", error " << @@ -157,3 +136,81 @@ WatchdogTask::LoopResult WatchdogTask::watchdogLoop() { } return LoopResult::OK; } + +WatchdogTask::LoopResult WatchdogTask::pollEvent(struct pollfd& waiter) { + 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; + return LoopResult::OK; + } +#if WATCHDOG_VERBOSE_LEVEL == 2 + std::cout << "Read " << readLen << " byte(s) on the pipe " << FIFO_NAME + << std::endl; +#endif + return parseCommandByte(readLen); + + } + else if(waiter.revents & POLLERR) { + std::cerr << "eive-watchdog: Poll error error on pipe " << watchdog::FIFO_NAME << + std::endl; + return LoopResult::FAULT; + } + else if (waiter.revents & POLLHUP) { + // Writer closed its end + } + return LoopResult::FAULT; +} + +WatchdogTask::LoopResult WatchdogTask::parseCommandByte(ssize_t readLen) { + for(ssize_t idx = 0; idx < readLen; idx++) { + char readChar = buf[idx]; + // Cancel request + if(readChar == watchdog::CANCEL_CHAR) { + return LoopResult::CANCEL_RQ; + } + // Begin request. Does not work if the operation was not suspended before + else if(readChar == watchdog::RESTART_CHAR) { + return LoopResult::RESTART_RQ; + } + // Suspend request + else if(readChar == watchdog::SUSPEND_CHAR) { + return LoopResult::SUSPEND_RQ; + } + // Everything else: All working as expected + } + return LoopResult::OK; +} + +int WatchdogTask::performRunningOperation() { + if(not obswRunning) { + obswRunning = true; +#if WATCHDOG_CREATE_FILE_IF_RUNNING == 1 + if (not std::filesystem::exists(watchdog::RUNNING_FILE_NAME)) { + std::ofstream obswRunningFile(watchdog::RUNNING_FILE_NAME); + if(not obswRunningFile.good()) { + std::cerr << "Creating file " << watchdog::RUNNING_FILE_NAME << " failed" + << std::endl; + } + } +#endif + } + return 0; +} + +int WatchdogTask::performTimeoutOperation() { +#if WATCHDOG_CREATE_FILE_IF_RUNNING == 1 + if (std::filesystem::exists(watchdog::RUNNING_FILE_NAME)) { + int result = std::remove(watchdog::RUNNING_FILE_NAME.c_str()); + if(result != 0) { + std::cerr << "Removing " << watchdog::RUNNING_FILE_NAME << " failed with code " << + errno << ": " << strerror(errno) << std::endl; + } + } +#endif + if(obswRunning) { + obswRunning = false; + } + return 0; +} diff --git a/watchdog/Watchdog.h b/watchdog/Watchdog.h index 53935fc2..088acc5e 100644 --- a/watchdog/Watchdog.h +++ b/watchdog/Watchdog.h @@ -15,9 +15,11 @@ public: enum class LoopResult { OK, + SUSPEND_RQ, CANCEL_RQ, RESTART_RQ, - TIMEOUT + TIMEOUT, + FAULT }; WatchdogTask(); @@ -28,10 +30,17 @@ public: private: int fd = 0; + bool obswRunning = false; + bool watchdogRunning = false; std::array buf; States state = States::NOT_STARTED; LoopResult watchdogLoop(); + LoopResult pollEvent(struct pollfd& waiter); + LoopResult parseCommandByte(ssize_t readLen); + + int performRunningOperation(); + int performTimeoutOperation(); }; #endif /* WATCHDOG_WATCHDOG_H_ */ diff --git a/watchdog/watchdogConf.h.in b/watchdog/watchdogConf.h.in index daa9f248..81faf572 100644 --- a/watchdog/watchdogConf.h.in +++ b/watchdog/watchdogConf.h.in @@ -1,4 +1,5 @@ #include +#include #define WATCHDOG_VERBOSE_LEVEL 1 /** @@ -13,4 +14,11 @@ static constexpr int TIMEOUT_MS = 10 * 1000; const std::string FIFO_NAME = "/tmp/watchdog-pipe"; const std::string RUNNING_FILE_NAME = "/tmp/obsw-running"; +// Suspend watchdog operations temporarily +static constexpr char SUSPEND_CHAR = 's'; +// Resume watchdog operations +static constexpr char RESTART_CHAR = 'b'; +// Causes the watchdog to close down +static constexpr char CANCEL_CHAR = 'c'; + }