#ifndef BSP_Q7S_MEMORY_SDCARDACCESSMANAGER_H_ #define BSP_Q7S_MEMORY_SDCARDACCESSMANAGER_H_ #include "definitions.h" #include "returnvalues/classIds.h" #include "events/subsystemIdRanges.h" #include "fsfw/events/Event.h" #include "fsfw/returnvalues/HasReturnvaluesIF.h" #include #include #include #include #include #include class MutexIF; /** * @brief Manages handling of SD cards like switching them on or off or getting the current * state */ 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 OP_ONGOING = HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 0); static constexpr ReturnValue_t ALREADY_ON = HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 1); 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 = 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, 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; static constexpr Event SANITIZATION_FAILED = event::makeEvent(SUBSYSTEM_ID, 0, severity::LOW); // 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"; static constexpr char SD_STATE_FILE[] = "/tmp/sd_status.txt"; virtual ~SdCardManager(); static void create(); /** * Returns the single instance of the SD card manager. */ static SdCardManager* instance(); /** * 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); /** * 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, 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, SdStatusPair* statusPair = nullptr); /** * Update the state file or creates one if it does not exist. You need to call this * function before calling #sdCardActive * @return - RETURN_OK if the state file was updated successfully * - SYSTEM_CALL_ERROR if the call to create the status file failed */ ReturnValue_t updateSdCardStateFile(); /** * Get the state of the SD cards. If the state file does not exist, this function will * take care of updating it. If it does not, the function will use the state file to get * the status of the SD cards and set the field of the provided boolean pair. * @param active Pair of booleans, where the first entry is the state of the first SD card * and the second one the state of the second SD card * @return - RETURN_OK if the state was read successfully * - STATUS_FILE_FORMAT_INVALID if there was an issue with the state file. The user * should call #updateSdCardStateFile again in that case * - STATUS_FILE_NEXISTS if the status file does not exist */ ReturnValue_t getSdCardActiveStatus(SdStatusPair& active); /** * Mount the specified SD card. This is necessary to use it. * @param sdCard * @return */ ReturnValue_t mountSdCard(sd::SdCard sdCard); /** * Unmount the specified SD card. This is recommended before switching it off. The SD card * can't be used after it has been unmounted. * @param sdCard * @return */ ReturnValue_t unmountSdCard(sd::SdCard sdCard); /** * 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 statusPair Current SD card status capture with #getSdCardActiveStatus * @param prefSdCard Preferred SD card captured with #getPreferredSdCard * @throws std::bad_alloc if one of the two arguments was a nullptr and an allocation failed * @return */ ReturnValue_t sanitizeState(SdStatusPair* statusPair = nullptr, sd::SdCard prefSdCard = sd::SdCard::NONE); /** * If sd::SdCard::NONE is passed as an argument, this funtion will get the currently * preferred SD card from the scratch buffer. * @param prefSdCardPtr * @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); void processSdStatusLine(SdStatusPair& active, std::string& line, uint8_t& idx, sd::SdCard& currentSd); std::string currentPrefix; ReturnValue_t handleCommand(std::string cmd, std::string funcName); ReturnValue_t handleBlockingOperation(std::string funcName); static SdCardManager* factoryInstance; }; #endif /* BSP_Q7S_MEMORY_SDCARDACCESSMANAGER_H_ */