Core Controller Remount SD Handling #253
@ -56,6 +56,7 @@ CoreController::CoreController(object_id_t objectId)
|
|||||||
} catch (const std::filesystem::filesystem_error &e) {
|
} catch (const std::filesystem::filesystem_error &e) {
|
||||||
sif::error << "CoreController::CoreController: Failed with exception " << e.what() << std::endl;
|
sif::error << "CoreController::CoreController: Failed with exception " << e.what() << std::endl;
|
||||||
}
|
}
|
||||||
|
sdCardCheckCd.timeOut();
|
||||||
eventQueue = QueueFactory::instance()->createMessageQueue(5, EventMessage::MAX_MESSAGE_SIZE);
|
eventQueue = QueueFactory::instance()->createMessageQueue(5, EventMessage::MAX_MESSAGE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,6 +78,10 @@ void CoreController::performControlOperation() {
|
|||||||
performWatchdogControlOperation();
|
performWatchdogControlOperation();
|
||||||
sdStateMachine();
|
sdStateMachine();
|
||||||
performMountedSdCardOperations();
|
performMountedSdCardOperations();
|
||||||
|
if (sdCardCheckCd.hasTimedOut()) {
|
||||||
|
performSdCardCheck();
|
||||||
|
sdCardCheckCd.resetTimer();
|
||||||
|
}
|
||||||
readHkData();
|
readHkData();
|
||||||
opDivider5.checkAndIncrement();
|
opDivider5.checkAndIncrement();
|
||||||
opDivider10.checkAndIncrement();
|
opDivider10.checkAndIncrement();
|
||||||
@ -134,6 +139,8 @@ ReturnValue_t CoreController::initialize() {
|
|||||||
|
|
||||||
ReturnValue_t CoreController::initializeAfterTaskCreation() {
|
ReturnValue_t CoreController::initializeAfterTaskCreation() {
|
||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||||
|
sdInfo.pref = sdcMan->getPreferredSdCard();
|
||||||
|
sdcMan->setActiveSdCard(sdInfo.pref);
|
||||||
if (BLOCKING_SD_INIT) {
|
if (BLOCKING_SD_INIT) {
|
||||||
ReturnValue_t result = initSdCardBlocking();
|
ReturnValue_t result = initSdCardBlocking();
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK and result != SdCardManager::ALREADY_MOUNTED) {
|
if (result != HasReturnvaluesIF::RETURN_OK and result != SdCardManager::ALREADY_MOUNTED) {
|
||||||
@ -165,7 +172,7 @@ ReturnValue_t CoreController::executeAction(ActionId_t actionId, MessageQueueId_
|
|||||||
if (size < 1) {
|
if (size < 1) {
|
||||||
return HasActionsIF::INVALID_PARAMETERS;
|
return HasActionsIF::INVALID_PARAMETERS;
|
||||||
}
|
}
|
||||||
std::string path = sdcMan->getCurrentMountPrefix(sdInfo.pref) + REBOOT_FILE;
|
std::string path = sdcMan->getCurrentMountPrefix() + REBOOT_FILE;
|
||||||
// Disable the reboot file mechanism
|
// Disable the reboot file mechanism
|
||||||
parseRebootFile(path, rebootFile);
|
parseRebootFile(path, rebootFile);
|
||||||
if (data[0] == 0) {
|
if (data[0] == 0) {
|
||||||
@ -205,7 +212,7 @@ ReturnValue_t CoreController::executeAction(ActionId_t actionId, MessageQueueId_
|
|||||||
if (size < 1) {
|
if (size < 1) {
|
||||||
return HasActionsIF::INVALID_PARAMETERS;
|
return HasActionsIF::INVALID_PARAMETERS;
|
||||||
}
|
}
|
||||||
std::string path = sdcMan->getCurrentMountPrefix(sdInfo.pref) + REBOOT_FILE;
|
std::string path = sdcMan->getCurrentMountPrefix() + REBOOT_FILE;
|
||||||
// Disable the reboot file mechanism
|
// Disable the reboot file mechanism
|
||||||
parseRebootFile(path, rebootFile);
|
parseRebootFile(path, rebootFile);
|
||||||
rebootFile.maxCount = data[0];
|
rebootFile.maxCount = data[0];
|
||||||
@ -237,13 +244,12 @@ ReturnValue_t CoreController::initSdCardBlocking() {
|
|||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
#else
|
#else
|
||||||
|
|
||||||
result = sdcMan->getSdCardActiveStatus(sdInfo.currentState);
|
result = sdcMan->getSdCardsStatus(sdInfo.currentState);
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
sif::warning << "Getting SD card activity status failed" << std::endl;
|
sif::warning << "Getting SD card activity status failed" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if Q7S_SD_CARD_CONFIG == Q7S_SD_COLD_REDUNDANT
|
#if Q7S_SD_CARD_CONFIG == Q7S_SD_COLD_REDUNDANT
|
||||||
determinePreferredSdCard();
|
|
||||||
updateSdInfoOther();
|
updateSdInfoOther();
|
||||||
sif::info << "Cold redundant SD card configuration, preferred SD card: "
|
sif::info << "Cold redundant SD card configuration, preferred SD card: "
|
||||||
<< static_cast<int>(sdInfo.pref) << std::endl;
|
<< static_cast<int>(sdInfo.pref) << std::endl;
|
||||||
@ -324,8 +330,8 @@ ReturnValue_t CoreController::sdStateMachine() {
|
|||||||
|
|
||||||
if (sdInfo.state == SdStates::SET_STATE_SELF) {
|
if (sdInfo.state == SdStates::SET_STATE_SELF) {
|
||||||
if (not sdInfo.commandExecuted) {
|
if (not sdInfo.commandExecuted) {
|
||||||
result = sdcMan->getSdCardActiveStatus(sdInfo.currentState);
|
result = sdcMan->getSdCardsStatus(sdInfo.currentState);
|
||||||
determinePreferredSdCard();
|
sdInfo.pref = sdcMan->getPreferredSdCard();
|
||||||
updateSdInfoOther();
|
updateSdInfoOther();
|
||||||
if (sdInfo.pref != sd::SdCard::SLOT_0 and sdInfo.pref != sd::SdCard::SLOT_1) {
|
if (sdInfo.pref != sd::SdCard::SLOT_0 and sdInfo.pref != sd::SdCard::SLOT_1) {
|
||||||
sif::warning << "Preferred SD card invalid. Setting to card 0.." << std::endl;
|
sif::warning << "Preferred SD card invalid. Setting to card 0.." << std::endl;
|
||||||
@ -468,7 +474,7 @@ ReturnValue_t CoreController::sdStateMachine() {
|
|||||||
sdInfo.state = SdStates::IDLE;
|
sdInfo.state = SdStates::IDLE;
|
||||||
sdInfo.cycleCount = 0;
|
sdInfo.cycleCount = 0;
|
||||||
sdcMan->setBlocking(false);
|
sdcMan->setBlocking(false);
|
||||||
sdcMan->getSdCardActiveStatus(sdInfo.currentState);
|
sdcMan->getSdCardsStatus(sdInfo.currentState);
|
||||||
if (not sdInfo.initFinished) {
|
if (not sdInfo.initFinished) {
|
||||||
updateSdInfoOther();
|
updateSdInfoOther();
|
||||||
sdInfo.initFinished = true;
|
sdInfo.initFinished = true;
|
||||||
@ -933,25 +939,6 @@ ReturnValue_t CoreController::actionPerformReboot(const uint8_t *data, size_t si
|
|||||||
|
|
||||||
CoreController::~CoreController() {}
|
CoreController::~CoreController() {}
|
||||||
|
|
||||||
void CoreController::determinePreferredSdCard() {
|
|
||||||
if (sdInfo.pref == sd::SdCard::NONE) {
|
|
||||||
ReturnValue_t result = sdcMan->getPreferredSdCard(sdInfo.pref);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
if (result == scratch::KEY_NOT_FOUND) {
|
|
||||||
sif::warning << "CoreController::sdCardInit: "
|
|
||||||
"Preferred SD card not set. Setting to 0"
|
|
||||||
<< std::endl;
|
|
||||||
sdcMan->setPreferredSdCard(sd::SdCard::SLOT_0);
|
|
||||||
sdInfo.pref = sd::SdCard::SLOT_0;
|
|
||||||
} else {
|
|
||||||
sif::warning << "CoreController::sdCardInit: Could not get preferred SD card"
|
|
||||||
"information from the scratch buffer"
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CoreController::updateSdInfoOther() {
|
void CoreController::updateSdInfoOther() {
|
||||||
if (sdInfo.pref == sd::SdCard::SLOT_0) {
|
if (sdInfo.pref == sd::SdCard::SLOT_0) {
|
||||||
sdInfo.prefChar = "0";
|
sdInfo.prefChar = "0";
|
||||||
@ -1235,46 +1222,71 @@ void CoreController::performWatchdogControlOperation() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CoreController::performMountedSdCardOperations() {
|
void CoreController::performMountedSdCardOperations() {
|
||||||
currMntPrefix = sdcMan->getCurrentMountPrefix();
|
auto mountedSdCardOp = [&](bool& mntSwitch, sd::SdCard sdCard, std::string mntPoint) {
|
||||||
if (performMountedSdCardOpsSwitch) {
|
if (mntSwitch) {
|
||||||
bool sdCardMounted = false;
|
bool sdCardMounted = sdcMan->isSdCardMounted(sdCard);
|
||||||
bool mountedReadOnly = false;
|
if (sdCardMounted and not performOneShotSdCardOpsSwitch) {
|
||||||
ReturnValue_t result = sdcMan->isSdCardMountedReadOnly(sdInfo.pref, mountedReadOnly);
|
std::ostringstream path;
|
||||||
|
path << mntPoint << "/" << CONF_FOLDER;
|
||||||
|
if (not std::filesystem::exists(path.str())) {
|
||||||
|
std::filesystem::create_directory(path.str());
|
||||||
|
}
|
||||||
|
initVersionFile();
|
||||||
|
initClockFromTimeFile();
|
||||||
|
performRebootFileHandling(false);
|
||||||
|
performOneShotSdCardOpsSwitch = true;
|
||||||
|
}
|
||||||
|
mntSwitch = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if(sdInfo.pref == sd::SdCard::SLOT_1) {
|
||||||
|
mountedSdCardOp(sdInfo.mountSwitch.second, sd::SdCard::SLOT_1, SdCardManager::SD_1_MOUNT_POINT);
|
||||||
|
mountedSdCardOp(sdInfo.mountSwitch.first, sd::SdCard::SLOT_0, SdCardManager::SD_0_MOUNT_POINT);
|
||||||
|
} else {
|
||||||
|
mountedSdCardOp(sdInfo.mountSwitch.first, sd::SdCard::SLOT_0, SdCardManager::SD_0_MOUNT_POINT);
|
||||||
|
mountedSdCardOp(sdInfo.mountSwitch.second, sd::SdCard::SLOT_1, SdCardManager::SD_1_MOUNT_POINT);
|
||||||
|
}
|
||||||
|
timeFileHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t CoreController::performSdCardCheck() {
|
||||||
|
bool mountedReadOnly = false;
|
||||||
|
SdCardManager::SdStatePair active;
|
||||||
|
sdcMan->getSdCardsStatus(active);
|
||||||
|
auto sdCardCheck = [&](sd::SdCard sdCard) {
|
||||||
|
ReturnValue_t result = sdcMan->isSdCardMountedReadOnly(sdCard, mountedReadOnly);
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
sif::error << "CoreController::performMountedSdCardOperations: Could not check "
|
sif::error << "CoreController::performSdCardCheck: Could not check "
|
||||||
"read-only mount state" << std::endl;
|
"read-only mount state"
|
||||||
|
<< std::endl;
|
||||||
mountedReadOnly = true;
|
mountedReadOnly = true;
|
||||||
}
|
}
|
||||||
if (mountedReadOnly) {
|
if (mountedReadOnly) {
|
||||||
int linuxErrno = 0;
|
int linuxErrno = 0;
|
||||||
result = sdcMan->performFsck(sdInfo.pref, true, linuxErrno);
|
result = sdcMan->performFsck(sdCard, true, linuxErrno);
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
sif::error << "CoreController::performMountedSdCardOperations: fsck command on SD Card "
|
sif::error << "CoreController::performSdCardCheck: fsck command on SD Card "
|
||||||
<< sdInfo.prefChar << " failed with code " << linuxErrno << " | " << strerror(linuxErrno);
|
<< static_cast<uint8_t>(sdCard) << " failed with code " << linuxErrno << " | "
|
||||||
|
<< strerror(linuxErrno);
|
||||||
}
|
}
|
||||||
result = sdcMan->remountReadWrite(sdInfo.pref);
|
result = sdcMan->remountReadWrite(sdCard);
|
||||||
if(result == HasReturnvaluesIF::RETURN_OK) {
|
if (result == HasReturnvaluesIF::RETURN_OK) {
|
||||||
sif::warning << "CoreController::performMountedSdCardOperations: Remounted SD Card " <<
|
sif::warning << "CoreController::performSdCardCheck: Remounted SD Card "
|
||||||
sdInfo.prefChar << " read-write";
|
<< static_cast<uint8_t>(sdCard) << " read-write";
|
||||||
} else {
|
} else {
|
||||||
sif::error << "CoreController::performMountedSdCardOperations: Remounting SD Card " <<
|
sif::error << "CoreController::performSdCardCheck: Remounting SD Card "
|
||||||
sdInfo.prefChar << " read-write failed";
|
<< static_cast<uint8_t>(sdCard) << " read-write failed";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sdCardMounted = sdcMan->isSdCardMounted(sdInfo.pref);
|
};
|
||||||
if (sdCardMounted and not performOneShotSdCardOpsSwitch) {
|
if (active.first == sd::SdState::MOUNTED) {
|
||||||
std::ostringstream path;
|
sdCardCheck(sd::SdCard::SLOT_0);
|
||||||
path << currMntPrefix << "/" << CONF_FOLDER;
|
|
||||||
if (not std::filesystem::exists(path.str())) {
|
|
||||||
std::filesystem::create_directory(path.str());
|
|
||||||
}
|
|
||||||
initVersionFile();
|
|
||||||
initClockFromTimeFile();
|
|
||||||
performRebootFileHandling(false);
|
|
||||||
performOneShotSdCardOpsSwitch = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
timeFileHandler();
|
if (active.second == sd::SdState::MOUNTED) {
|
||||||
|
sdCardCheck(sd::SdCard::SLOT_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreController::performRebootFileHandling(bool recreateFile) {
|
void CoreController::performRebootFileHandling(bool recreateFile) {
|
||||||
@ -1702,7 +1714,7 @@ void CoreController::rewriteRebootFile(RebootFile file) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CoreController::setRebootMechanismLock(bool lock, xsc::Chip tgtChip, xsc::Copy tgtCopy) {
|
void CoreController::setRebootMechanismLock(bool lock, xsc::Chip tgtChip, xsc::Copy tgtCopy) {
|
||||||
std::string path = sdcMan->getCurrentMountPrefix(sdInfo.pref) + REBOOT_FILE;
|
std::string path = currMntPrefix + REBOOT_FILE;
|
||||||
// Disable the reboot file mechanism
|
// Disable the reboot file mechanism
|
||||||
parseRebootFile(path, rebootFile);
|
parseRebootFile(path, rebootFile);
|
||||||
if (tgtChip == xsc::CHIP_0) {
|
if (tgtChip == xsc::CHIP_0) {
|
||||||
|
@ -159,11 +159,12 @@ class CoreController : public ExtendedControllerBase {
|
|||||||
|
|
||||||
struct SdInfo {
|
struct SdInfo {
|
||||||
sd::SdCard pref = sd::SdCard::NONE;
|
sd::SdCard pref = sd::SdCard::NONE;
|
||||||
sd::SdState prefState = sd::SdState::OFF;
|
|
||||||
sd::SdCard other = sd::SdCard::NONE;
|
sd::SdCard other = sd::SdCard::NONE;
|
||||||
|
sd::SdState prefState = sd::SdState::OFF;
|
||||||
sd::SdState otherState = sd::SdState::OFF;
|
sd::SdState otherState = sd::SdState::OFF;
|
||||||
std::string prefChar = "0";
|
std::string prefChar = "0";
|
||||||
std::string otherChar = "1";
|
std::string otherChar = "1";
|
||||||
|
std::pair<bool, bool> mountSwitch = {true, true};
|
||||||
SdStates state = SdStates::START;
|
SdStates state = SdStates::START;
|
||||||
// Used to track whether a command was executed
|
// Used to track whether a command was executed
|
||||||
bool commandExecuted = true;
|
bool commandExecuted = true;
|
||||||
@ -180,7 +181,6 @@ class CoreController : public ExtendedControllerBase {
|
|||||||
RebootFile rebootFile = {};
|
RebootFile rebootFile = {};
|
||||||
std::string currMntPrefix;
|
std::string currMntPrefix;
|
||||||
bool performOneShotSdCardOpsSwitch = true;
|
bool performOneShotSdCardOpsSwitch = true;
|
||||||
bool performMountedSdCardOpsSwitch = true;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Index 0: Chip 0 Copy 0
|
* Index 0: Chip 0 Copy 0
|
||||||
@ -196,12 +196,14 @@ class CoreController : public ExtendedControllerBase {
|
|||||||
|
|
||||||
ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
||||||
LocalDataPoolManager& poolManager) override;
|
LocalDataPoolManager& poolManager) override;
|
||||||
|
Countdown sdCardCheckCd = Countdown(10000);
|
||||||
LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;
|
LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;
|
||||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t* msToReachTheMode);
|
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t* msToReachTheMode);
|
||||||
void performMountedSdCardOperations();
|
void performMountedSdCardOperations();
|
||||||
ReturnValue_t initVersionFile();
|
ReturnValue_t initVersionFile();
|
||||||
|
|
||||||
ReturnValue_t initClockFromTimeFile();
|
ReturnValue_t initClockFromTimeFile();
|
||||||
|
ReturnValue_t performSdCardCheck();
|
||||||
ReturnValue_t timeFileHandler();
|
ReturnValue_t timeFileHandler();
|
||||||
ReturnValue_t initBootCopy();
|
ReturnValue_t initBootCopy();
|
||||||
ReturnValue_t initWatchdogFifo();
|
ReturnValue_t initWatchdogFifo();
|
||||||
@ -215,7 +217,6 @@ class CoreController : public ExtendedControllerBase {
|
|||||||
ReturnValue_t sdColdRedundantBlockingInit();
|
ReturnValue_t sdColdRedundantBlockingInit();
|
||||||
|
|
||||||
void currentStateSetter(sd::SdCard sdCard, sd::SdState newState);
|
void currentStateSetter(sd::SdCard sdCard, sd::SdState newState);
|
||||||
void determinePreferredSdCard();
|
|
||||||
void executeNextExternalSdCommand();
|
void executeNextExternalSdCommand();
|
||||||
void checkExternalSdCommandStatus();
|
void checkExternalSdCommandStatus();
|
||||||
void performRebootFileHandling(bool recreateFile);
|
void performRebootFileHandling(bool recreateFile);
|
||||||
|
@ -70,9 +70,8 @@ void FileSystemHandler::fileSystemHandlerLoop() {
|
|||||||
|
|
||||||
void FileSystemHandler::fileSystemCheckup() {
|
void FileSystemHandler::fileSystemCheckup() {
|
||||||
SdCardManager::SdStatePair statusPair;
|
SdCardManager::SdStatePair statusPair;
|
||||||
sdcMan->getSdCardActiveStatus(statusPair);
|
sdcMan->getSdCardsStatus(statusPair);
|
||||||
sd::SdCard preferredSdCard;
|
sd::SdCard preferredSdCard = sdcMan->getPreferredSdCard();
|
||||||
sdcMan->getPreferredSdCard(preferredSdCard);
|
|
||||||
if ((preferredSdCard == sd::SdCard::SLOT_0) and (statusPair.first == sd::SdState::MOUNTED)) {
|
if ((preferredSdCard == sd::SdCard::SLOT_0) and (statusPair.first == sd::SdState::MOUNTED)) {
|
||||||
currentMountPrefix = SdCardManager::SD_0_MOUNT_POINT;
|
currentMountPrefix = SdCardManager::SD_0_MOUNT_POINT;
|
||||||
} else if ((preferredSdCard == sd::SdCard::SLOT_1) and
|
} else if ((preferredSdCard == sd::SdCard::SLOT_1) and
|
||||||
@ -109,11 +108,7 @@ ReturnValue_t FileSystemHandler::initialize() {
|
|||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
sdcMan = SdCardManager::instance();
|
sdcMan = SdCardManager::instance();
|
||||||
sd::SdCard preferredSdCard;
|
sd::SdCard preferredSdCard = sdcMan->getPreferredSdCard();
|
||||||
ReturnValue_t result = sdcMan->getPreferredSdCard(preferredSdCard);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (preferredSdCard == sd::SdCard::SLOT_0) {
|
if (preferredSdCard == sd::SdCard::SLOT_0) {
|
||||||
currentMountPrefix = SdCardManager::SD_0_MOUNT_POINT;
|
currentMountPrefix = SdCardManager::SD_0_MOUNT_POINT;
|
||||||
} else if (preferredSdCard == sd::SdCard::SLOT_1) {
|
} else if (preferredSdCard == sd::SdCard::SLOT_1) {
|
||||||
|
@ -16,23 +16,44 @@
|
|||||||
#include "linux/utility/utility.h"
|
#include "linux/utility/utility.h"
|
||||||
#include "scratchApi.h"
|
#include "scratchApi.h"
|
||||||
|
|
||||||
SdCardManager* SdCardManager::factoryInstance = nullptr;
|
SdCardManager* SdCardManager::INSTANCE = nullptr;
|
||||||
|
|
||||||
SdCardManager::SdCardManager() : SystemObject(objects::SDC_MANAGER), cmdExecutor(256) {
|
SdCardManager::SdCardManager() : SystemObject(objects::SDC_MANAGER), cmdExecutor(256) {
|
||||||
mutex = MutexFactory::instance()->createMutex();
|
mutex = MutexFactory::instance()->createMutex();
|
||||||
|
MutexGuard mg(mutex);
|
||||||
|
uint8_t prefSdRaw = 0;
|
||||||
|
ReturnValue_t result = scratch::readNumber(scratch::PREFERED_SDC_KEY, prefSdRaw);
|
||||||
|
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
if (result == scratch::KEY_NOT_FOUND) {
|
||||||
|
sif::warning << "CoreController::sdCardInit: "
|
||||||
|
"Preferred SD card not set. Setting to 0"
|
||||||
|
<< std::endl;
|
||||||
|
setPreferredSdCard(sd::SdCard::SLOT_0);
|
||||||
|
sdInfo.pref = sd::SdCard::SLOT_0;
|
||||||
|
} else {
|
||||||
|
// Should not happen.
|
||||||
|
// TODO: Maybe trigger event?
|
||||||
|
sif::error << "SdCardManager::SdCardManager: Reading preferred SD card from scratch"
|
||||||
|
"buffer failed"
|
||||||
|
<< std::endl;
|
||||||
|
sdInfo.pref = sd::SdCard::SLOT_0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sdInfo.pref = static_cast<sd::SdCard>(prefSdRaw);
|
||||||
}
|
}
|
||||||
|
|
||||||
SdCardManager::~SdCardManager() {}
|
SdCardManager::~SdCardManager() {}
|
||||||
|
|
||||||
void SdCardManager::create() {
|
void SdCardManager::create() {
|
||||||
if (factoryInstance == nullptr) {
|
if (INSTANCE == nullptr) {
|
||||||
factoryInstance = new SdCardManager();
|
INSTANCE = new SdCardManager();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SdCardManager* SdCardManager::instance() {
|
SdCardManager* SdCardManager::instance() {
|
||||||
SdCardManager::create();
|
SdCardManager::create();
|
||||||
return SdCardManager::factoryInstance;
|
return SdCardManager::INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t SdCardManager::switchOnSdCard(sd::SdCard sdCard, bool doMountSdCard,
|
ReturnValue_t SdCardManager::switchOnSdCard(sd::SdCard sdCard, bool doMountSdCard,
|
||||||
@ -51,7 +72,7 @@ ReturnValue_t SdCardManager::switchOnSdCard(sd::SdCard sdCard, bool doMountSdCar
|
|||||||
if (statusPair == nullptr) {
|
if (statusPair == nullptr) {
|
||||||
sdStatusPtr = std::make_unique<SdStatePair>();
|
sdStatusPtr = std::make_unique<SdStatePair>();
|
||||||
statusPair = sdStatusPtr.get();
|
statusPair = sdStatusPtr.get();
|
||||||
result = getSdCardActiveStatus(*statusPair);
|
result = getSdCardsStatus(*statusPair);
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -98,7 +119,7 @@ ReturnValue_t SdCardManager::switchOnSdCard(sd::SdCard sdCard, bool doMountSdCar
|
|||||||
ReturnValue_t SdCardManager::switchOffSdCard(sd::SdCard sdCard, bool doUnmountSdCard,
|
ReturnValue_t SdCardManager::switchOffSdCard(sd::SdCard sdCard, bool doUnmountSdCard,
|
||||||
SdStatePair* statusPair) {
|
SdStatePair* statusPair) {
|
||||||
std::pair<sd::SdState, sd::SdState> active;
|
std::pair<sd::SdState, sd::SdState> active;
|
||||||
ReturnValue_t result = getSdCardActiveStatus(active);
|
ReturnValue_t result = getSdCardsStatus(active);
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -165,7 +186,7 @@ ReturnValue_t SdCardManager::setSdCardState(sd::SdCard sdCard, bool on) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t SdCardManager::getSdCardActiveStatus(SdStatePair& active) {
|
ReturnValue_t SdCardManager::getSdCardsStatus(SdStatePair& active) {
|
||||||
using namespace std;
|
using namespace std;
|
||||||
MutexGuard mg(mutex);
|
MutexGuard mg(mutex);
|
||||||
if (not filesystem::exists(SD_STATE_FILE)) {
|
if (not filesystem::exists(SD_STATE_FILE)) {
|
||||||
@ -273,14 +294,14 @@ ReturnValue_t SdCardManager::sanitizeState(SdStatePair* statusPair, sd::SdCard p
|
|||||||
resetNonBlockingState = true;
|
resetNonBlockingState = true;
|
||||||
}
|
}
|
||||||
if (prefSdCard == sd::SdCard::NONE) {
|
if (prefSdCard == sd::SdCard::NONE) {
|
||||||
result = getPreferredSdCard(prefSdCard);
|
result = getPreferredSdCard();
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (statusPair == nullptr) {
|
if (statusPair == nullptr) {
|
||||||
sdStatusPtr = std::make_unique<SdStatePair>();
|
sdStatusPtr = std::make_unique<SdStatePair>();
|
||||||
statusPair = sdStatusPtr.get();
|
statusPair = sdStatusPtr.get();
|
||||||
getSdCardActiveStatus(*statusPair);
|
getSdCardsStatus(*statusPair);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statusPair->first == sd::SdState::ON) {
|
if (statusPair->first == sd::SdState::ON) {
|
||||||
@ -351,20 +372,21 @@ void SdCardManager::processSdStatusLine(std::pair<sd::SdState, sd::SdState>& act
|
|||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t SdCardManager::getPreferredSdCard(sd::SdCard& sdCard) const {
|
sd::SdCard SdCardManager::getPreferredSdCard() const {
|
||||||
uint8_t prefSdCard = 0;
|
MutexGuard mg(mutex);
|
||||||
ReturnValue_t result = scratch::readNumber(scratch::PREFERED_SDC_KEY, prefSdCard);
|
auto res = mg.getLockResult();
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (res != RETURN_OK) {
|
||||||
return result;
|
sif::error << "SdCardManager::getPreferredSdCard: Lock error" << std::endl;
|
||||||
}
|
}
|
||||||
sdCard = static_cast<sd::SdCard>(prefSdCard);
|
return sdInfo.pref;
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t SdCardManager::setPreferredSdCard(sd::SdCard sdCard) {
|
ReturnValue_t SdCardManager::setPreferredSdCard(sd::SdCard sdCard) {
|
||||||
|
MutexGuard mg(mutex);
|
||||||
if (sdCard == sd::SdCard::BOTH) {
|
if (sdCard == sd::SdCard::BOTH) {
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
sdInfo.pref = sdCard;
|
||||||
return scratch::writeNumber(scratch::PREFERED_SDC_KEY, static_cast<uint8_t>(sdCard));
|
return scratch::writeNumber(scratch::PREFERED_SDC_KEY, static_cast<uint8_t>(sdCard));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,14 +405,9 @@ ReturnValue_t SdCardManager::updateSdCardStateFile() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SdCardManager::getCurrentMountPrefix(sd::SdCard prefSdCard) {
|
std::string SdCardManager::getCurrentMountPrefix() const {
|
||||||
if (prefSdCard == sd::SdCard::NONE) {
|
MutexGuard mg(mutex);
|
||||||
ReturnValue_t result = getPreferredSdCard(prefSdCard);
|
if (sdInfo.active == sd::SdCard::SLOT_0) {
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
return SD_0_MOUNT_POINT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (prefSdCard == sd::SdCard::SLOT_0) {
|
|
||||||
return SD_0_MOUNT_POINT;
|
return SD_0_MOUNT_POINT;
|
||||||
} else {
|
} else {
|
||||||
return SD_1_MOUNT_POINT;
|
return SD_1_MOUNT_POINT;
|
||||||
@ -443,7 +460,7 @@ void SdCardManager::setPrintCommandOutput(bool print) { this->printCmdOutput = p
|
|||||||
|
|
||||||
bool SdCardManager::isSdCardMounted(sd::SdCard sdCard) {
|
bool SdCardManager::isSdCardMounted(sd::SdCard sdCard) {
|
||||||
SdCardManager::SdStatePair active;
|
SdCardManager::SdStatePair active;
|
||||||
ReturnValue_t result = this->getSdCardActiveStatus(active);
|
ReturnValue_t result = this->getSdCardsStatus(active);
|
||||||
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
sif::debug << "SdCardManager::isSdCardMounted: Failed to get SD card active state";
|
sif::debug << "SdCardManager::isSdCardMounted: Failed to get SD card active state";
|
||||||
@ -469,10 +486,10 @@ bool SdCardManager::isSdCardMounted(sd::SdCard sdCard) {
|
|||||||
|
|
||||||
ReturnValue_t SdCardManager::isSdCardMountedReadOnly(sd::SdCard sdcard, bool& readOnly) {
|
ReturnValue_t SdCardManager::isSdCardMountedReadOnly(sd::SdCard sdcard, bool& readOnly) {
|
||||||
std::ostringstream command;
|
std::ostringstream command;
|
||||||
if(sdcard == sd::SdCard::SLOT_0) {
|
if (sdcard == sd::SdCard::SLOT_0) {
|
||||||
command << "grep -q \"" << SD_0_DEV_NAME << " vfat ro, \" /proc/mounts";
|
command << "grep -q \"" << SD_0_DEV_NAME << " vfat ro, \" /proc/mounts";
|
||||||
} else {
|
} else {
|
||||||
command << "grep -q \"" << SD_1_DEV_NAME << " vfat ro, \" /proc/mounts";
|
command << "grep -q \"" << SD_1_DEV_NAME << " vfat ro, \" /proc/mounts";
|
||||||
}
|
}
|
||||||
ReturnValue_t result = cmdExecutor.load(command.str(), true, false);
|
ReturnValue_t result = cmdExecutor.load(command.str(), true, false);
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
@ -484,7 +501,7 @@ ReturnValue_t SdCardManager::isSdCardMountedReadOnly(sd::SdCard sdcard, bool& re
|
|||||||
}
|
}
|
||||||
auto& readVec = cmdExecutor.getReadVector();
|
auto& readVec = cmdExecutor.getReadVector();
|
||||||
size_t readLen = strnlen(readVec.data(), readVec.size());
|
size_t readLen = strnlen(readVec.data(), readVec.size());
|
||||||
if(readLen == 0) {
|
if (readLen == 0) {
|
||||||
readOnly = false;
|
readOnly = false;
|
||||||
}
|
}
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
@ -493,7 +510,7 @@ ReturnValue_t SdCardManager::isSdCardMountedReadOnly(sd::SdCard sdcard, bool& re
|
|||||||
|
|
||||||
ReturnValue_t SdCardManager::remountReadWrite(sd::SdCard sdcard) {
|
ReturnValue_t SdCardManager::remountReadWrite(sd::SdCard sdcard) {
|
||||||
std::ostringstream command;
|
std::ostringstream command;
|
||||||
if(sdcard == sd::SdCard::SLOT_0) {
|
if (sdcard == sd::SdCard::SLOT_0) {
|
||||||
command << "mount -o remount,rw " << SD_0_DEV_NAME << " " << SD_0_MOUNT_POINT;
|
command << "mount -o remount,rw " << SD_0_DEV_NAME << " " << SD_0_MOUNT_POINT;
|
||||||
} else {
|
} else {
|
||||||
command << "mount -o remount,rw " << SD_1_DEV_NAME << " " << SD_1_MOUNT_POINT;
|
command << "mount -o remount,rw " << SD_1_DEV_NAME << " " << SD_1_MOUNT_POINT;
|
||||||
@ -507,7 +524,7 @@ ReturnValue_t SdCardManager::remountReadWrite(sd::SdCard sdcard) {
|
|||||||
|
|
||||||
ReturnValue_t SdCardManager::performFsck(sd::SdCard sdcard, bool printOutput, int& linuxError) {
|
ReturnValue_t SdCardManager::performFsck(sd::SdCard sdcard, bool printOutput, int& linuxError) {
|
||||||
std::ostringstream command;
|
std::ostringstream command;
|
||||||
if(sdcard == sd::SdCard::SLOT_0) {
|
if (sdcard == sd::SdCard::SLOT_0) {
|
||||||
command << "fsck -y " << SD_0_DEV_NAME;
|
command << "fsck -y " << SD_0_DEV_NAME;
|
||||||
} else {
|
} else {
|
||||||
command << "fsck -y " << SD_1_DEV_NAME;
|
command << "fsck -y " << SD_1_DEV_NAME;
|
||||||
@ -517,8 +534,16 @@ ReturnValue_t SdCardManager::performFsck(sd::SdCard sdcard, bool printOutput, in
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
result = cmdExecutor.execute();
|
result = cmdExecutor.execute();
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
linuxError = cmdExecutor.getLastError();
|
linuxError = cmdExecutor.getLastError();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SdCardManager::setActiveSdCard(sd::SdCard sdCard) {
|
||||||
|
sdInfo.active = sdCard;
|
||||||
|
}
|
||||||
|
|
||||||
|
sd::SdCard SdCardManager::getActiveSdCard() const {
|
||||||
|
return sdInfo.active;
|
||||||
|
}
|
||||||
|
@ -24,7 +24,7 @@ class MutexIF;
|
|||||||
* @brief Manages handling of SD cards like switching them on or off or getting the current
|
* @brief Manages handling of SD cards like switching them on or off or getting the current
|
||||||
* state
|
* state
|
||||||
*/
|
*/
|
||||||
class SdCardManager : public SystemObject, public SdCardMountedIF {
|
class SdCardManager : public SystemObject, public HasReturnvaluesIF, public SdCardMountedIF {
|
||||||
friend class SdCardAccess;
|
friend class SdCardAccess;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -36,6 +36,12 @@ class SdCardManager : public SystemObject, public SdCardMountedIF {
|
|||||||
|
|
||||||
using SdStatePair = std::pair<sd::SdState, sd::SdState>;
|
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 uint8_t INTERFACE_ID = CLASS_ID::SD_CARD_MANAGER;
|
||||||
|
|
||||||
static constexpr ReturnValue_t OP_ONGOING = HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 0);
|
static constexpr ReturnValue_t OP_ONGOING = HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 0);
|
||||||
@ -91,7 +97,7 @@ class SdCardManager : public SystemObject, public SdCardMountedIF {
|
|||||||
* @param sdCard
|
* @param sdCard
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
ReturnValue_t getPreferredSdCard(sd::SdCard& sdCard) const override;
|
sd::SdCard getPreferredSdCard() const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Switch on the specified SD card.
|
* Switch on the specified SD card.
|
||||||
@ -138,7 +144,7 @@ class SdCardManager : public SystemObject, public SdCardMountedIF {
|
|||||||
* 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 getSdCardActiveStatus(SdStatePair& active);
|
ReturnValue_t getSdCardsStatus(SdStatePair& active);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mount the specified SD card. This is necessary to use it.
|
* Mount the specified SD card. This is necessary to use it.
|
||||||
@ -146,6 +152,20 @@ class SdCardManager : public SystemObject, public SdCardMountedIF {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
ReturnValue_t mountSdCard(sd::SdCard sdCard);
|
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
|
||||||
|
*/
|
||||||
|
sd::SdCard getActiveSdCard() const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unmount the specified SD card. This is recommended before switching it off. The SD card
|
* Unmount the specified SD card. This is recommended before switching it off. The SD card
|
||||||
* can't be used after it has been unmounted.
|
* can't be used after it has been unmounted.
|
||||||
@ -173,7 +193,7 @@ class SdCardManager : public SystemObject, public SdCardMountedIF {
|
|||||||
* @param prefSdCardPtr
|
* @param prefSdCardPtr
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
std::string getCurrentMountPrefix(sd::SdCard prefSdCardPtr = sd::SdCard::NONE) override;
|
std::string getCurrentMountPrefix() const override;
|
||||||
|
|
||||||
OpStatus checkCurrentOp(Operations& currentOp);
|
OpStatus checkCurrentOp(Operations& currentOp);
|
||||||
|
|
||||||
@ -216,7 +236,7 @@ class SdCardManager : public SystemObject, public SdCardMountedIF {
|
|||||||
|
|
||||||
std::string currentPrefix;
|
std::string currentPrefix;
|
||||||
|
|
||||||
static SdCardManager* factoryInstance;
|
static SdCardManager* INSTANCE;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* BSP_Q7S_MEMORY_SDCARDACCESSMANAGER_H_ */
|
#endif /* BSP_Q7S_MEMORY_SDCARDACCESSMANAGER_H_ */
|
||||||
|
@ -114,7 +114,7 @@ bool Max31865RtdReader::periodicInitHandling() {
|
|||||||
#if OBSW_RTD_AUTO_MODE == 0
|
#if OBSW_RTD_AUTO_MODE == 0
|
||||||
result = writeBiasSel(Bias::ON, rtd->spiCookie, BASE_CFG);
|
result = writeBiasSel(Bias::ON, rtd->spiCookie, BASE_CFG);
|
||||||
#endif
|
#endif
|
||||||
someRtdUsable = true;
|
someRtdUsable = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return someRtdUsable;
|
return someRtdUsable;
|
||||||
|
@ -123,7 +123,7 @@ void Max31865EiveHandler::fillCommandAndReplyMap() {
|
|||||||
|
|
||||||
ReturnValue_t Max31865EiveHandler::scanForReply(const uint8_t* start, size_t remainingSize,
|
ReturnValue_t Max31865EiveHandler::scanForReply(const uint8_t* start, size_t remainingSize,
|
||||||
DeviceCommandId_t* foundId, size_t* foundLen) {
|
DeviceCommandId_t* foundId, size_t* foundLen) {
|
||||||
if(mode == _MODE_POWER_ON or mode == _MODE_WAIT_ON) {
|
if (mode == _MODE_POWER_ON or mode == _MODE_WAIT_ON) {
|
||||||
return IGNORE_FULL_PACKET;
|
return IGNORE_FULL_PACKET;
|
||||||
}
|
}
|
||||||
if (remainingSize != structLen) {
|
if (remainingSize != structLen) {
|
||||||
|
@ -490,10 +490,9 @@ void PayloadPcduHandler::checkAdcValues() {
|
|||||||
|
|
||||||
void PayloadPcduHandler::checkJsonFileInit() {
|
void PayloadPcduHandler::checkJsonFileInit() {
|
||||||
if (not jsonFileInitComplete) {
|
if (not jsonFileInitComplete) {
|
||||||
sd::SdCard prefSd;
|
sd::SdCard activeSd = sdcMan->getActiveSdCard();
|
||||||
sdcMan->getPreferredSdCard(prefSd);
|
if (sdcMan->isSdCardMounted(activeSd)) {
|
||||||
if (sdcMan->isSdCardMounted(prefSd)) {
|
params.initialize(sdcMan->getCurrentMountPrefix());
|
||||||
params.initialize(sdcMan->getCurrentMountPrefix(prefSd));
|
|
||||||
jsonFileInitComplete = true;
|
jsonFileInitComplete = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,11 @@
|
|||||||
class SdCardMountedIF {
|
class SdCardMountedIF {
|
||||||
public:
|
public:
|
||||||
virtual ~SdCardMountedIF(){};
|
virtual ~SdCardMountedIF(){};
|
||||||
virtual std::string getCurrentMountPrefix(sd::SdCard prefSdCardPtr = sd::SdCard::NONE) = 0;
|
virtual std::string getCurrentMountPrefix() const = 0;
|
||||||
virtual bool isSdCardMounted(sd::SdCard sdCard) = 0;
|
virtual bool isSdCardMounted(sd::SdCard sdCard) = 0;
|
||||||
virtual ReturnValue_t getPreferredSdCard(sd::SdCard& sdCard) const = 0;
|
virtual sd::SdCard getPreferredSdCard() const = 0;
|
||||||
|
virtual void setActiveSdCard(sd::SdCard sdCard) = 0;
|
||||||
|
virtual sd::SdCard getActiveSdCard() const = 0;
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
2
tmtc
2
tmtc
@ -1 +1 @@
|
|||||||
Subproject commit 9332fb8690de200070e712a70b1fa339d5b6b8d8
|
Subproject commit 51bbeaa693a11bfc4d2cb342354041972dd93c1e
|
Loading…
Reference in New Issue
Block a user