diff --git a/bsp_q7s/memory/SdCardManager.cpp b/bsp_q7s/memory/SdCardManager.cpp index af963180..8c67ea2c 100644 --- a/bsp_q7s/memory/SdCardManager.cpp +++ b/bsp_q7s/memory/SdCardManager.cpp @@ -1,4 +1,6 @@ #include "SdCardManager.h" +#include "linux/utility/utility.h" + #include "fsfw/ipc/MutexFactory.h" #include "fsfw/serviceinterface/ServiceInterface.h" @@ -24,29 +26,66 @@ SdCardManager* SdCardManager::instance() { return SdCardManager::factoryInstance; } -ReturnValue_t SdCardManager::switchOnSdCard(sd::SdCard sdCard) { - std::pair active; +ReturnValue_t SdCardManager::switchOnSdCard(sd::SdCard sdCard, bool doMountSdCard) { + std::pair active; ReturnValue_t result = sdCardActive(active); + // 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; } - if((sdCard == sd::SdCard::SLOT_0 and active.first) or - (sdCard == sd::SdCard::SLOT_1 and active.second)) { - return ALREADY_ON; + if(sdCard == sd::SdCard::SLOT_0) { + if(active.first == sd::SdStatus::ON or active.first == sd::SdStatus::MOUNTED) { + return ALREADY_ON; + } } - return setSdCardState(sdCard, true); + else if(sdCard == sd::SdCard::SLOT_1) { + if(active.second == sd::SdStatus::ON or active.second == sd::SdStatus::MOUNTED) { + return ALREADY_ON; + } + } + result = setSdCardState(sdCard, true); + if(result != HasReturnvaluesIF::RETURN_OK or not doMountSdCard) { + return result; + } + + return mountSdCard(sdCard); } -ReturnValue_t SdCardManager::switchOffSdCard(sd::SdCard sdCard) { - std::pair active; +ReturnValue_t SdCardManager::switchOffSdCard(sd::SdCard sdCard, bool doUnmountSdCard) { + std::pair active; ReturnValue_t result = sdCardActive(active); if(result != HasReturnvaluesIF::RETURN_OK) { return result; } - if((sdCard == sd::SdCard::SLOT_0 and not active.first) or - (sdCard == sd::SdCard::SLOT_1 and not active.second)) { - return ALREADY_OFF; + // Not allowed, this function turns on off 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(sdCard == sd::SdCard::SLOT_0) { + if(active.first == sd::SdStatus::OFF) { + return ALREADY_OFF; + } + } + else if(sdCard == sd::SdCard::SLOT_1) { + if(active.second == sd::SdStatus::OFF) { + return ALREADY_OFF; + } + } + + if(doUnmountSdCard) { + result = unmountSdCard(sdCard); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return setSdCardState(sdCard, false); } @@ -76,7 +115,7 @@ ReturnValue_t SdCardManager::setSdCardState(sd::SdCard sdCard, bool on) { return SYSTEM_CALL_ERROR; } -ReturnValue_t SdCardManager::sdCardActive(std::pair& active) { +ReturnValue_t SdCardManager::sdCardActive(std::pair& active) { using namespace std; if(not filesystem::exists("/tmp/sd_status.txt")) { return STATUS_FILE_NEXISTS; @@ -89,45 +128,127 @@ ReturnValue_t SdCardManager::sdCardActive(std::pair& active) { } string line; uint8_t idx = 0; - + sd::SdCard currentSd = sd::SdCard::SLOT_0; + // Process status file line by line while (std::getline(sdStatus, line)) { - istringstream iss(line); - string word; - sd::SdCard currentSd = sd::SdCard::SLOT_0; - while(iss >> word) { + processSdStatusLine(active, line, idx, currentSd); + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t SdCardManager::mountSdCard(sd::SdCard sdCard) { + using namespace std; + if(sdCard == sd::SdCard::BOTH) { + sif::warning << "SdCardManager::mountSdCard: API does not allow sd::SdStatus::BOTH" + << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + std::string mountDev; + std::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; + mountPoint = SD_1_MOUNT_POINT; + } + if(not std::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; + } + + 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; +} + +ReturnValue_t SdCardManager::unmountSdCard(sd::SdCard sdCard) { + using namespace std; + if(sdCard == sd::SdCard::BOTH) { + sif::warning << "SdCardManager::unmountSdCard: API does not allow sd::SdStatus::BOTH" + << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + string mountPoint; + if(sdCard == sd::SdCard::SLOT_0) { + mountPoint = SD_0_MOUNT_POINT; + } + else if(sdCard == sd::SdCard::SLOT_1) { + mountPoint = SD_1_MOUNT_POINT; + } + if(filesystem::is_empty(mountPoint)) { + // The mount point will always exist, but if it is empty, that is strong hint that + // the SD card was not mounted properly. Still proceed with operation. + 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; +} + +void SdCardManager::processSdStatusLine(std::pair &active, + std::string& line, uint8_t& idx, sd::SdCard& currentSd) { + using namespace std; + istringstream iss(line); + string word; + bool slotLine = false; + bool mountLine = false; + while(iss >> word) { + if (word == "Slot") { + slotLine = true; + } + if(word == "Mounted") { + mountLine = true; + } + + if(slotLine) { if (word == "1:") { currentSd = sd::SdCard::SLOT_1; } if(word == "on") { if(currentSd == sd::SdCard::SLOT_0) { - active.first = true; + active.first = sd::SdStatus::ON; } else { - active.second = true; + active.second = sd::SdStatus::ON; } } else if (word == "off") { if(currentSd == sd::SdCard::SLOT_0) { - active.first = false; + active.first = sd::SdStatus::OFF; } else { - active.second = false; + active.second = sd::SdStatus::OFF; } } - else { - continue; - } + } - if(idx > 3) { - sif::warning << "SdCardManager::sdCardActive: Status file has more " - "than 4 lines!" << std::endl; - return STATUS_FILE_FORMAT_INVALID; + if(mountLine) { + if(currentSd == sd::SdCard::SLOT_0) { + active.first = sd::SdStatus::MOUNTED; + } + else { + active.second = sd::SdStatus::MOUNTED; } } - idx++; + + if(idx > 5) { + sif::warning << "SdCardManager::sdCardActive: /tmp/sd_status.txt has more than 6 " + "lines and might be invalid!" << std::endl; + } } - return HasReturnvaluesIF::RETURN_OK; + idx++; } sd::SdCard SdCardManager::getPreferredSdCard() const { diff --git a/bsp_q7s/memory/SdCardManager.h b/bsp_q7s/memory/SdCardManager.h index 0c9c664d..9052d9b0 100644 --- a/bsp_q7s/memory/SdCardManager.h +++ b/bsp_q7s/memory/SdCardManager.h @@ -8,6 +8,7 @@ #include #include +#include class MutexIF; @@ -26,8 +27,17 @@ public: HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 2); static constexpr ReturnValue_t STATUS_FILE_FORMAT_INVALID = HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 3); + static constexpr ReturnValue_t MOUNT_ERROR = HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 4); + static constexpr ReturnValue_t UNMOUNT_ERROR = + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 5); static constexpr ReturnValue_t SYSTEM_CALL_ERROR = - HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 4); + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 6); + + // C++17 does not support constexpr std::string yet + static constexpr char SD_0_DEV_NAME[] = "/dev/mmcblk0p1"; + static constexpr char SD_1_DEV_NAME[] = "/dev/mmcblk1p1"; + static constexpr char SD_0_MOUNT_POINT[] = "/mnt/sd0"; + static constexpr char SD_1_MOUNT_POINT[] = "/mnt/sd1"; virtual ~SdCardManager(); @@ -45,18 +55,22 @@ public: /** * Switch on the specified SD card * @param sdCard + * @param doMountSdCard Mount the SD card after switching it on, which is necessary + * to use it * @return - RETURN_OK on success, ALREADY_ON if it is already on, * SYSTEM_CALL_ERROR on system error */ - ReturnValue_t switchOnSdCard(sd::SdCard sdCard); + ReturnValue_t switchOnSdCard(sd::SdCard sdCard, bool doMountSdCard = true); /** * Switch off the specified SD card * @param sdCard + * @param doUnmountSdCard Unmount the SD card before switching the card off, which makes + * the operation safer * @return - RETURN_OK on success, ALREADY_ON if it is already on, * SYSTEM_CALL_ERROR on system error */ - ReturnValue_t switchOffSdCard(sd::SdCard sdCard); + ReturnValue_t switchOffSdCard(sd::SdCard sdCard, bool doUnmountSdCard = true); /** * Updated the state file or creates one if it does not exist. You need to call this @@ -77,7 +91,10 @@ 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 sdCardActive(std::pair& active); + + ReturnValue_t mountSdCard(sd::SdCard sdCard); + ReturnValue_t unmountSdCard(sd::SdCard sdCard); sd::SdCard getPreferedSdCard() const; @@ -88,6 +105,9 @@ private: sd::SdCard preferredSdCard = sd::SdCard::SLOT_0; + void processSdStatusLine(std::pair& 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 9a998dcc..a2d29d9b 100644 --- a/bsp_q7s/memory/definitions.h +++ b/bsp_q7s/memory/definitions.h @@ -1,8 +1,17 @@ #ifndef BSP_Q7S_MEMORY_DEFINITIONS_H_ #define BSP_Q7S_MEMORY_DEFINITIONS_H_ +#include + namespace sd { +enum SdStatus: uint8_t { + OFF = 0, + ON = 1, + // A mounted SD card is on as well + MOUNTED = 2 +}; + enum SdCard { SLOT_0, SLOT_1,