diff --git a/bsp_q7s/boardconfig/q7sConfig.h.in b/bsp_q7s/boardconfig/q7sConfig.h.in index 9bed2a4a..11dec25c 100644 --- a/bsp_q7s/boardconfig/q7sConfig.h.in +++ b/bsp_q7s/boardconfig/q7sConfig.h.in @@ -4,6 +4,17 @@ #include #cmakedefine01 Q7S_SIMPLE_MODE + +#define Q7S_SD_NONE 0 +#define Q7S_SD_COLD_REDUNDANT 1 +#define Q7S_SD_HOT_REDUNDANT 2 +// The OBSW will perform different actions to set up the SD cards depending on the flag set here +// Set to Q7S_SD_NONE: Don't do anything +// Set to Q7S_COLD_REDUNDANT: On startup, get the prefered SD card, turn it on and mount it, and +// turn off the second SD card if it is on +// Set to Q7S_HOT_REDUNDANT: On startup, turn on both SD cards and mount them +#define Q7S_SD_CARD_CONFIG Q7S_SD_COLD_REDUNDANT + #define Q7S_ADD_RTD_DEVICES 0 /* Only one of those 2 should be enabled! */ diff --git a/bsp_q7s/core/CoreController.cpp b/bsp_q7s/core/CoreController.cpp index ced75056..c4863260 100644 --- a/bsp_q7s/core/CoreController.cpp +++ b/bsp_q7s/core/CoreController.cpp @@ -1,4 +1,6 @@ #include "CoreController.h" +#include "q7sConfig.h" + #include "../memory/SdCardManager.h" CoreController::CoreController(object_id_t objectId): @@ -22,39 +24,125 @@ LocalPoolDataSetBase* CoreController::getDataSetHandle(sid_t sid) { } ReturnValue_t CoreController::initialize() { - // Find a way to store this non-volatile outside of SD cards (ProASIC?) - sd::SdCard preferredSdCard = sd::SdCard::SLOT_0; - std::string printoutString; - if(preferredSdCard == sd::SdCard::SLOT_0) { - printoutString = "0"; - } - else { - printoutString = "1"; - } - // Creator or update status file - ReturnValue_t result = SdCardManager::instance()->updateSdCardStateFile(); - if(result != HasReturnvaluesIF::RETURN_OK) { - sif::warning << "CoreController::initialize: Updating SD card state file failed" - << std::endl; - } - - sif::info << "Switching on SD card " << printoutString << ".." << std::endl; - - result = SdCardManager::instance()->switchOnSdCard(preferredSdCard, true); - if(result == SdCardManager::ALREADY_ON) { - sif::info << "SD card " << printoutString << " is already on" << std::endl; - } - else if(result != HasReturnvaluesIF::RETURN_OK) { - sif::warning << "CoreController::initialize: Turning SD card on failed" - << std::endl; - } - else { - sif::info << "SD card " << printoutString << " was switched on" << std::endl; - } - return HasReturnvaluesIF::RETURN_OK; + return sdCardInit(); } ReturnValue_t CoreController::checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode) { return HasReturnvaluesIF::RETURN_OK; } + +ReturnValue_t CoreController::sdCardInit() { +#if Q7S_SD_CARD_CONFIG == Q7S_SD_NONE + sif::info << "No SD card initialization will be performed" << std::endl; + return HasReturnvaluesIF::RETURN_OK; +#else + SdCardManager* sdcMan = SdCardManager::instance(); + + // Create update status file + ReturnValue_t result = sdcMan->updateSdCardStateFile(); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::warning << "CoreController::initialize: Updating SD card state file failed" + << std::endl; + } + + auto sdStatus = std::pair(sd::SdStatus::OFF, sd::SdStatus::OFF); + result = sdcMan->getSdCardActiveStatus(sdStatus); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::warning << "Getting SD card activity status failed" << std::endl; + } + + // Use a lambda to avoid duplicate code + auto setUpSdCard = [&](sd::SdCard sdCard, sd::SdStatus status, std::string sdString) { + std::string mountString; + if(sdCard == sd::SdCard::SLOT_0) { + mountString = SdCardManager::SD_0_MOUNT_POINT; + } + else { + mountString = SdCardManager::SD_1_MOUNT_POINT; + } + + if(status == sd::SdStatus::OFF) { + sif::info << "Switching on and mounting SD card " << sdString << " at " << + mountString << std::endl; + return sdcMan->switchOnSdCard(sdCard, true, &sdStatus); + } + else if(status == sd::SdStatus::ON) { + sif::info << "Mounting SD card " << sdString << " at " << mountString << std::endl; + return sdcMan->mountSdCard(sdCard); + } + else { + sif::info << "SD card " << sdString << " already on and mounted at " << + mountString << std::endl; + return SdCardManager::ALREADY_MOUNTED; + } + }; + +#if Q7S_SD_CARD_CONFIG == Q7S_SD_COLD_REDUNDANT + sd::SdCard preferredSdCard = sd::SdCard::SLOT_0; + result = sdcMan->getPreferredSdCard(preferredSdCard); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::warning << "Could not get preferred SD card information from the scratch buffer" + << std::endl; + } + std::string preferredString; + sd::SdStatus preferredStatus = sd::SdStatus::OFF; + + sd::SdStatus otherStatus = sd::SdStatus::OFF; + std::string otherString; + sd::SdCard otherSdc = sd::SdCard::SLOT_0; + + if(preferredSdCard == sd::SdCard::SLOT_0) { + preferredStatus = sdStatus.first; + preferredString = "0"; + otherSdc = sd::SdCard::SLOT_1; + otherStatus = sdStatus.second; + otherString = "1"; + } + else { + preferredString = "1"; + preferredStatus = sdStatus.second; + otherStatus = sdStatus.first; + otherSdc = sd::SdCard::SLOT_0; + otherString = "0"; + } + + sif::info << "Cold redundant SD card configuration, preferred SD card " << + preferredString << std::endl; + + result = setUpSdCard(preferredSdCard, preferredStatus, preferredString); + if(result != SdCardManager::ALREADY_MOUNTED and result != HasReturnvaluesIF::RETURN_OK) { + sif::warning << "Setting up preferred card " << otherString << + " in cold redundant mode failed" << std::endl; + // Try other SD card and mark set up operation as failed + setUpSdCard(otherSdc, otherStatus, otherString); + result = HasReturnvaluesIF::RETURN_FAILED; + } + + if(result != HasReturnvaluesIF::RETURN_FAILED and otherStatus != sd::SdStatus::OFF) { + sif::info << "Switching off secondary SD card " << otherString << std::endl; + // Switch off other SD card in cold redundant mode if setting up preferred one walked + // without issues + result = sdcMan->switchOffSdCard(otherSdc, otherStatus, &sdStatus); + if(result != HasReturnvaluesIF::RETURN_OK and result != SdCardManager::ALREADY_OFF) { + sif::warning << "Switching off secondary SD card " << otherString << + " in cold redundant mode failed" << std::endl; + } + } + + // Update status file + sdcMan->updateSdCardStateFile(); + return HasReturnvaluesIF::RETURN_OK; +#elif Q7S_SD_CARD_CONFIG == Q7S_SD_HOT_REDUNDANT + sif::info << "Hot redundant SD card configuration" << std::endl; + + setUpSdCard(sd::SdCard::SLOT_0, sdStatus.first, "0"); + setUpSdCard(sd::SdCard::SLOT_1, sdStatus.second, "1"); + // Update status file + sdcMan->updateSdCardStateFile(); + return HasReturnvaluesIF::RETURN_OK; +#endif + +#endif /* Q7S_SD_CARD_CONFIG != Q7S_SD_NONE */ + +} diff --git a/bsp_q7s/core/CoreController.h b/bsp_q7s/core/CoreController.h index 674ed073..940a9097 100644 --- a/bsp_q7s/core/CoreController.h +++ b/bsp_q7s/core/CoreController.h @@ -17,6 +17,8 @@ private: LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode); + + ReturnValue_t sdCardInit(); }; diff --git a/bsp_q7s/memory/CMakeLists.txt b/bsp_q7s/memory/CMakeLists.txt index ada948fb..6c7d0a94 100644 --- a/bsp_q7s/memory/CMakeLists.txt +++ b/bsp_q7s/memory/CMakeLists.txt @@ -1,6 +1,5 @@ target_sources(${TARGET_NAME} PRIVATE FileSystemHandler.cpp - SdCardAccess.cpp SdCardManager.cpp scratchApi.cpp ) \ No newline at end of file diff --git a/bsp_q7s/memory/FileSystemHandler.cpp b/bsp_q7s/memory/FileSystemHandler.cpp index 5f7e0435..1519b92b 100644 --- a/bsp_q7s/memory/FileSystemHandler.cpp +++ b/bsp_q7s/memory/FileSystemHandler.cpp @@ -4,9 +4,11 @@ #include "fsfw/memory/GenericFileSystemMessage.h" #include "fsfw/ipc/QueueFactory.h" +#include + FileSystemHandler::FileSystemHandler(object_id_t fileSystemHandler): SystemObject(fileSystemHandler) { - mq = QueueFactory::instance()->createMessageQueue(50); + mq = QueueFactory::instance()->createMessageQueue(FS_MAX_QUEUE_SIZE); } FileSystemHandler::~FileSystemHandler() { @@ -15,33 +17,86 @@ FileSystemHandler::~FileSystemHandler() { ReturnValue_t FileSystemHandler::performOperation(uint8_t unsignedChar) { while(true) { - CommandMessage filemsg; - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - while(true) { - result = mq->receiveMessage(&filemsg); - if(result == MessageQueueIF::EMPTY) { - break; - } - else if(result != HasReturnvaluesIF::RETURN_FAILED) { - sif::warning << "FileSystemHandler::performOperation: Message reception failed!" - << std::endl; - break; - } - Command_t command = filemsg.getCommand(); - switch(command) { - case(GenericFileSystemMessage::CMD_CREATE_DIRECTORY): { - break; - } - case(GenericFileSystemMessage::CMD_CREATE_FILE): { - break; - } - } + try { + fileSystemHandlerLoop(); } + catch(std::bad_alloc& e) { + // Restart OBSW, hints at a memory leak + sif::error << "Allocation error in FileSystemHandler::performOperation" + << e.what() << std::endl; + // TODO: If we trigger an event, it might not get sent because were restarting + // Set up an error file or a special flag in the scratch buffer. + // TODO: CoreController: Implement function to restart OBC + } + } +} - // This task will have a low priority and will run permanently in the background - // so we will just run in a permanent loop here and check file system - // messages permanently - TaskFactory::instance()->delayTask(1000); + +void FileSystemHandler::fileSystemHandlerLoop() { + CommandMessage filemsg; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + while(true) { + if(opCounter % 5 == 0) { + fileSystemCheckup(); + } + result = mq->receiveMessage(&filemsg); + if(result == MessageQueueIF::EMPTY) { + break; + } + else if(result != HasReturnvaluesIF::RETURN_FAILED) { + sif::warning << "FileSystemHandler::performOperation: Message reception failed!" + << std::endl; + break; + } + Command_t command = filemsg.getCommand(); + switch(command) { + case(GenericFileSystemMessage::CMD_CREATE_DIRECTORY): { + break; + } + case(GenericFileSystemMessage::CMD_CREATE_FILE): { + break; + } + } + opCounter++; + } + + // This task will have a low priority and will run permanently in the background + // so we will just run in a permanent loop here and check file system + // messages permanently + TaskFactory::instance()->delayTask(1000); +} + +void FileSystemHandler::fileSystemCheckup() { + SdCardManager::SdStatusPair statusPair; + sdcMan->getSdCardActiveStatus(statusPair); + sd::SdCard preferredSdCard; + sdcMan->getPreferredSdCard(preferredSdCard); + if((preferredSdCard == sd::SdCard::SLOT_0) and + (statusPair.first == sd::SdStatus::MOUNTED)) { + currentMountPrefix = SdCardManager::SD_0_MOUNT_POINT; + } + if((preferredSdCard == sd::SdCard::SLOT_1) and + (statusPair.second == sd::SdStatus::MOUNTED)) { + currentMountPrefix = SdCardManager::SD_1_MOUNT_POINT; + } + else { + std::string sdString; + if(preferredSdCard == sd::SdCard::SLOT_0) { + sdString = "0"; + } + else { + sdString = "1"; + } + sif::warning << "FileSystemHandler::performOperation: Inconsistent" << + " state detected. Preferred SD card is " << sdString << + " but does not appear to be mounted. Attempting fix.." << std::endl; + // This function will appear to fix the inconsistent state + ReturnValue_t result = sdcMan->sanitizeState(&preferredSdCard, &statusPair); + if(result != HasReturnvaluesIF::RETURN_OK) { + // Oh no. + // TODO: Trigger medium severity event + sif::error << "Fix failed" << std::endl; + } } } @@ -49,17 +104,81 @@ MessageQueueId_t FileSystemHandler::getCommandQueue() const { return mq->getId(); } +ReturnValue_t FileSystemHandler::initialize() { + sdcMan = SdCardManager::instance(); + sd::SdCard preferredSdCard; + ReturnValue_t result = sdcMan->getPreferredSdCard(preferredSdCard); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(preferredSdCard == sd::SdCard::SLOT_0) { + currentMountPrefix = SdCardManager::SD_0_MOUNT_POINT; + } + else if(preferredSdCard == sd::SdCard::SLOT_1) { + currentMountPrefix = SdCardManager::SD_1_MOUNT_POINT; + } + return HasReturnvaluesIF::RETURN_OK; +} + ReturnValue_t FileSystemHandler::appendToFile(const char *repositoryPath, const char *filename, const uint8_t *data, size_t size, uint16_t packetNumber, void *args) { + // A double slash between repo and filename should not be an issue, so add it in any case + std::string fullPath = currentMountPrefix + std::string(repositoryPath) + "/" + + std::string(filename); return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t FileSystemHandler::createFile(const char *repositoryPath, const char *filename, const uint8_t *data, size_t size, void *args) { + // A double slash between repo and filename should not be an issue, so add it in any case + std::string fullPath = currentMountPrefix + std::string(repositoryPath) + "/" + + std::string(filename); return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t FileSystemHandler::deleteFile(const char *repositoryPath, const char *filename, void *args) { + // A double slash between repo and filename should not be an issue, so add it in any case + std::string fullPath = currentMountPrefix + std::string(repositoryPath) + "/" + + std::string(filename); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t FileSystemHandler::createDirectory(const char *repositoryPath, void *args) { + std::string fullPath = currentMountPrefix + std::string(repositoryPath); + if(std::filesystem::exists(fullPath)) { + return DIRECTORY_ALREADY_EXISTS; + } + if(std::filesystem::create_directory(fullPath)) { + return HasReturnvaluesIF::RETURN_OK; + } + sif::warning << "Creating directory " << fullPath << " failed" << std::endl; + return GENERIC_FILE_ERROR; +} + +ReturnValue_t FileSystemHandler::removeDirectory(const char *repositoryPath, + bool deleteRecurively, void *args) { + std::string fullPath = currentMountPrefix + std::string(repositoryPath); + if(not std::filesystem::exists(fullPath)) { + return DIRECTORY_DOES_NOT_EXIST; + } + std::error_code err; + if(not deleteRecurively) { + if(std::filesystem::remove(fullPath, err)) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + // Check error code. Most probably denied permissions because folder is not empty + } + } + else { + if(std::filesystem::remove_all(fullPath, err)) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + // Check error code + } + } + return HasReturnvaluesIF::RETURN_OK; } diff --git a/bsp_q7s/memory/FileSystemHandler.h b/bsp_q7s/memory/FileSystemHandler.h index 04cea3dc..886fa574 100644 --- a/bsp_q7s/memory/FileSystemHandler.h +++ b/bsp_q7s/memory/FileSystemHandler.h @@ -1,11 +1,16 @@ #ifndef BSP_Q7S_MEMORY_FILESYSTEMHANDLER_H_ #define BSP_Q7S_MEMORY_FILESYSTEMHANDLER_H_ +#include "SdCardManager.h" +#include "OBSWConfig.h" + #include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/tasks/ExecutableObjectIF.h" #include "fsfw/objectmanager/SystemObject.h" #include "fsfw/memory/HasFileSystemIF.h" +#include + class FileSystemHandler: public SystemObject, public ExecutableObjectIF, public HasFileSystemIF { @@ -15,6 +20,8 @@ public: ReturnValue_t performOperation(uint8_t) override; + ReturnValue_t initialize() override; + /** * Function to get the MessageQueueId_t of the implementing object * @return MessageQueueId_t of the object @@ -23,6 +30,13 @@ public: private: MessageQueueIF* mq = nullptr; + std::string currentMountPrefix = SdCardManager::SD_0_MOUNT_POINT; + static constexpr uint32_t FS_MAX_QUEUE_SIZE = config::OBSW_FILESYSTEM_HANDLER_QUEUE_SIZE; + SdCardManager* sdcMan = nullptr; + uint8_t opCounter = 0; + + void fileSystemHandlerLoop(); + void fileSystemCheckup(); ReturnValue_t appendToFile(const char* repositoryPath, const char* filename, const uint8_t* data, size_t size, @@ -32,6 +46,9 @@ private: size_t size = 0, void* args = nullptr) override; ReturnValue_t deleteFile(const char* repositoryPath, const char* filename, void* args = nullptr) override; + ReturnValue_t createDirectory(const char* repositoryPath, void* args = nullptr) override; + ReturnValue_t removeDirectory(const char* repositoryPath, bool deleteRecurively = false, + void* args = nullptr) override; }; diff --git a/bsp_q7s/memory/SdCardAccess.cpp b/bsp_q7s/memory/SdCardAccess.cpp deleted file mode 100644 index 92837787..00000000 --- a/bsp_q7s/memory/SdCardAccess.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "SdCardAccess.h" - -#include "fsfw/ipc/MutexGuard.h" - -SdCardAccess::SdCardAccess(sd::SdCard sdCard) { - -} diff --git a/bsp_q7s/memory/SdCardAccess.h b/bsp_q7s/memory/SdCardAccess.h deleted file mode 100644 index 8128b122..00000000 --- a/bsp_q7s/memory/SdCardAccess.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef BSP_Q7S_MEMORY_SDCARDACCESS_H_ -#define BSP_Q7S_MEMORY_SDCARDACCESS_H_ - -#include "definitions.h" - -class SdCardAccess { -public: - SdCardAccess(sd::SdCard sdCard); -private: -}; - - -#endif /* BSP_Q7S_MEMORY_SDCARDACCESS_H_ */ diff --git a/bsp_q7s/memory/SdCardManager.cpp b/bsp_q7s/memory/SdCardManager.cpp index 9c47f0de..5a50665b 100644 --- a/bsp_q7s/memory/SdCardManager.cpp +++ b/bsp_q7s/memory/SdCardManager.cpp @@ -1,10 +1,13 @@ #include "SdCardManager.h" +#include "scratchApi.h" + #include "linux/utility/utility.h" #include "fsfw/ipc/MutexFactory.h" #include "fsfw/serviceinterface/ServiceInterface.h" #include +#include #include SdCardManager* SdCardManager::factoryInstance = nullptr; @@ -26,29 +29,54 @@ SdCardManager* SdCardManager::instance() { return SdCardManager::factoryInstance; } -ReturnValue_t SdCardManager::switchOnSdCard(sd::SdCard sdCard, bool doMountSdCard) { - std::pair active; - ReturnValue_t result = sdCardActive(active); +ReturnValue_t SdCardManager::switchOnSdCard(sd::SdCard sdCard, bool doMountSdCard, + SdStatusPair* statusPair) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + if(statusPair == nullptr) { + statusPair = std::make_unique().get(); + result = getSdCardActiveStatus(*statusPair); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + // Not allowed, this function turns on one SD card if(sdCard == sd::SdCard::BOTH) { sif::warning << "SdCardManager::switchOffSdCard: API does not allow sd::SdStatus::BOTH" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + + sd::SdStatus targetStatus; if(sdCard == sd::SdCard::SLOT_0) { - if(active.first == sd::SdStatus::ON or active.first == sd::SdStatus::MOUNTED) { - return ALREADY_ON; - } + targetStatus = statusPair->first; } else if(sdCard == sd::SdCard::SLOT_1) { - if(active.second == sd::SdStatus::ON or active.second == sd::SdStatus::MOUNTED) { - return ALREADY_ON; - } + targetStatus = statusPair->second; } - result = setSdCardState(sdCard, true); + + auto switchCall = [&]() { + if(targetStatus == sd::SdStatus::ON) { + if(not doMountSdCard) { + return ALREADY_ON; + } + else { + return mountSdCard(sdCard); + } + } + else if(targetStatus == sd::SdStatus::MOUNTED) { + return ALREADY_MOUNTED; + } + else if(targetStatus == sd::SdStatus::OFF) { + return setSdCardState(sdCard, true); + } + else { + return HasReturnvaluesIF::RETURN_FAILED; + } + }; + + result = switchCall(); + if(result != HasReturnvaluesIF::RETURN_OK or not doMountSdCard) { return result; } @@ -56,13 +84,14 @@ ReturnValue_t SdCardManager::switchOnSdCard(sd::SdCard sdCard, bool doMountSdCar return mountSdCard(sdCard); } -ReturnValue_t SdCardManager::switchOffSdCard(sd::SdCard sdCard, bool doUnmountSdCard) { +ReturnValue_t SdCardManager::switchOffSdCard(sd::SdCard sdCard, bool doUnmountSdCard, + SdStatusPair* statusPair) { std::pair active; - ReturnValue_t result = sdCardActive(active); + ReturnValue_t result = getSdCardActiveStatus(active); if(result != HasReturnvaluesIF::RETURN_OK) { return result; } - // Not allowed, this function turns on off SD card + // Not allowed, this function turns off one SD card if(sdCard == sd::SdCard::BOTH) { sif::warning << "SdCardManager::switchOffSdCard: API does not allow sd::SdStatus::BOTH" << std::endl; @@ -90,8 +119,9 @@ ReturnValue_t SdCardManager::switchOffSdCard(sd::SdCard sdCard, bool doUnmountSd } ReturnValue_t SdCardManager::setSdCardState(sd::SdCard sdCard, bool on) { - std::string sdstring = ""; - std::string statestring = ""; + using namespace std; + string sdstring = ""; + string statestring = ""; if(sdCard == sd::SdCard::SLOT_0) { sdstring = "0"; } @@ -104,9 +134,9 @@ ReturnValue_t SdCardManager::setSdCardState(sd::SdCard sdCard, bool on) { else { statestring = "off"; } - std::ostringstream command; + ostringstream command; command << "q7hw sd set " << sdstring << " " << statestring; - int result = std::system(command.str().c_str()); + int result = system(command.str().c_str()); if(result == 0) { return HasReturnvaluesIF::RETURN_OK; } @@ -115,7 +145,7 @@ ReturnValue_t SdCardManager::setSdCardState(sd::SdCard sdCard, bool on) { return SYSTEM_CALL_ERROR; } -ReturnValue_t SdCardManager::sdCardActive(std::pair& active) { +ReturnValue_t SdCardManager::getSdCardActiveStatus(SdStatusPair& active) { using namespace std; if(not filesystem::exists(SD_STATE_FILE)) { return STATUS_FILE_NEXISTS; @@ -143,17 +173,17 @@ ReturnValue_t SdCardManager::mountSdCard(sd::SdCard sdCard) { << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } - std::string mountDev; - std::string mountPoint; + string mountDev; + string mountPoint; if(sdCard == sd::SdCard::SLOT_0) { mountDev = SD_0_DEV_NAME; mountPoint = SD_0_MOUNT_POINT; } else if(sdCard == sd::SdCard::SLOT_1) { - mountDev = SD_0_DEV_NAME; + mountDev = SD_1_DEV_NAME; mountPoint = SD_1_MOUNT_POINT; } - if(not std::filesystem::exists(mountDev)) { + if(not filesystem::exists(mountDev)) { sif::warning << "SdCardManager::mountSdCard: Device file does not exists. Make sure to" " turn on the SD card" << std::endl; return MOUNT_ERROR; @@ -196,6 +226,28 @@ ReturnValue_t SdCardManager::unmountSdCard(sd::SdCard sdCard) { return HasReturnvaluesIF::RETURN_OK; } +ReturnValue_t SdCardManager::sanitizeState(sd::SdCard* prefSdCard, SdStatusPair* statusPair) { + if(prefSdCard == nullptr) { + prefSdCard = std::make_unique(sd::SdCard::SLOT_0).get(); + getPreferredSdCard(*prefSdCard); + } + if(statusPair == nullptr) { + statusPair = std::make_unique().get(); + getSdCardActiveStatus(*statusPair); + } + + auto sanitizerFunc = [&](sd::SdCard prefSdCard) { + if(statusPair->first == sd::SdStatus::ON) { + return mountSdCard(prefSdCard); + } + else { + return switchOnSdCard(prefSdCard, true, statusPair); + } + }; + + return sanitizerFunc(*prefSdCard); +} + void SdCardManager::processSdStatusLine(std::pair &active, std::string& line, uint8_t& idx, sd::SdCard& currentSd) { using namespace std; @@ -251,13 +303,21 @@ void SdCardManager::processSdStatusLine(std::pair &a idx++; } -sd::SdCard SdCardManager::getPreferredSdCard() const { - //int result = std::system("xsc_scratch read PREFSD > /tmp/pref_sd.txt"); - return preferredSdCard; +ReturnValue_t SdCardManager::getPreferredSdCard(sd::SdCard& sdCard) const { + uint8_t prefSdCard = 0; + ReturnValue_t result = scratch::readNumber(scratch::PREFERED_SDC_KEY, prefSdCard); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + sdCard = static_cast(prefSdCard); + return HasReturnvaluesIF::RETURN_OK; } -void SdCardManager::setPreferredSdCard(sd::SdCard sdCard) { - preferredSdCard = sdCard; +ReturnValue_t SdCardManager::setPreferredSdCard(sd::SdCard sdCard) { + if(sdCard == sd::SdCard::BOTH) { + return HasReturnvaluesIF::RETURN_FAILED; + } + return scratch::writeNumber(scratch::PREFERED_SDC_KEY, static_cast(sdCard)); } ReturnValue_t SdCardManager::updateSdCardStateFile() { diff --git a/bsp_q7s/memory/SdCardManager.h b/bsp_q7s/memory/SdCardManager.h index 810536fe..966e6e2a 100644 --- a/bsp_q7s/memory/SdCardManager.h +++ b/bsp_q7s/memory/SdCardManager.h @@ -19,19 +19,26 @@ class MutexIF; class SdCardManager { friend class SdCardAccess; public: + using SdStatusPair = std::pair; + static constexpr uint8_t INTERFACE_ID = CLASS_ID::SD_CARD_MANAGER; - static constexpr ReturnValue_t ALREADY_ON = HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 0); - static constexpr ReturnValue_t ALREADY_OFF = HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 1); - static constexpr ReturnValue_t STATUS_FILE_NEXISTS = + static constexpr ReturnValue_t ALREADY_ON = + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 0); + static constexpr ReturnValue_t ALREADY_MOUNTED = + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 1); + static constexpr ReturnValue_t ALREADY_OFF = HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 2); + static constexpr ReturnValue_t STATUS_FILE_NEXISTS = + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 10); static constexpr ReturnValue_t STATUS_FILE_FORMAT_INVALID = - HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 3); - static constexpr ReturnValue_t MOUNT_ERROR = HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 4); + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 11); + static constexpr ReturnValue_t MOUNT_ERROR = + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 12); static constexpr ReturnValue_t UNMOUNT_ERROR = - HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 5); + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 13); static constexpr ReturnValue_t SYSTEM_CALL_ERROR = - HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 6); + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 14); // C++17 does not support constexpr std::string yet static constexpr char SD_0_DEV_NAME[] = "/dev/mmcblk0p1"; @@ -49,29 +56,46 @@ public: */ static SdCardManager* instance(); - void setPreferredSdCard(sd::SdCard sdCard); + /** + * Set the preferred SD card which will determine which SD card will be used as the primary + * SD card in hot redundant and cold redundant mode. This function will not switch the + * SD cards which are currently on and mounted, this needs to be implemented by + * an upper layer by using #switchOffSdCard , #switchOnSdCard and #updateSdCardStateFile + * @param sdCard + * @return + */ + ReturnValue_t setPreferredSdCard(sd::SdCard sdCard); - sd::SdCard getPreferredSdCard() const; + /** + * Get the currently configured preferred SD card + * @param sdCard + * @return + */ + ReturnValue_t getPreferredSdCard(sd::SdCard& sdCard) const; /** * Switch on the specified SD card. * @param sdCard * @param doMountSdCard Mount the SD card after switching it on, which is necessary * to use it + * @param statusPair If the status pair is already available, it can be passed here * @return - RETURN_OK on success, ALREADY_ON if it is already on, * SYSTEM_CALL_ERROR on system error */ - ReturnValue_t switchOnSdCard(sd::SdCard sdCard, bool doMountSdCard = true); + ReturnValue_t switchOnSdCard(sd::SdCard sdCard, bool doMountSdCard = true, + SdStatusPair* statusPair = nullptr); /** * Switch off the specified SD card. * @param sdCard * @param doUnmountSdCard Unmount the SD card before switching the card off, which makes * the operation safer + * @param statusPair If the status pair is already available, it can be passed here * @return - RETURN_OK on success, ALREADY_ON if it is already on, * SYSTEM_CALL_ERROR on system error */ - ReturnValue_t switchOffSdCard(sd::SdCard sdCard, bool doUnmountSdCard = true); + ReturnValue_t switchOffSdCard(sd::SdCard sdCard, bool doUnmountSdCard = true, + SdStatusPair* statusPair = nullptr); /** * Update the state file or creates one if it does not exist. You need to call this @@ -92,7 +116,7 @@ public: * should call #updateSdCardStateFile again in that case * - STATUS_FILE_NEXISTS if the status file does not exist */ - ReturnValue_t sdCardActive(std::pair& active); + ReturnValue_t getSdCardActiveStatus(SdStatusPair& active); /** * Mount the specified SD card. This is necessary to use it. @@ -108,17 +132,26 @@ public: */ ReturnValue_t unmountSdCard(sd::SdCard sdCard); - sd::SdCard getPreferedSdCard() const; + /** + * In case that there is a discrepancy between the preferred SD card and the currently + * mounted one, this function will sanitize the state by attempting to mount the + * currently preferred SD card. If the caller already has state information, it can be + * passed into the function. + * @param prefSdCard Preferred SD card captured with #getPreferredSdCard + * @param statusPair Current SD card status capture with #getSdCardActiveStatus + * @throws std::bad_alloc if one of the two arguments was a nullptr and an allocation failed + * @return + */ + ReturnValue_t sanitizeState(sd::SdCard* prefSdCard = nullptr, + SdStatusPair* statusPair = nullptr); private: SdCardManager(); ReturnValue_t setSdCardState(sd::SdCard sdCard, bool on); - sd::SdCard preferredSdCard = sd::SdCard::SLOT_0; - - void processSdStatusLine(std::pair& active, - std::string& line, uint8_t& idx, sd::SdCard& currentSd); + void processSdStatusLine(SdStatusPair& active, std::string& line, uint8_t& idx, + sd::SdCard& currentSd); static SdCardManager* factoryInstance; }; diff --git a/bsp_q7s/memory/definitions.h b/bsp_q7s/memory/definitions.h index a2d29d9b..546a6585 100644 --- a/bsp_q7s/memory/definitions.h +++ b/bsp_q7s/memory/definitions.h @@ -12,7 +12,7 @@ enum SdStatus: uint8_t { MOUNTED = 2 }; -enum SdCard { +enum SdCard: uint8_t { SLOT_0, SLOT_1, BOTH diff --git a/bsp_q7s/memory/scratchApi.h b/bsp_q7s/memory/scratchApi.h index 09bf6bab..eceda11a 100644 --- a/bsp_q7s/memory/scratchApi.h +++ b/bsp_q7s/memory/scratchApi.h @@ -16,6 +16,8 @@ */ namespace scratch { +static constexpr char PREFERED_SDC_KEY[] = "PREFSD"; + namespace { static uint8_t counter = 0; } diff --git a/fsfw b/fsfw index 62e0465b..0b0e2e5f 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit 62e0465b3d3aad22d03be45ca4fe30f25bc38010 +Subproject commit 0b0e2e5f753193e435fa78ce8245322f874d1349 diff --git a/fsfw_hal b/fsfw_hal index 8ff09c95..1eda4874 160000 --- a/fsfw_hal +++ b/fsfw_hal @@ -1 +1 @@ -Subproject commit 8ff09c95a69f1f43fec6104d6cce1e788b2b870d +Subproject commit 1eda4874cda2a31443c435fc671fd5cae8236660 diff --git a/linux/fsfwconfig/OBSWConfig.h.in b/linux/fsfwconfig/OBSWConfig.h.in index a5a439ab..ef6b419d 100644 --- a/linux/fsfwconfig/OBSWConfig.h.in +++ b/linux/fsfwconfig/OBSWConfig.h.in @@ -14,6 +14,8 @@ #include "commonConfig.h" #include "OBSWVersion.h" +#define OBSW_FILESYSTEM_HANDLER_QUEUE_SIZE 50 + /* These defines should be disabled for mission code but are useful for debugging. */ #define OBSW_VERBOSE_LEVEL 1