Filesystem Update #53

Merged
meierj merged 17 commits from mueller/filesystem-update into develop 2021-07-22 09:03:43 +02:00
15 changed files with 640 additions and 143 deletions

View File

@ -709,6 +709,26 @@ Rebooting currently running image:
xsc_boot_copy -r xsc_boot_copy -r
``` ```
## Preparation of a fresh rootfs and SD card
This section summarizes important changes between a fresh rootfs and the current
EIVE implementation
### rootfs
- Mount point `/mnt/sd0` created for SD card 0. Created with `mkdir`
- Mount point `/mnt/sd1` created for SD card 1. Created with `mkdir`
- Folder `scripts` in `/home/root` folder.
- `scripts` folder currently contains `update_main_components.sh` script
### SD Cards
- Folder `bin` for binaries, for example the OBSW
- Folder `misc` for miscellaneous files
- Folder `tc` for telecommands
- Folder `tm` for telemetry
- Folder `xdi` for XDI components (e.g. for firmware or device tree updates)
# Running the EIVE OBSW on a Raspberry Pi # Running the EIVE OBSW on a Raspberry Pi
Special section for running the EIVE OBSW on the Raspberry Pi. Special section for running the EIVE OBSW on the Raspberry Pi.

View File

@ -4,6 +4,17 @@
#include <cstdint> #include <cstdint>
#cmakedefine01 Q7S_SIMPLE_MODE #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 #define Q7S_ADD_RTD_DEVICES 0
/* Only one of those 2 should be enabled! */ /* Only one of those 2 should be enabled! */

View File

@ -1,4 +1,6 @@
#include "CoreController.h" #include "CoreController.h"
#include "q7sConfig.h"
#include "../memory/SdCardManager.h" #include "../memory/SdCardManager.h"
CoreController::CoreController(object_id_t objectId): CoreController::CoreController(object_id_t objectId):
@ -22,39 +24,125 @@ LocalPoolDataSetBase* CoreController::getDataSetHandle(sid_t sid) {
} }
ReturnValue_t CoreController::initialize() { ReturnValue_t CoreController::initialize() {
// Find a way to store this non-volatile outside of SD cards (ProASIC?) return sdCardInit();
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);
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;
} }
ReturnValue_t CoreController::checkModeCommand(Mode_t mode, Submode_t submode, ReturnValue_t CoreController::checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) { uint32_t *msToReachTheMode) {
return HasReturnvaluesIF::RETURN_OK; 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, sd::SdStatus>(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 */
}

View File

@ -17,6 +17,8 @@ private:
LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode); uint32_t *msToReachTheMode);
ReturnValue_t sdCardInit();
}; };

View File

@ -1,6 +1,5 @@
target_sources(${TARGET_NAME} PRIVATE target_sources(${TARGET_NAME} PRIVATE
FileSystemHandler.cpp FileSystemHandler.cpp
SdCardAccess.cpp
SdCardManager.cpp SdCardManager.cpp
scratchApi.cpp scratchApi.cpp
) )

View File

