fixed merge conflicts
This commit is contained in:
@ -2,13 +2,15 @@ target_sources(${TARGET_NAME} PUBLIC
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_subdirectory(boardtest)
|
||||
|
||||
if(Q7S_SIMPLE_MODE)
|
||||
add_subdirectory(simple)
|
||||
else()
|
||||
add_subdirectory(boardconfig)
|
||||
add_subdirectory(comIF)
|
||||
add_subdirectory(boardtest)
|
||||
add_subdirectory(gpio)
|
||||
add_subdirectory(core)
|
||||
add_subdirectory(spiCallbacks)
|
||||
add_subdirectory(memory)
|
||||
add_subdirectory(spiCallbacks)
|
||||
endif()
|
||||
|
@ -1,7 +1,20 @@
|
||||
#ifndef BSP_Q7S_BOARDCONFIG_Q7S_CONFIG_H_
|
||||
#define BSP_Q7S_BOARDCONFIG_Q7S_CONFIG_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#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
|
||||
|
||||
/* Only one of those 2 should be enabled! */
|
||||
@ -11,4 +24,12 @@
|
||||
#define Q7S_ADD_SPI_TEST 0
|
||||
#endif
|
||||
|
||||
#define Q7S_SIMPLE_ADD_FILE_SYSTEM_TEST 0
|
||||
|
||||
namespace config {
|
||||
|
||||
static const uint32_t SD_CARD_ACCESS_MUTEX_TIMEOUT = 50;
|
||||
|
||||
}
|
||||
|
||||
#endif /* BSP_Q7S_BOARDCONFIG_Q7S_CONFIG_H_ */
|
||||
|
@ -1,4 +1,6 @@
|
||||
target_sources(${TARGET_NAME} PRIVATE
|
||||
FileSystemTest.cpp
|
||||
Q7STestTask.cpp
|
||||
)
|
||||
|
||||
|
||||
|
21
bsp_q7s/boardtest/FileSystemTest.cpp
Normal file
21
bsp_q7s/boardtest/FileSystemTest.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
#include "FileSystemTest.h"
|
||||
#include "fsfw/timemanager/Stopwatch.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
||||
FileSystemTest::FileSystemTest() {
|
||||
using namespace std;
|
||||
SdCard sdCard = SdCard::SDC0;
|
||||
cout << "SD Card Test for SD card " << static_cast<int>(sdCard) << std::endl;
|
||||
//Stopwatch stopwatch;
|
||||
std::system("q7hw sd info all > /tmp/sd_status.txt");
|
||||
//stopwatch.stop(true);
|
||||
std::system("q7hw sd set 0 on > /tmp/sd_set.txt");
|
||||
//stopwatch.stop(true);
|
||||
std::system("q7hw sd set 0 off > /tmp/sd_set.txt");
|
||||
//stopwatch.stop(true);
|
||||
}
|
||||
|
||||
FileSystemTest::~FileSystemTest() {
|
||||
}
|
18
bsp_q7s/boardtest/FileSystemTest.h
Normal file
18
bsp_q7s/boardtest/FileSystemTest.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef BSP_Q7S_BOARDTEST_FILESYSTEMTEST_H_
|
||||
#define BSP_Q7S_BOARDTEST_FILESYSTEMTEST_H_
|
||||
|
||||
enum SdCard {
|
||||
SDC0,
|
||||
SDC1
|
||||
};
|
||||
|
||||
class FileSystemTest {
|
||||
public:
|
||||
FileSystemTest();
|
||||
virtual~ FileSystemTest();
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* BSP_Q7S_BOARDTEST_FILESYSTEMTEST_H_ */
|
67
bsp_q7s/boardtest/Q7STestTask.cpp
Normal file
67
bsp_q7s/boardtest/Q7STestTask.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
#include "Q7STestTask.h"
|
||||
|
||||
#include "fsfw/timemanager/Stopwatch.h"
|
||||
#include "fsfw/tasks/TaskFactory.h"
|
||||
|
||||
#include "bsp_q7s/memory/scratchApi.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
|
||||
Q7STestTask::Q7STestTask(object_id_t objectId): TestTask(objectId) {
|
||||
}
|
||||
|
||||
ReturnValue_t Q7STestTask::performOneShotAction() {
|
||||
//sdCardTests();
|
||||
testScratchApi();
|
||||
return TestTask::performOneShotAction();
|
||||
}
|
||||
|
||||
void Q7STestTask::sdCardTests() {
|
||||
using namespace std;
|
||||
Stopwatch stopwatch;
|
||||
int result = std::system("q7hw sd info all > /tmp/sd_status.txt");
|
||||
if(result != 0) {
|
||||
sif::debug << "system call failed with " << result << endl;
|
||||
}
|
||||
ifstream sdStatus("/tmp/sd_status.txt");
|
||||
string line;
|
||||
uint8_t idx = 0;
|
||||
while (std::getline(sdStatus, line)) {
|
||||
std::istringstream iss(line);
|
||||
string word;
|
||||
while(iss >> word) {
|
||||
if(word == "on") {
|
||||
sif::info << "SD card " << static_cast<int>(idx) << " is on" << endl;
|
||||
}
|
||||
else if(word == "off") {
|
||||
sif::info << "SD card " << static_cast<int>(idx) << " is off" << endl;
|
||||
}
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
std::remove("/tmp/sd_status.txt");
|
||||
}
|
||||
|
||||
void Q7STestTask::fileTests() {
|
||||
using namespace std;
|
||||
ofstream testFile("/tmp/test.txt");
|
||||
testFile << "Hallo Welt" << endl;
|
||||
testFile.close();
|
||||
|
||||
system("echo \"Hallo Welt\" > /tmp/test2.txt");
|
||||
system("echo \"Hallo Welt\"");
|
||||
}
|
||||
|
||||
void Q7STestTask::testScratchApi() {
|
||||
ReturnValue_t result = scratch::writeNumber("TEST", 1);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
sif::debug << "Q7STestTask::scratchApiTest: Writing number failed" << std::endl;
|
||||
}
|
||||
int number = 0;
|
||||
result = scratch::readNumber("TEST", number);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
sif::debug << "Q7STestTask::scratchApiTest: Reading number failed" << std::endl;
|
||||
}
|
||||
}
|
20
bsp_q7s/boardtest/Q7STestTask.h
Normal file
20
bsp_q7s/boardtest/Q7STestTask.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef BSP_Q7S_BOARDTEST_Q7STESTTASK_H_
|
||||
#define BSP_Q7S_BOARDTEST_Q7STESTTASK_H_
|
||||
|
||||
#include "test/testtasks/TestTask.h"
|
||||
|
||||
class Q7STestTask: public TestTask {
|
||||
public:
|
||||
Q7STestTask(object_id_t objectId);
|
||||
private:
|
||||
ReturnValue_t performOneShotAction() override;
|
||||
|
||||
void sdCardTests();
|
||||
void fileTests();
|
||||
|
||||
void testScratchApi();
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* BSP_Q7S_BOARDTEST_Q7STESTTASK_H_ */
|
@ -1,4 +1,7 @@
|
||||
#include "CoreController.h"
|
||||
#include "q7sConfig.h"
|
||||
|
||||
#include "../memory/SdCardManager.h"
|
||||
|
||||
CoreController::CoreController(object_id_t objectId):
|
||||
ExtendedControllerBase(objectId, objects::NO_OBJECT, 5) {
|
||||
@ -20,7 +23,126 @@ LocalPoolDataSetBase* CoreController::getDataSetHandle(sid_t sid) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ReturnValue_t CoreController::initialize() {
|
||||
return sdCardInit();
|
||||
}
|
||||
|
||||
ReturnValue_t CoreController::checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t *msToReachTheMode) {
|
||||
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 */
|
||||
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ class CoreController: public ExtendedControllerBase {
|
||||
public:
|
||||
CoreController(object_id_t objectId);
|
||||
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
ReturnValue_t handleCommandMessage(CommandMessage *message) override;
|
||||
void performControlOperation() override;
|
||||
private:
|
||||
@ -15,6 +17,8 @@ private:
|
||||
LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;
|
||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t *msToReachTheMode);
|
||||
|
||||
ReturnValue_t sdCardInit();
|
||||
};
|
||||
|
||||
|
||||
|
@ -44,6 +44,7 @@ void initmission::initMission() {
|
||||
|
||||
void initmission::initTasks() {
|
||||
TaskFactory* factory = TaskFactory::instance();
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||
if(factory == nullptr) {
|
||||
/* Should never happen ! */
|
||||
return;
|
||||
@ -54,11 +55,18 @@ void initmission::initTasks() {
|
||||
void (*missedDeadlineFunc) (void) = nullptr;
|
||||
#endif
|
||||
|
||||
PeriodicTaskIF* coreController = factory->createPeriodicTask(
|
||||
"CORE_CTRL", 60, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.4, missedDeadlineFunc);
|
||||
result = coreController->addComponent(objects::CORE_CONTROLLER);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
initmission::printAddObjectError("CORE_CTRL", objects::CORE_CONTROLLER);
|
||||
|
||||
}
|
||||
|
||||
/* TMTC Distribution */
|
||||
PeriodicTaskIF* tmTcDistributor = factory->createPeriodicTask(
|
||||
"DIST", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.2, missedDeadlineFunc);
|
||||
ReturnValue_t result = tmTcDistributor->addComponent(
|
||||
objects::CCSDS_PACKET_DISTRIBUTOR);
|
||||
result = tmTcDistributor->addComponent(objects::CCSDS_PACKET_DISTRIBUTOR);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
initmission::printAddObjectError("CCSDS_DISTRIB", objects::CCSDS_PACKET_DISTRIBUTOR);
|
||||
}
|
||||
@ -229,6 +237,7 @@ void initmission::initTasks() {
|
||||
tmTcDistributor->startTask();
|
||||
udpBridgeTask->startTask();
|
||||
udpPollingTask->startTask();
|
||||
coreController->startTask();
|
||||
|
||||
#if TE0720 == 0
|
||||
uartPst->startTask();
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include <bsp_q7s/boardtest/Q7STestTask.h>
|
||||
#include "ObjectFactory.h"
|
||||
#include "OBSWConfig.h"
|
||||
#include "tmtc/apid.h"
|
||||
@ -643,6 +644,11 @@ void ObjectFactory::produce(void* args){
|
||||
new UdpTmTcBridge(objects::UDP_BRIDGE, objects::CCSDS_PACKET_DISTRIBUTOR);
|
||||
new UdpTcPollingTask(objects::UDP_POLLING_TASK, objects::UDP_BRIDGE);
|
||||
|
||||
/* Test Task */
|
||||
#if OBSW_ADD_TEST_CODE == 1
|
||||
new Q7STestTask(objects::TEST_TASK);
|
||||
#endif
|
||||
|
||||
#if TE0720 == 1 && TEST_LIBGPIOD == 1
|
||||
/* Configure MIO0 as input */
|
||||
GpiodRegular gpioConfigMio0(std::string("gpiochip0"), 0,
|
||||
@ -728,4 +734,5 @@ void ObjectFactory::produce(void* args){
|
||||
#if Q7S_ADD_SPI_TEST == 1
|
||||
new SpiTestClass(objects::SPI_TEST, gpioComIF);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
@ -6,12 +6,15 @@
|
||||
#include "simple/simple.h"
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
||||
/**
|
||||
* @brief This is the main program for the target hardware.
|
||||
* @return
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
using namespace std;
|
||||
#if Q7S_SIMPLE_MODE == 0
|
||||
return obsw::obsw();
|
||||
#else
|
||||
|
@ -1,4 +1,5 @@
|
||||
target_sources(${TARGET_NAME} PRIVATE
|
||||
FileSystemManager.cpp
|
||||
SdCardAccess.cpp
|
||||
FileSystemHandler.cpp
|
||||
SdCardManager.cpp
|
||||
scratchApi.cpp
|
||||
)
|
184
bsp_q7s/memory/FileSystemHandler.cpp
Normal file
184
bsp_q7s/memory/FileSystemHandler.cpp
Normal file
@ -0,0 +1,184 @@
|
||||
#include "FileSystemHandler.h"
|
||||
|
||||
#include "fsfw/tasks/TaskFactory.h"
|
||||
#include "fsfw/memory/GenericFileSystemMessage.h"
|
||||
#include "fsfw/ipc/QueueFactory.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
FileSystemHandler::FileSystemHandler(object_id_t fileSystemHandler):
|
||||
SystemObject(fileSystemHandler) {
|
||||
mq = QueueFactory::instance()->createMessageQueue(FS_MAX_QUEUE_SIZE);
|
||||
}
|
||||
|
||||
FileSystemHandler::~FileSystemHandler() {
|
||||
QueueFactory::instance()->deleteMessageQueue(mq);
|
||||
}
|
||||
|
||||
ReturnValue_t FileSystemHandler::performOperation(uint8_t unsignedChar) {
|
||||
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;
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||
while(true) {
|
||||
if(opCounter % 5 == 0) {
|
||||
fileSystemCheckup();
|
||||
}
|
||||
result = mq->receiveMessage(&filemsg);
|
||||
if(result == MessageQueueIF::EMPTY) {
|
||||
break;
|
||||
}
|
||||
else if(result != HasReturnvaluesIF::RETURN_FAILED) {
|
||||
sif::warning << "FileSystemHandler::performOperation: Message reception failed!"
|
||||
<< std::endl;
|
||||
break;
|
||||
}
|
||||
Command_t command = filemsg.getCommand();
|
||||
switch(command) {
|
||||
case(GenericFileSystemMessage::CMD_CREATE_DIRECTORY): {
|
||||
break;
|
||||
}
|
||||
case(GenericFileSystemMessage::CMD_CREATE_FILE): {
|
||||
break;
|
||||
}
|
||||
}
|
||||
opCounter++;
|
||||
}
|
||||
|
||||
// This task will have a low priority and will run permanently in the background
|
||||
// so we will just run in a permanent loop here and check file system
|
||||
// messages permanently
|
||||
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 {
|
||||
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,
|
||||
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;
|
||||
}
|
||||
|
||||
ReturnValue_t FileSystemHandler::createFile(const char *repositoryPath, const char *filename,
|
||||
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;
|
||||
}
|
||||
|
||||
ReturnValue_t FileSystemHandler::deleteFile(const char *repositoryPath, const char *filename,
|
||||
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;
|
||||
}
|
56
bsp_q7s/memory/FileSystemHandler.h
Normal file
56
bsp_q7s/memory/FileSystemHandler.h
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef BSP_Q7S_MEMORY_FILESYSTEMHANDLER_H_
|
||||
#define BSP_Q7S_MEMORY_FILESYSTEMHANDLER_H_
|
||||
|
||||
#include "SdCardManager.h"
|
||||
#include "OBSWConfig.h"
|
||||
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
#include "fsfw/memory/HasFileSystemIF.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class FileSystemHandler: public SystemObject,
|
||||
public ExecutableObjectIF,
|
||||
public HasFileSystemIF {
|
||||
public:
|
||||
FileSystemHandler(object_id_t fileSystemHandler);
|
||||
virtual~ FileSystemHandler();
|
||||
|
||||
ReturnValue_t performOperation(uint8_t) override;
|
||||
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
/**
|
||||
* Function to get the MessageQueueId_t of the implementing object
|
||||
* @return MessageQueueId_t of the object
|
||||
*/
|
||||
MessageQueueId_t getCommandQueue() const override;
|
||||
|
||||
private:
|
||||
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,
|
||||
const char* filename, const uint8_t* data, size_t size,
|
||||
uint16_t packetNumber, void* args = nullptr) override;
|
||||
ReturnValue_t createFile(const char* repositoryPath,
|
||||
const char* filename, const uint8_t* data = nullptr,
|
||||
size_t size = 0, void* args = nullptr) override;
|
||||
ReturnValue_t deleteFile(const char* repositoryPath,
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* BSP_Q7S_MEMORY_FILESYSTEMMANAGER_H_ */
|
@ -1,7 +0,0 @@
|
||||
#include "FileSystemManager.h"
|
||||
|
||||
class FileSystemManager {
|
||||
public:
|
||||
|
||||
private:
|
||||
};
|
@ -1,8 +0,0 @@
|
||||
#ifndef BSP_Q7S_MEMORY_FILESYSTEMMANAGER_H_
|
||||
#define BSP_Q7S_MEMORY_FILESYSTEMMANAGER_H_
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* BSP_Q7S_MEMORY_FILESYSTEMMANAGER_H_ */
|
@ -1,4 +0,0 @@
|
||||
#include "SdCardAccess.h"
|
||||
|
||||
SdCardAccess::SdCardAccess() {
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
#ifndef BSP_Q7S_MEMORY_SDCARDACCESS_H_
|
||||
#define BSP_Q7S_MEMORY_SDCARDACCESS_H_
|
||||
|
||||
class SdCardAccess {
|
||||
public:
|
||||
SdCardAccess();
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
#endif /* BSP_Q7S_MEMORY_SDCARDACCESS_H_ */
|
333
bsp_q7s/memory/SdCardManager.cpp
Normal file
333
bsp_q7s/memory/SdCardManager.cpp
Normal file
@ -0,0 +1,333 @@
|
||||
#include "SdCardManager.h"
|
||||
#include "scratchApi.h"
|
||||
|
||||
#include "linux/utility/utility.h"
|
||||
|
||||
#include "fsfw/ipc/MutexFactory.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <filesystem>
|
||||
|
||||
SdCardManager* SdCardManager::factoryInstance = nullptr;
|
||||
|
||||
SdCardManager::SdCardManager() {
|
||||
}
|
||||
|
||||
SdCardManager::~SdCardManager() {
|
||||
}
|
||||
|
||||
void SdCardManager::create() {
|
||||
if(factoryInstance == nullptr) {
|
||||
factoryInstance = new SdCardManager();
|
||||
}
|
||||
}
|
||||
|
||||
SdCardManager* SdCardManager::instance() {
|
||||
SdCardManager::create();
|
||||
return SdCardManager::factoryInstance;
|
||||
}
|
||||
|
||||
ReturnValue_t SdCardManager::switchOnSdCard(sd::SdCard sdCard, bool doMountSdCard,
|
||||
SdStatusPair* statusPair) {
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||
if(statusPair == nullptr) {
|
||||
statusPair = std::make_unique<SdStatusPair>().get();
|
||||
result = getSdCardActiveStatus(*statusPair);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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) {
|
||||
return result;
|
||||
}
|
||||
// Not allowed, this function turns off 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(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);
|
||||
}
|
||||
|
||||
ReturnValue_t SdCardManager::setSdCardState(sd::SdCard sdCard, bool on) {
|
||||
using namespace std;
|
||||
string sdstring = "";
|
||||
string statestring = "";
|
||||
if(sdCard == sd::SdCard::SLOT_0) {
|
||||
sdstring = "0";
|
||||
}
|
||||
else if(sdCard == sd::SdCard::SLOT_1) {
|
||||
sdstring = "1";
|
||||
}
|
||||
if(on) {
|
||||
statestring = "on";
|
||||
}
|
||||
else {
|
||||
statestring = "off";
|
||||
}
|
||||
ostringstream command;
|
||||
command << "q7hw sd set " << sdstring << " " << statestring;
|
||||
int result = system(command.str().c_str());
|
||||
if(result == 0) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
sif::warning << "SdCardManager::setSdCardState: system call failed with code " <<
|
||||
result << std::endl;
|
||||
return SYSTEM_CALL_ERROR;
|
||||
}
|
||||
|
||||
ReturnValue_t SdCardManager::getSdCardActiveStatus(SdStatusPair& active) {
|
||||
using namespace std;
|
||||
if(not filesystem::exists(SD_STATE_FILE)) {
|
||||
return STATUS_FILE_NEXISTS;
|
||||
}
|
||||
|
||||
// Now the file should exist in any case. Still check whether it exists.
|
||||
fstream sdStatus(SD_STATE_FILE);
|
||||
if (not sdStatus.good()) {
|
||||
return STATUS_FILE_NEXISTS;
|
||||
}
|
||||
string line;
|
||||
uint8_t idx = 0;
|
||||
sd::SdCard currentSd = sd::SdCard::SLOT_0;
|
||||
// Process status file line by 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);
|
||||
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 = sd::SdStatus::ON;
|
||||
}
|
||||
else {
|
||||
active.second = sd::SdStatus::ON;
|
||||
}
|
||||
}
|
||||
else if (word == "off") {
|
||||
if(currentSd == sd::SdCard::SLOT_0) {
|
||||
active.first = sd::SdStatus::OFF;
|
||||
}
|
||||
else {
|
||||
active.second = sd::SdStatus::OFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(mountLine) {
|
||||
if(currentSd == sd::SdCard::SLOT_0) {
|
||||
active.first = sd::SdStatus::MOUNTED;
|
||||
}
|
||||
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++;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ReturnValue_t SdCardManager::setPreferredSdCard(sd::SdCard sdCard) {
|
||||
if(sdCard == sd::SdCard::BOTH) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
return scratch::writeNumber(scratch::PREFERED_SDC_KEY, static_cast<uint8_t>(sdCard));
|
||||
}
|
||||
|
||||
ReturnValue_t SdCardManager::updateSdCardStateFile() {
|
||||
// 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) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
sif::warning << "SdCardManager::updateSdCardStateFile: system call failed with code " <<
|
||||
result << std::endl;
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
159
bsp_q7s/memory/SdCardManager.h
Normal file
159
bsp_q7s/memory/SdCardManager.h
Normal file
@ -0,0 +1,159 @@
|
||||
#ifndef BSP_Q7S_MEMORY_SDCARDACCESSMANAGER_H_
|
||||
#define BSP_Q7S_MEMORY_SDCARDACCESSMANAGER_H_
|
||||
|
||||
#include "definitions.h"
|
||||
#include "returnvalues/classIds.h"
|
||||
|
||||
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
|
||||
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:
|
||||
using SdStatusPair = std::pair<sd::SdStatus, sd::SdStatus>;
|
||||
|
||||
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_MOUNTED =
|
||||
HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 1);
|
||||
static constexpr ReturnValue_t ALREADY_OFF =
|
||||
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 =
|
||||
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);
|
||||
|
||||
// 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 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:
|
||||
SdCardManager();
|
||||
|
||||
ReturnValue_t setSdCardState(sd::SdCard sdCard, bool on);
|
||||
|
||||
void processSdStatusLine(SdStatusPair& active, std::string& line, uint8_t& idx,
|
||||
sd::SdCard& currentSd);
|
||||
|
||||
static SdCardManager* factoryInstance;
|
||||
};
|
||||
|
||||
#endif /* BSP_Q7S_MEMORY_SDCARDACCESSMANAGER_H_ */
|
25
bsp_q7s/memory/definitions.h
Normal file
25
bsp_q7s/memory/definitions.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef BSP_Q7S_MEMORY_DEFINITIONS_H_
|
||||
#define BSP_Q7S_MEMORY_DEFINITIONS_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace sd {
|
||||
|
||||
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_1,
|
||||
BOTH
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* BSP_Q7S_MEMORY_DEFINITIONS_H_ */
|
12
bsp_q7s/memory/scratchApi.cpp
Normal file
12
bsp_q7s/memory/scratchApi.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
#include "scratchApi.h"
|
||||
|
||||
ReturnValue_t scratch::writeString(std::string name, std::string string) {
|
||||
std::ostringstream oss;
|
||||
oss << "xsc_scratch write " << name << " \"" << string << "\"";
|
||||
int result = std::system(oss.str().c_str());
|
||||
if(result != 0) {
|
||||
utility::handleSystemError(result, "scratch::String");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
72
bsp_q7s/memory/scratchApi.h
Normal file
72
bsp_q7s/memory/scratchApi.h
Normal file
@ -0,0 +1,72 @@
|
||||
#ifndef BSP_Q7S_MEMORY_SCRATCHAPI_H_
|
||||
#define BSP_Q7S_MEMORY_SCRATCHAPI_H_
|
||||
|
||||
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
#include "linux/utility/utility.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
#include <cstdlib>
|
||||
|
||||
/**
|
||||
* @brief API for the scratch buffer
|
||||
*/
|
||||
namespace scratch {
|
||||
|
||||
static constexpr char PREFERED_SDC_KEY[] = "PREFSD";
|
||||
|
||||
namespace {
|
||||
static uint8_t counter = 0;
|
||||
}
|
||||
|
||||
template<typename T, class = typename std::enable_if<std::is_integral<T>::value>::type>
|
||||
inline ReturnValue_t writeNumber(std::string name, T num) noexcept {
|
||||
std::ostringstream oss;
|
||||
oss << "xsc_scratch write " << name << " " << num;
|
||||
int result = std::system(oss.str().c_str());
|
||||
if(result != 0) {
|
||||
utility::handleSystemError(result, "scratch::writeNumber");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
template<typename T, class = typename std::enable_if<std::is_integral<T>::value>::type>
|
||||
inline ReturnValue_t readNumber(std::string name, T& num) noexcept {
|
||||
using namespace std;
|
||||
string filename = "/tmp/sro" + std::to_string(counter++);
|
||||
ostringstream oss;
|
||||
oss << "xsc_scratch read " << name << " > " << filename;
|
||||
|
||||
int result = std::system(oss.str().c_str());
|
||||
if(result != 0) {
|
||||
utility::handleSystemError(result, "scratch::writeNumber");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
ifstream file(filename);
|
||||
string line;
|
||||
if (not std::getline(file, line)) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
size_t pos = line.find("=");
|
||||
std::string valueAsString = line.substr(pos + 1);
|
||||
try {
|
||||
num = std::stoi(valueAsString);
|
||||
}
|
||||
catch(std::invalid_argument& e) {
|
||||
sif::warning << "scratch::readNumber: stoi call failed with " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
std::remove(filename.c_str());
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t writeString(std::string name, std::string string);
|
||||
|
||||
}
|
||||
|
||||
#endif /* BSP_Q7S_MEMORY_SCRATCHAPI_H_ */
|
@ -1,5 +1,17 @@
|
||||
#include "simple.h"
|
||||
#include "q7sConfig.h"
|
||||
|
||||
#if Q7S_SIMPLE_ADD_FILE_SYSTEM_TEST == 1
|
||||
#include "../boardtest/FileSystemTest.h"
|
||||
#endif
|
||||
|
||||
int simple::simple() {
|
||||
cout << "-- Q7S Simple Application --" << endl;
|
||||
#if Q7S_SIMPLE_ADD_FILE_SYSTEM_TEST == 1
|
||||
{
|
||||
FileSystemTest fileSystemTest;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user