247 lines
8.9 KiB
C++
247 lines
8.9 KiB
C++
#ifndef BSP_Q7S_MEMORY_SDCARDACCESSMANAGER_H_
|
|
#define BSP_Q7S_MEMORY_SDCARDACCESSMANAGER_H_
|
|
|
|
#include <fsfw/objectmanager/SystemObject.h>
|
|
#include <poll.h>
|
|
|
|
#include <array>
|
|
#include <cstdint>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
#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 CoreController;
|
|
|
|
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<sd::SdState, sd::SdState>;
|
|
|
|
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<sd::SdCard> 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, SdStatePair& sdStates, bool doUnmountSdCard);
|
|
|
|
/**
|
|
* 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<sd::SdCard> 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<sd::SdCard> 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();
|
|
void markUsable();
|
|
|
|
private:
|
|
CommandExecutor cmdExecutor;
|
|
SdStatePair sdStates;
|
|
Operations currentOp = Operations::IDLE;
|
|
bool blocking = false;
|
|
bool sdCardActive = true;
|
|
bool printCmdOutput = true;
|
|
bool markedUnusable = false;
|
|
MutexIF* sdLock = nullptr;
|
|
MutexIF* prefLock = nullptr;
|
|
MutexIF* defaultLock = nullptr;
|
|
static constexpr MutexIF::TimeoutType LOCK_TYPE = MutexIF::TimeoutType::WAITING;
|
|
static constexpr uint32_t SD_LOCK_TIMEOUT = 100;
|
|
static constexpr uint32_t OTHER_TIMEOUT = 20;
|
|
static constexpr char LOCK_CTX[] = "SdCardManager";
|
|
|
|
SdCardManager();
|
|
|
|
/**
|
|
* 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();
|
|
|
|
ReturnValue_t setSdCardState(sd::SdCard sdCard, bool on);
|
|
|
|
void processSdStatusLine(std::string& line, uint8_t& idx, sd::SdCard& currentSd);
|
|
|
|
std::optional<std::string> currentPrefix;
|
|
|
|
static SdCardManager* INSTANCE;
|
|
};
|
|
|
|
#endif /* BSP_Q7S_MEMORY_SDCARDACCESSMANAGER_H_ */
|