From 1cfb9250fa32e878b4f4419a745c00fb8d866486 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 5 Aug 2021 10:14:17 +0200 Subject: [PATCH] SDC manager non-blocking mode --- bsp_q7s/core/CoreController.cpp | 20 +++-- bsp_q7s/memory/SdCardManager.cpp | 136 ++++++++++++++++++++++++++----- bsp_q7s/memory/SdCardManager.h | 50 +++++++++++- fsfw | 2 +- tmtc | 2 +- 5 files changed, 180 insertions(+), 30 deletions(-) diff --git a/bsp_q7s/core/CoreController.cpp b/bsp_q7s/core/CoreController.cpp index b1ca47d9..e49f0007 100644 --- a/bsp_q7s/core/CoreController.cpp +++ b/bsp_q7s/core/CoreController.cpp @@ -4,6 +4,7 @@ #include "watchdogConf.h" #include "fsfw/FSFWVersion.h" +#include "fsfw/timemanager/Stopwatch.h" #include "fsfw/serviceinterface/ServiceInterface.h" #if OBSW_USE_TMTC_TCP_BRIDGE == 0 #include "fsfw/osal/common/UdpTmTcBridge.h" @@ -32,15 +33,11 @@ CoreController::CoreController(object_id_t objectId): 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; - } + result = initBootCopy(); 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 " << @@ -91,6 +88,7 @@ ReturnValue_t CoreController::initSdCard() { if(sdcMan == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } + // Create update status file ReturnValue_t result = sdcMan->updateSdCardStateFile(); if(result != HasReturnvaluesIF::RETURN_OK) { @@ -168,7 +166,17 @@ ReturnValue_t CoreController::executeAction(ActionId_t actionId, MessageQueueId_ } ReturnValue_t CoreController::initializeAfterTaskCreation() { - ReturnValue_t result = initVersionFile(); + + // TODO: Do this here because this can take a longer time. Later, use non-blocking mode + // to start doing stuff in ctor and initialize function. + // This operation can take 1-2 seconds on reboot, and around 50-100ms if the SD + // card is already on. + ReturnValue_t result = initSdCard(); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::warning << "CoreController::CoreController: SD card init failed" << std::endl; + } + + result = initVersionFile(); if(result != HasReturnvaluesIF::RETURN_OK) { sif::warning << "CoreController::initialize: Version initialization failed" << std::endl; } diff --git a/bsp_q7s/memory/SdCardManager.cpp b/bsp_q7s/memory/SdCardManager.cpp index 3dfa0b10..4e9ce6c8 100644 --- a/bsp_q7s/memory/SdCardManager.cpp +++ b/bsp_q7s/memory/SdCardManager.cpp @@ -6,13 +6,17 @@ #include "fsfw/ipc/MutexFactory.h" #include "fsfw/serviceinterface/ServiceInterface.h" +#include + #include #include #include +#include SdCardManager* SdCardManager::factoryInstance = nullptr; SdCardManager::SdCardManager() { + waiter.events = POLLIN; } SdCardManager::~SdCardManager() { @@ -128,6 +132,9 @@ ReturnValue_t SdCardManager::setSdCardState(sd::SdCard sdCard, bool on) { using namespace std; string sdstring = ""; string statestring = ""; + if(currentOp != Operations::IDLE) { + return OP_ONGOING; + } if(sdCard == sd::SdCard::SLOT_0) { sdstring = "0"; } @@ -135,20 +142,16 @@ ReturnValue_t SdCardManager::setSdCardState(sd::SdCard sdCard, bool on) { sdstring = "1"; } if(on) { + currentOp = Operations::SWITCHING_ON; statestring = "on"; } else { + currentOp = Operations::SWITCHING_OFF; statestring = "off"; } ostringstream command; command << "q7hw sd set " << sdstring << " " << statestring; - int result = system(command.str().c_str()); - if(result == 0) { - return HasReturnvaluesIF::RETURN_OK; - } - sif::warning << "SdCardManager::setSdCardState: system call failed with code " << - result << std::endl; - return SYSTEM_CALL_ERROR; + return handleCommand(command.str(), "SdCardManager::setSdCardState"); } ReturnValue_t SdCardManager::getSdCardActiveStatus(SdStatusPair& active) { @@ -174,6 +177,9 @@ ReturnValue_t SdCardManager::getSdCardActiveStatus(SdStatusPair& active) { ReturnValue_t SdCardManager::mountSdCard(sd::SdCard sdCard) { using namespace std; + if(currentOp != Operations::IDLE) { + return OP_ONGOING; + } if(sdCard == sd::SdCard::BOTH) { sif::warning << "SdCardManager::mountSdCard: API does not allow sd::SdStatus::BOTH" << std::endl; @@ -196,12 +202,7 @@ ReturnValue_t SdCardManager::mountSdCard(sd::SdCard sdCard) { } string sdMountCommand = "mount " + mountDev + " " + mountPoint; - int result = system(sdMountCommand.c_str()); - if (result != 0) { - utility::handleSystemError(result, "SdCardManager::mountSdCard"); - return SYSTEM_CALL_ERROR; - } - return HasReturnvaluesIF::RETURN_OK; + return handleCommand(sdMountCommand, "SdCardManager::mountSdCard"); } ReturnValue_t SdCardManager::unmountSdCard(sd::SdCard sdCard) { @@ -229,12 +230,7 @@ ReturnValue_t SdCardManager::unmountSdCard(sd::SdCard sdCard) { sif::warning << "SdCardManager::unmountSdCard: Mount point is empty!" << std::endl; } string sdUnmountCommand = "umount " + mountPoint; - int result = system(sdUnmountCommand.c_str()); - if (result != 0) { - utility::handleSystemError(result, "SdCardManager::unmountSdCard"); - return SYSTEM_CALL_ERROR; - } - return HasReturnvaluesIF::RETURN_OK; + return handleCommand(sdUnmountCommand, "SdCardManager::unmountSdCard"); } ReturnValue_t SdCardManager::sanitizeState(SdStatusPair* statusPair, sd::SdCard prefSdCard) { @@ -354,3 +350,105 @@ std::string SdCardManager::getCurrentMountPrefix(sd::SdCard prefSdCard) { return SD_1_MOUNT_POINT; } } + +SdCardManager::OpStatus SdCardManager::checkCurrentOp(Operations ¤tOp) { + currentOp = this->currentOp; + switch(currentOpStatus) { + case(OpStatus::IDLE): + case(OpStatus::FAIL): + case(OpStatus::TIMEOUT): + case(OpStatus::SUCCESS):{ + break; + } + case(OpStatus::ONGOING): { + int result = poll(&waiter, 1, 0); + switch(result) { + case(0): { + // No data available + break; + } + case(1): { + if (waiter.revents & POLLIN) { + ssize_t readBytes = read(opFileNum, readBuf.data(), readBuf.size()); + if(readBytes == 0) { + // Should not happen.. + sif::warning << "SdCardManager::checkCurrentOp: 0 bytes read" << std::endl; + } + else if(readBytes > 0) { + sif::info << currentCmd << " | " << readBuf.data() << std::endl; + } + else { + sif::error << "SdCardManager::checkCurrentOp: Error code " << errno << + ": " << strerror(errno) << std::endl; + return OpStatus::FAIL; + } + } + else if (waiter.revents & POLLERR) { + sif::warning << "SdCardManager::checkCurrentOp: Poll error.." << std::endl; + } + else if(waiter.revents & POLLHUP) { + int result = pclose(opFile); + if(result != 0) { + sif::error << "SdCardManager::setSdCardState: pclose failed with code " << + result << ": " << strerror(result) << std::endl; + } + opFile = nullptr; + opFileNum = 0; + currentOp = Operations::IDLE; + return OpStatus::SUCCESS; + } + break; + } + default: { + sif::error << "SdCardManager::checkCurrentOp: Unexpected returnvalue " << result << + "for poll call" << std::endl; + break; + } + } + } + } + return currentOpStatus; +} + +void SdCardManager::resetState() { + currentOp = Operations::IDLE; + currentOpStatus = OpStatus::IDLE; + currentOpSdCard = sd::SdCard::NONE; +} + +void SdCardManager::setBlocking(bool blocking) { + this->blocking = blocking; + if(not blocking) { + currentOp = Operations::IDLE; + currentOpStatus = OpStatus::IDLE; + } +} + +ReturnValue_t SdCardManager::handleCommand(std::string cmd, std::string funcName) { + currentCmd = cmd; + opFile = popen(currentCmd.c_str(), "r"); + if(opFile == nullptr) { + return POPEN_CALL_ERROR; + } + if(blocking) { + return handleBlockingOperation(funcName); + } + else { + opFileNum = fileno(opFile); + waiter.fd = opFileNum; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t SdCardManager::handleBlockingOperation(std::string funcName) { + while(fgets(readBuf.data(), readBuf.size(), opFile) != nullptr) { + sif::info << currentCmd << " | " << readBuf.data() << std::endl; + } + int result = pclose(opFile); + if(result != 0) { + sif::error << "SdCardManager::setSdCardState: pclose failed with code " << + result << ": " << strerror(result) << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/bsp_q7s/memory/SdCardManager.h b/bsp_q7s/memory/SdCardManager.h index 7af57a67..c1832e25 100644 --- a/bsp_q7s/memory/SdCardManager.h +++ b/bsp_q7s/memory/SdCardManager.h @@ -8,10 +8,13 @@ #include "fsfw/events/Event.h" #include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include + #include #include #include #include +#include class MutexIF; @@ -22,16 +25,33 @@ class MutexIF; class SdCardManager { friend class SdCardAccess; public: + enum class Operations { + SWITCHING_ON, + SWITCHING_OFF, + MOUNTING, + IDLE + }; + + enum class OpStatus { + IDLE, + SUCCESS, + TIMEOUT, + ONGOING, + FAIL + }; + using SdStatusPair = std::pair; static constexpr uint8_t INTERFACE_ID = CLASS_ID::SD_CARD_MANAGER; - static constexpr ReturnValue_t ALREADY_ON = + static constexpr ReturnValue_t OP_ONGOING = HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 0); - static constexpr ReturnValue_t ALREADY_MOUNTED = + static constexpr ReturnValue_t ALREADY_ON = HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 1); - static constexpr ReturnValue_t ALREADY_OFF = + static constexpr ReturnValue_t ALREADY_MOUNTED = HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 2); + static constexpr ReturnValue_t ALREADY_OFF = + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 3); static constexpr ReturnValue_t STATUS_FILE_NEXISTS = HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 10); static constexpr ReturnValue_t STATUS_FILE_FORMAT_INVALID = @@ -42,6 +62,8 @@ public: HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 13); static constexpr ReturnValue_t SYSTEM_CALL_ERROR = HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 14); + static constexpr ReturnValue_t POPEN_CALL_ERROR = + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 15); static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::FILE_SYSTEM; @@ -159,7 +181,26 @@ public: * @return */ std::string getCurrentMountPrefix(sd::SdCard prefSdCardPtr = sd::SdCard::NONE); + + OpStatus checkCurrentOp(Operations& currentOp); + + /** + * If there are issues with the state machine, it can be reset with this function + */ + void resetState(); + + void setBlocking(bool blocking); private: + Operations currentOp = Operations::IDLE; + OpStatus currentOpStatus = OpStatus::IDLE; + sd::SdCard currentOpSdCard = sd::SdCard::NONE; + FILE* opFile = nullptr; + bool blocking = true; + struct pollfd waiter {}; + std::array readBuf {}; + std::string currentCmd; + int opFileNum = 0; + SdCardManager(); ReturnValue_t setSdCardState(sd::SdCard sdCard, bool on); @@ -169,6 +210,9 @@ private: std::string currentPrefix; + ReturnValue_t handleCommand(std::string cmd, std::string funcName); + ReturnValue_t handleBlockingOperation(std::string funcName); + static SdCardManager* factoryInstance; }; diff --git a/fsfw b/fsfw index bb88490c..1a4a85ce 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit bb88490cc6cda5474d1d4913452eeb758da8cc25 +Subproject commit 1a4a85ceb2ad665e3cd3c2042925ae2f2aae70c1 diff --git a/tmtc b/tmtc index a226bf65..3e8626bf 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit a226bf659eeadd3ad300b249d2659043317e2245 +Subproject commit 3e8626bfafa561510323bf8fe3963bc2860950ed