#ifndef BSP_Q7S_MEMORY_SDCARDACCESSMANAGER_H_ #define BSP_Q7S_MEMORY_SDCARDACCESSMANAGER_H_ #include #include #include #include #include #include #include #include "events/subsystemIdRanges.h" #include "fsfw/events/Event.h" #include "fsfw/returnvalues/returnvalue.h" #include "fsfw_hal/linux/CommandExecutor.h" #include "mission/memory/SdCardMountedIF.h" #include "mission/memory/definitions.h" #include "returnvalues/classIds.h" class MutexIF; /** * @brief Manages handling of SD cards like switching them on or off or getting the current * state */ class SdCardManager : public SystemObject, public SdCardMountedIF { friend class SdCardAccess; public: using mountInitCb = ReturnValue_t (*)(void* args); enum class Operations { SWITCHING_ON, SWITCHING_OFF, MOUNTING, UNMOUNTING, IDLE }; enum class OpStatus { IDLE, TIMEOUT, ONGOING, SUCCESS, FAIL }; using SdStatePair = std::pair; struct SdInfo { sd::SdCard pref = sd::SdCard::NONE; sd::SdCard other = sd::SdCard::NONE; sd::SdCard active = sd::SdCard::NONE; } sdInfo; static constexpr uint8_t INTERFACE_ID = CLASS_ID::SD_CARD_MANAGER; static constexpr ReturnValue_t OP_ONGOING = returnvalue::makeCode(INTERFACE_ID, 0); static constexpr ReturnValue_t ALREADY_ON = returnvalue::makeCode(INTERFACE_ID, 1); static constexpr ReturnValue_t ALREADY_MOUNTED = returnvalue::makeCode(INTERFACE_ID, 2); static constexpr ReturnValue_t ALREADY_OFF = returnvalue::makeCode(INTERFACE_ID, 3); static constexpr ReturnValue_t STATUS_FILE_NEXISTS = returnvalue::makeCode(INTERFACE_ID, 10); static constexpr ReturnValue_t STATUS_FILE_FORMAT_INVALID = returnvalue::makeCode(INTERFACE_ID, 11); static constexpr ReturnValue_t MOUNT_ERROR = returnvalue::makeCode(INTERFACE_ID, 12); static constexpr ReturnValue_t UNMOUNT_ERROR = returnvalue::makeCode(INTERFACE_ID, 13); static constexpr ReturnValue_t SYSTEM_CALL_ERROR = returnvalue::makeCode(INTERFACE_ID, 14); static constexpr ReturnValue_t POPEN_CALL_ERROR = returnvalue::makeCode(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); static constexpr Event MOUNTED_SD_CARD = event::makeEvent(SUBSYSTEM_ID, 1, severity::INFO); // 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_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 */ std::optional getPreferredSdCard() const override; /** * 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 - returnvalue::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, SdStatePair* 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 - returnvalue::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, SdStatePair* statusPair = nullptr); /** * Update the state file or creates one if it does not exist. You need to call this * function before calling #sdCardActive * @return * - returnvalue::OK if the state file was updated successfully * - CommandExecutor::COMMAND_PENDING: Non-blocking command is pending * - returnvalue::FAILED: blocking command 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 - returnvalue::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 getSdCardsStatus(SdStatePair& active); /** * Mount the specified SD card. This is necessary to use it. * @param sdCard * @return */ ReturnValue_t mountSdCard(sd::SdCard sdCard); /** * Set the currently active SD card. This does not necessarily mean that the SD card is on or * mounted * @param sdCard */ void setActiveSdCard(sd::SdCard sdCard) override; /** * Get the currently active SD card. This does not necessarily mean that the SD card is on or * mounted * @return */ std::optional getActiveSdCard() const override; /** * 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. For now, this operation will be enforced in blocking mode. * @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(SdStatePair* statusPair = nullptr, sd::SdCard prefSdCard = sd::SdCard::NONE); /** * If sd::SdCard::NONE is passed as an argument, this function will get the currently * preferred SD card from the scratch buffer. * @param prefSdCardPtr * @return */ const char* getCurrentMountPrefix() const override; 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); void setPrintCommandOutput(bool print); /** * @brief Checks if an SD card is mounted. * * @param sdCard The SD card to check * * @return true if mounted, otherwise false */ bool isSdCardUsable(std::optional sdCard) override; ReturnValue_t isSdCardMountedReadOnly(sd::SdCard sdcard, bool& readOnly); ReturnValue_t remountReadWrite(sd::SdCard sdcard); ReturnValue_t performFsck(sd::SdCard sdcard, bool printOutput, int& linuxError); void markUnusable(); private: CommandExecutor cmdExecutor; Operations currentOp = Operations::IDLE; bool blocking = false; bool sdCardActive = true; bool printCmdOutput = true; bool markedUnusable = false; MutexIF* sdLock = nullptr; static constexpr MutexIF::TimeoutType LOCK_TYPE = MutexIF::TimeoutType::WAITING; static constexpr uint32_t LOCK_TIMEOUT = 200; static constexpr char LOCK_CTX[] = "SdCardManager"; SdCardManager(); ReturnValue_t setSdCardState(sd::SdCard sdCard, bool on); void processSdStatusLine(SdStatePair& active, std::string& line, uint8_t& idx, sd::SdCard& currentSd); std::optional currentPrefix; static SdCardManager* INSTANCE; }; #endif /* BSP_Q7S_MEMORY_SDCARDACCESSMANAGER_H_ */