@ -4,9 +4,11 @@
#include "fsfw/memory/GenericFileSystemMessage.h" #include "fsfw/memory/GenericFileSystemMessage.h"
#include "fsfw/ipc/QueueFactory.h" #include "fsfw/ipc/QueueFactory.h"
#include <filesystem>
FileSystemHandler::FileSystemHandler(object_id_t fileSystemHandler): FileSystemHandler::FileSystemHandler(object_id_t fileSystemHandler):
SystemObject(fileSystemHandler) { SystemObject(fileSystemHandler) {
mq = QueueFactory::instance()->createMessageQueue(50); mq = QueueFactory::instance()->createMessageQueue(FS_MAX_QUEUE_SIZE);
} }
FileSystemHandler::~FileSystemHandler() { FileSystemHandler::~FileSystemHandler() {
@ -15,9 +17,28 @@ FileSystemHandler::~FileSystemHandler() {
ReturnValue_t FileSystemHandler::performOperation(uint8_t unsignedChar) { ReturnValue_t FileSystemHandler::performOperation(uint8_t unsignedChar) {
while(true) { while(true) {
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
}
}
}
void FileSystemHandler::fileSystemHandlerLoop() {
CommandMessage filemsg; CommandMessage filemsg;
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
while(true) { while(true) {
if(opCounter % 5 == 0) {
fileSystemCheckup();
}
result = mq->receiveMessage(&filemsg); result = mq->receiveMessage(&filemsg);
if(result == MessageQueueIF::EMPTY) { if(result == MessageQueueIF::EMPTY) {
break; break;
@ -36,6 +57,7 @@ ReturnValue_t FileSystemHandler::performOperation(uint8_t unsignedChar) {
break; break;
} }
} }
opCounter++;
} }
// This task will have a low priority and will run permanently in the background // This task will have a low priority and will run permanently in the background
@ -43,23 +65,120 @@ ReturnValue_t FileSystemHandler::performOperation(uint8_t unsignedChar) {
// messages permanently // messages permanently
TaskFactory::instance()->delayTask(1000); 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;
}
}
} }
MessageQueueId_t FileSystemHandler::getCommandQueue() const { MessageQueueId_t FileSystemHandler::getCommandQueue() const {
return mq->getId(); 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, ReturnValue_t FileSystemHandler::appendToFile(const char *repositoryPath, const char *filename,
const uint8_t *data, size_t size, uint16_t packetNumber, void *args) { 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; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t FileSystemHandler::createFile(const char *repositoryPath, const char *filename, ReturnValue_t FileSystemHandler::createFile(const char *repositoryPath, const char *filename,
const uint8_t *data, size_t size, void *args) { 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; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t FileSystemHandler::deleteFile(const char *repositoryPath, const char *filename, ReturnValue_t FileSystemHandler::deleteFile(const char *repositoryPath, const char *filename,
void *args) { 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; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -1,11 +1,16 @@
#ifndef BSP_Q7S_MEMORY_FILESYSTEMHANDLER_H_ #ifndef BSP_Q7S_MEMORY_FILESYSTEMHANDLER_H_
#define BSP_Q7S_MEMORY_FILESYSTEMHANDLER_H_ #define BSP_Q7S_MEMORY_FILESYSTEMHANDLER_H_
#include "SdCardManager.h"
#include "OBSWConfig.h"
#include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/ipc/MessageQueueIF.h"
#include "fsfw/tasks/ExecutableObjectIF.h" #include "fsfw/tasks/ExecutableObjectIF.h"
#include "fsfw/objectmanager/SystemObject.h" #include "fsfw/objectmanager/SystemObject.h"
#include "fsfw/memory/HasFileSystemIF.h" #include "fsfw/memory/HasFileSystemIF.h"
#include <string>
class FileSystemHandler: public SystemObject, class FileSystemHandler: public SystemObject,
public ExecutableObjectIF, public ExecutableObjectIF,
public HasFileSystemIF { public HasFileSystemIF {
@ -15,6 +20,8 @@ public:
ReturnValue_t performOperation(uint8_t) override; ReturnValue_t performOperation(uint8_t) override;
ReturnValue_t initialize() override;
/** /**
* Function to get the MessageQueueId_t of the implementing object * Function to get the MessageQueueId_t of the implementing object
* @return MessageQueueId_t of the object * @return MessageQueueId_t of the object
@ -23,6 +30,13 @@ public:
private: private:
MessageQueueIF* mq = nullptr; 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, ReturnValue_t appendToFile(const char* repositoryPath,
const char* filename, const uint8_t* data, size_t size, const char* filename, const uint8_t* data, size_t size,
@ -32,6 +46,9 @@ private:
size_t size = 0, void* args = nullptr) override; size_t size = 0, void* args = nullptr) override;
ReturnValue_t deleteFile(const char* repositoryPath, ReturnValue_t deleteFile(const char* repositoryPath,
const char* filename, void* args = nullptr) override; 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;
}; };

View File

@ -1,7 +0,0 @@
#include "SdCardAccess.h"
#include "fsfw/ipc/MutexGuard.h"
SdCardAccess::SdCardAccess(sd::SdCard sdCard) {
}

View File

@ -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_ */

View File

@ -1,8 +1,13 @@
#include "SdCardManager.h" #include "SdCardManager.h"
#include "scratchApi.h"
#include "linux/utility/utility.h"
#include "fsfw/ipc/MutexFactory.h" #include "fsfw/ipc/MutexFactory.h"
#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/serviceinterface/ServiceInterface.h"
#include <fstream> #include <fstream>
#include <memory>
#include <filesystem> #include <filesystem>
SdCardManager* SdCardManager::factoryInstance = nullptr; SdCardManager* SdCardManager::factoryInstance = nullptr;
@ -24,35 +29,99 @@ SdCardManager* SdCardManager::instance() {
return SdCardManager::factoryInstance; return SdCardManager::factoryInstance;
} }
ReturnValue_t SdCardManager::switchOnSdCard(sd::SdCard sdCard) { ReturnValue_t SdCardManager::switchOnSdCard(sd::SdCard sdCard, bool doMountSdCard,
std::pair<bool, bool> active; SdStatusPair* statusPair) {
ReturnValue_t result = sdCardActive(active); ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
if(statusPair == nullptr) {
statusPair = std::make_unique<SdStatusPair>().get();
result = getSdCardActiveStatus(*statusPair);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
if((sdCard == sd::SdCard::SLOT_0 and active.first) or
(sdCard == sd::SdCard::SLOT_1 and active.second)) {
return ALREADY_ON;
}
return setSdCardState(sdCard, true);
} }
ReturnValue_t SdCardManager::switchOffSdCard(sd::SdCard sdCard) { // Not allowed, this function turns on one SD card
std::pair<bool, bool> active; if(sdCard == sd::SdCard::BOTH) {
ReturnValue_t result = sdCardActive(active); sif::warning << "SdCardManager::switchOffSdCard: API does not allow sd::SdStatus::BOTH"
<< std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
sd::SdStatus targetStatus;
if(sdCard == sd::SdCard::SLOT_0) {
targetStatus = statusPair->first;
}
else if(sdCard == sd::SdCard::SLOT_1) {
targetStatus = statusPair->second;
}
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;
}
return mountSdCard(sdCard);
}
ReturnValue_t SdCardManager::switchOffSdCard(sd::SdCard sdCard, bool doUnmountSdCard,
SdStatusPair* statusPair) {
std::pair<sd::SdStatus, sd::SdStatus> active;
ReturnValue_t result = getSdCardActiveStatus(active);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
if((sdCard == sd::SdCard::SLOT_0 and not active.first) or // Not allowed, this function turns off one SD card
(sdCard == sd::SdCard::SLOT_1 and not active.second)) { 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; 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); return setSdCardState(sdCard, false);
} }
ReturnValue_t SdCardManager::setSdCardState(sd::SdCard sdCard, bool on) { ReturnValue_t SdCardManager::setSdCardState(sd::SdCard sdCard, bool on) {
std::string sdstring = ""; using namespace std;
std::string statestring = ""; string sdstring = "";
string statestring = "";
if(sdCard == sd::SdCard::SLOT_0) { if(sdCard == sd::SdCard::SLOT_0) {
sdstring = "0"; sdstring = "0";
} }
@ -65,9 +134,9 @@ ReturnValue_t SdCardManager::setSdCardState(sd::SdCard sdCard, bool on) {
else { else {
statestring = "off"; statestring = "off";
} }
std::ostringstream command; ostringstream command;
command << "q7hw sd set " << sdstring << " " << statestring; command << "q7hw sd set " << sdstring << " " << statestring;
int result = std::system(command.str().c_str()); int result = system(command.str().c_str());
if(result == 0) { if(result == 0) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -76,71 +145,185 @@ ReturnValue_t SdCardManager::setSdCardState(sd::SdCard sdCard, bool on) {
return SYSTEM_CALL_ERROR; return SYSTEM_CALL_ERROR;
} }
ReturnValue_t SdCardManager::sdCardActive(std::pair<bool, bool>& active) { ReturnValue_t SdCardManager::getSdCardActiveStatus(SdStatusPair& active) {
using namespace std; using namespace std;
if(not filesystem::exists("/tmp/sd_status.txt")) { if(not filesystem::exists(SD_STATE_FILE)) {
return STATUS_FILE_NEXISTS; return STATUS_FILE_NEXISTS;
} }
// Now the file should exist in any case. Still check whether it exists. // Now the file should exist in any case. Still check whether it exists.
fstream sdStatus("/tmp/sd_status.txt"); fstream sdStatus(SD_STATE_FILE);
if (not sdStatus.good()) { if (not sdStatus.good()) {
return STATUS_FILE_NEXISTS; return STATUS_FILE_NEXISTS;
} }
string line; string line;
uint8_t idx = 0; uint8_t idx = 0;
sd::SdCard currentSd = sd::SdCard::SLOT_0;
// Process status file line by line
while (std::getline(sdStatus, line)) { while (std::getline(sdStatus, line)) {
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;
}
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_1_DEV_NAME;
mountPoint = SD_1_MOUNT_POINT;
}
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;
}
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;
}
ReturnValue_t SdCardManager::sanitizeState(sd::SdCard* prefSdCard, SdStatusPair* statusPair) {
if(prefSdCard == nullptr) {
prefSdCard = std::make_unique<sd::SdCard>(sd::SdCard::SLOT_0).get();
getPreferredSdCard(*prefSdCard);
}
if(statusPair == nullptr) {
statusPair = std::make_unique<SdStatusPair>().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<sd::SdStatus, sd::SdStatus> &active,
std::string& line, uint8_t& idx, sd::SdCard& currentSd) {
using namespace std;
istringstream iss(line); istringstream iss(line);
string word; string word;
sd::SdCard currentSd = sd::SdCard::SLOT_0; bool slotLine = false;
bool mountLine = false;
while(iss >> word) { while(iss >> word) {
if (word == "Slot") {
slotLine = true;
}
if(word == "Mounted") {
mountLine = true;
}
if(slotLine) {
if (word == "1:") { if (word == "1:") {
currentSd = sd::SdCard::SLOT_1; currentSd = sd::SdCard::SLOT_1;
} }
if(word == "on") { if(word == "on") {
if(currentSd == sd::SdCard::SLOT_0) { if(currentSd == sd::SdCard::SLOT_0) {
active.first = true; active.first = sd::SdStatus::ON;
} }
else { else {
active.second = true; active.second = sd::SdStatus::ON;
} }
} }
else if (word == "off") { else if (word == "off") {
if(currentSd == sd::SdCard::SLOT_0) { if(currentSd == sd::SdCard::SLOT_0) {
active.first = false; active.first = sd::SdStatus::OFF;
} }
else { else {
active.second = false; active.second = sd::SdStatus::OFF;
} }
} }
else {
continue;
} }
if(idx > 3) { if(mountLine) {
sif::warning << "SdCardManager::sdCardActive: Status file has more " if(currentSd == sd::SdCard::SLOT_0) {
"than 4 lines!" << std::endl; active.first = sd::SdStatus::MOUNTED;
return STATUS_FILE_FORMAT_INVALID; }
else {
active.second = sd::SdStatus::MOUNTED;
}
}
if(idx > 5) {
sif::warning << "SdCardManager::sdCardActive: /tmp/sd_status.txt has more than 6 "
"lines and might be invalid!" << std::endl;
} }
} }
idx++; idx++;
} }
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<sd::SdCard>(prefSdCard);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
sd::SdCard SdCardManager::getPreferredSdCard() const { ReturnValue_t SdCardManager::setPreferredSdCard(sd::SdCard sdCard) {
//int result = std::system("xsc_scratch read PREFSD > /tmp/pref_sd.txt"); if(sdCard == sd::SdCard::BOTH) {
return preferredSdCard; return HasReturnvaluesIF::RETURN_FAILED;
} }
return scratch::writeNumber(scratch::PREFERED_SDC_KEY, static_cast<uint8_t>(sdCard));
void SdCardManager::setPreferredSdCard(sd::SdCard sdCard) {
preferredSdCard = sdCard;
} }
ReturnValue_t SdCardManager::updateSdCardStateFile() { ReturnValue_t SdCardManager::updateSdCardStateFile() {
int result = std::system("q7hw sd info all > /tmp/sd_status.txt"); // Use q7hw utility and pipe the command output into the state file
std::string updateCmd = "q7hw sd info all > " + std::string(SD_STATE_FILE);
int result = std::system(updateCmd.c_str());
if(result == 0) { if(result == 0) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -8,6 +8,7 @@
#include <cstdint> #include <cstdint>
#include <utility> #include <utility>
#include <string>
class MutexIF; class MutexIF;
@ -18,16 +19,33 @@ class MutexIF;
class SdCardManager { class SdCardManager {
friend class SdCardAccess; friend class SdCardAccess;
public: public:
using SdStatusPair = std::pair<sd::SdStatus, sd::SdStatus>;
static constexpr uint8_t INTERFACE_ID = CLASS_ID::SD_CARD_MANAGER; 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_ON =
static constexpr ReturnValue_t ALREADY_OFF = HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 1); HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 0);
static constexpr ReturnValue_t STATUS_FILE_NEXISTS = static constexpr ReturnValue_t ALREADY_MOUNTED =
HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 1);
static constexpr ReturnValue_t ALREADY_OFF =
HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 2); 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 = static constexpr ReturnValue_t STATUS_FILE_FORMAT_INVALID =
HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 3); 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 = static constexpr ReturnValue_t SYSTEM_CALL_ERROR =
HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 4); HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 14);
// 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(); virtual ~SdCardManager();
@ -38,29 +56,50 @@ public:
*/ */
static SdCardManager* instance(); 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::SdCard getPreferredSdCard() const; * 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);
/** /**
* Switch on the specified SD card * Get the currently configured preferred SD card
* @param sdCard * @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, * @return - RETURN_OK on success, ALREADY_ON if it is already on,
* SYSTEM_CALL_ERROR on system error * SYSTEM_CALL_ERROR on system error
*/ */
ReturnValue_t switchOnSdCard(sd::SdCard sdCard); ReturnValue_t switchOnSdCard(sd::SdCard sdCard, bool doMountSdCard = true,
SdStatusPair* statusPair = nullptr);
/** /**
* Switch off the specified SD card * Switch off the specified SD card.
* @param sdCard * @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, * @return - RETURN_OK on success, ALREADY_ON if it is already on,
* SYSTEM_CALL_ERROR on system error * SYSTEM_CALL_ERROR on system error
*/ */
ReturnValue_t switchOffSdCard(sd::SdCard sdCard); ReturnValue_t switchOffSdCard(sd::SdCard sdCard, bool doUnmountSdCard = true,
SdStatusPair* statusPair = nullptr);
/** /**
* Updated the state file or creates one if it does not exist. You need to call this * Update the state file or creates one if it does not exist. You need to call this
* function before calling #sdCardActiv * function before calling #sdCardActive
* @return - RETURN_OK if the state file was updated successfully * @return - RETURN_OK if the state file was updated successfully
* - SYSTEM_CALL_ERROR if the call to create the status file failed * - SYSTEM_CALL_ERROR if the call to create the status file failed
*/ */
@ -77,16 +116,42 @@ public:
* should call #updateSdCardStateFile again in that case * should call #updateSdCardStateFile again in that case
* - STATUS_FILE_NEXISTS if the status file does not exist * - STATUS_FILE_NEXISTS if the status file does not exist
*/ */
ReturnValue_t sdCardActive(std::pair<bool, bool>& active); ReturnValue_t getSdCardActiveStatus(SdStatusPair& active);
sd::SdCard getPreferedSdCard() const; /**
* 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 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: private:
SdCardManager(); SdCardManager();
ReturnValue_t setSdCardState(sd::SdCard sdCard, bool on); ReturnValue_t setSdCardState(sd::SdCard sdCard, bool on);
sd::SdCard preferredSdCard = sd::SdCard::SLOT_0; void processSdStatusLine(SdStatusPair& active, std::string& line, uint8_t& idx,
sd::SdCard& currentSd);
static SdCardManager* factoryInstance; static SdCardManager* factoryInstance;
}; };

View File

@ -1,9 +1,18 @@
#ifndef BSP_Q7S_MEMORY_DEFINITIONS_H_ #ifndef BSP_Q7S_MEMORY_DEFINITIONS_H_
#define BSP_Q7S_MEMORY_DEFINITIONS_H_ #define BSP_Q7S_MEMORY_DEFINITIONS_H_
#include <cstdint>
namespace sd { namespace sd {
enum SdCard { enum SdStatus: uint8_t {
OFF = 0,
ON = 1,
// A mounted SD card is on as well
MOUNTED = 2
};
enum SdCard: uint8_t {
SLOT_0, SLOT_0,
SLOT_1, SLOT_1,
BOTH BOTH

View File

@ -16,6 +16,8 @@
*/ */
namespace scratch { namespace scratch {
static constexpr char PREFERED_SDC_KEY[] = "PREFSD";
namespace { namespace {
static uint8_t counter = 0; static uint8_t counter = 0;
} }

2
fsfw

@ -1 +1 @@
Subproject commit eef2fd3b7ac764f06ed5d9a3c97c894d92a515fa Subproject commit da8a4470734808bed4d872e47c192af694382c41

View File

@ -14,6 +14,8 @@
#include "commonConfig.h" #include "commonConfig.h"
#include "OBSWVersion.h" #include "OBSWVersion.h"
#define OBSW_FILESYSTEM_HANDLER_QUEUE_SIZE 50
/* These defines should be disabled for mission code but are useful for /* These defines should be disabled for mission code but are useful for
debugging. */ debugging. */
#define OBSW_VERBOSE_LEVEL 1 #define OBSW_VERBOSE_LEVEL 1