small README
Some checks failed
EIVE/eive-obsw/pipeline/pr-develop There was a failure building this commit
Some checks failed
EIVE/eive-obsw/pipeline/pr-develop There was a failure building this commit
This commit is contained in:
7
unittest/rebootLogic/src/CMakeLists.txt
Normal file
7
unittest/rebootLogic/src/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
target_sources(reboot-logic PRIVATE
|
||||
main.cpp
|
||||
CoreController.cpp
|
||||
SdCardManager.cpp
|
||||
event.cpp
|
||||
libxiphos.cpp
|
||||
)
|
431
unittest/rebootLogic/src/CoreController.cpp
Normal file
431
unittest/rebootLogic/src/CoreController.cpp
Normal file
@ -0,0 +1,431 @@
|
||||
#include "conf.h"
|
||||
#include "HasActionsIF.h"
|
||||
#include "CoreController.h"
|
||||
#include "SdCardManager.h"
|
||||
#include "event.h"
|
||||
#include "libxiphos.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
|
||||
xsc::Chip CoreController::CURRENT_CHIP = xsc::Chip::NO_CHIP;
|
||||
xsc::Copy CoreController::CURRENT_COPY = xsc::Copy::NO_COPY;
|
||||
|
||||
CoreController::CoreController() {
|
||||
sdcMan = new SdCardManager();
|
||||
setCurrentBootCopy(xsc::CHIP_0, xsc::COPY_0);
|
||||
}
|
||||
|
||||
void CoreController::performRebootFileHandling(bool recreateFile) {
|
||||
using namespace std;
|
||||
std::string path = sdcMan->getCurrentMountPrefix(sdInfo.pref) + REBOOT_FILE;
|
||||
if (not std::filesystem::exists(path) or recreateFile) {
|
||||
#if OBSW_VERBOSE_LEVEL >= 1
|
||||
std::cout << "CoreController::performRebootFileHandling: Recreating reboot file" << std::endl;
|
||||
#endif
|
||||
rebootFile.enabled = true;
|
||||
rebootFile.img00Cnt = 0;
|
||||
rebootFile.img01Cnt = 0;
|
||||
rebootFile.img10Cnt = 0;
|
||||
rebootFile.img11Cnt = 0;
|
||||
rebootFile.lastChip = xsc::Chip::CHIP_0;
|
||||
rebootFile.lastCopy = xsc::Copy::COPY_0;
|
||||
rebootFile.bootFlag = false;
|
||||
rewriteRebootFile(rebootFile);
|
||||
} else {
|
||||
if (not parseRebootFile(path, rebootFile)) {
|
||||
performRebootFileHandling(true);
|
||||
}
|
||||
}
|
||||
|
||||
switch (CURRENT_CHIP) {
|
||||
case (xsc::CHIP_0): {
|
||||
switch (CURRENT_COPY) {
|
||||
case (xsc::COPY_0): {
|
||||
rebootFile.img00Cnt++;
|
||||
break;
|
||||
}
|
||||
case (xsc::COPY_1): {
|
||||
rebootFile.img01Cnt++;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case (xsc::CHIP_1): {
|
||||
switch (CURRENT_COPY) {
|
||||
case (xsc::COPY_0): {
|
||||
rebootFile.img10Cnt++;
|
||||
break;
|
||||
}
|
||||
case (xsc::COPY_1): {
|
||||
rebootFile.img11Cnt++;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rebootFile.bootFlag) {
|
||||
// Trigger event to inform ground that a reboot was triggered
|
||||
uint32_t p1 = rebootFile.lastChip << 16 | rebootFile.lastCopy;
|
||||
uint32_t p2 = rebootFile.img00Cnt << 24 | rebootFile.img01Cnt << 16 |
|
||||
rebootFile.img10Cnt << 8 | rebootFile.img11Cnt;
|
||||
triggerEvent(REBOOT_MECHANISM_TRIGGERED, p1, p2);
|
||||
// Clear the boot flag
|
||||
rebootFile.bootFlag = false;
|
||||
}
|
||||
|
||||
// Only reboot if the reboot functionality is enabled.
|
||||
// The handler will still increment the boot counts
|
||||
if (rebootFile.enabled and (*rebootFile.relevantBootCnt >= rebootFile.maxCount)) {
|
||||
// Reboot to other image
|
||||
bool doReboot = false;
|
||||
xsc::Chip tgtChip = xsc::NO_CHIP;
|
||||
xsc::Copy tgtCopy = xsc::NO_COPY;
|
||||
determineAndExecuteReboot(rebootFile, doReboot, tgtChip, tgtCopy);
|
||||
if (doReboot) {
|
||||
rebootFile.bootFlag = true;
|
||||
#if OBSW_VERBOSE_LEVEL >= 1
|
||||
std::cout << "Boot counter for image " << CURRENT_CHIP << " " << CURRENT_COPY
|
||||
<< " too high. Rebooting to " << tgtChip << " " << tgtCopy
|
||||
<< std::endl;
|
||||
#endif
|
||||
rebootFile.lastChip = CURRENT_CHIP;
|
||||
rebootFile.lastCopy = CURRENT_COPY;
|
||||
rewriteRebootFile(rebootFile);
|
||||
xsc_boot_copy(static_cast<xsc_libnor_chip_t>(tgtChip),
|
||||
static_cast<xsc_libnor_copy_t>(tgtCopy));
|
||||
}
|
||||
} else {
|
||||
rewriteRebootFile(rebootFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CoreController::determineAndExecuteReboot(RebootFile &rf, bool &needsReboot,
|
||||
xsc::Chip &tgtChip, xsc::Copy &tgtCopy) {
|
||||
tgtChip = xsc::CHIP_0;
|
||||
tgtCopy = xsc::COPY_0;
|
||||
needsReboot = false;
|
||||
if ((CURRENT_CHIP == xsc::CHIP_0) and (CURRENT_COPY == xsc::COPY_0) and
|
||||
(rf.img00Cnt >= rf.maxCount)) {
|
||||
needsReboot = true;
|
||||
if (rf.img01Cnt >= rf.maxCount) {
|
||||
if (rf.img10Cnt >= rf.maxCount) {
|
||||
if (rf.img11Cnt >= rf.maxCount) {
|
||||
// Can't really do much here. Stay on image
|
||||
std::cout << "All reboot counts too high, but already on fallback image" << std::endl;
|
||||
return;
|
||||
} else {
|
||||
tgtChip = xsc::CHIP_1;
|
||||
tgtCopy = xsc::COPY_1;
|
||||
}
|
||||
} else {
|
||||
tgtChip = xsc::CHIP_1;
|
||||
tgtCopy = xsc::COPY_0;
|
||||
}
|
||||
} else {
|
||||
tgtCopy = xsc::COPY_1;
|
||||
}
|
||||
}
|
||||
if ((CURRENT_CHIP == xsc::CHIP_0) and (CURRENT_COPY == xsc::COPY_1) and
|
||||
(rf.img01Cnt >= rf.maxCount)) {
|
||||
needsReboot = true;
|
||||
if (rf.img00Cnt >= rf.maxCount) {
|
||||
if (rf.img10Cnt >= rf.maxCount) {
|
||||
if (rf.img11Cnt >= rf.maxCount) {
|
||||
// Reboot to fallback image
|
||||
} else {
|
||||
tgtChip = xsc::CHIP_1;
|
||||
tgtCopy = xsc::COPY_1;
|
||||
}
|
||||
} else {
|
||||
tgtChip = xsc::CHIP_1;
|
||||
tgtCopy = xsc::COPY_0;
|
||||
}
|
||||
} else {
|
||||
// Reboot on fallback image
|
||||
}
|
||||
}
|
||||
if ((CURRENT_CHIP == xsc::CHIP_1) and (CURRENT_COPY == xsc::COPY_0) and
|
||||
(rf.img10Cnt >= rf.maxCount)) {
|
||||
needsReboot = true;
|
||||
if (rf.img11Cnt >= rf.maxCount) {
|
||||
if (rf.img00Cnt >= rf.maxCount) {
|
||||
if (rf.img01Cnt >= rf.maxCount) {
|
||||
// Reboot to fallback image
|
||||
} else {
|
||||
tgtChip = xsc::CHIP_0;
|
||||
tgtCopy = xsc::COPY_1;
|
||||
}
|
||||
} else {
|
||||
tgtChip = xsc::CHIP_0;
|
||||
tgtCopy = xsc::COPY_0;
|
||||
}
|
||||
} else {
|
||||
tgtChip = xsc::CHIP_1;
|
||||
tgtCopy = xsc::COPY_1;
|
||||
}
|
||||
}
|
||||
if ((CURRENT_CHIP == xsc::CHIP_1) and (CURRENT_COPY == xsc::COPY_1) and
|
||||
(rf.img11Cnt >= rf.maxCount)) {
|
||||
needsReboot = true;
|
||||
if (rf.img10Cnt >= rf.maxCount) {
|
||||
if (rf.img00Cnt >= rf.maxCount) {
|
||||
if (rf.img01Cnt >= rf.maxCount) {
|
||||
// Reboot to fallback image
|
||||
} else {
|
||||
tgtChip = xsc::CHIP_0;
|
||||
tgtCopy = xsc::COPY_1;
|
||||
}
|
||||
} else {
|
||||
tgtChip = xsc::CHIP_0;
|
||||
tgtCopy = xsc::COPY_0;
|
||||
}
|
||||
} else {
|
||||
tgtChip = xsc::CHIP_1;
|
||||
tgtCopy = xsc::COPY_0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CoreController::parseRebootFile(std::string path, RebootFile &rf) {
|
||||
using namespace std;
|
||||
std::string selfMatch;
|
||||
if (CURRENT_CHIP == xsc::CHIP_0) {
|
||||
if (CURRENT_COPY == xsc::COPY_0) {
|
||||
selfMatch = "00";
|
||||
} else {
|
||||
selfMatch = "01";
|
||||
}
|
||||
} else {
|
||||
if (CURRENT_COPY == xsc::COPY_0) {
|
||||
selfMatch = "10";
|
||||
} else {
|
||||
selfMatch = "11";
|
||||
}
|
||||
}
|
||||
ifstream file(path);
|
||||
string word;
|
||||
string line;
|
||||
uint8_t lineIdx = 0;
|
||||
while (std::getline(file, line)) {
|
||||
istringstream iss(line);
|
||||
switch (lineIdx) {
|
||||
case 0: {
|
||||
iss >> word;
|
||||
if (word.find("on:") == string::npos) {
|
||||
// invalid file
|
||||
return false;
|
||||
}
|
||||
iss >> rf.enabled;
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
iss >> word;
|
||||
if (word.find("maxcnt:") == string::npos) {
|
||||
return false;
|
||||
}
|
||||
iss >> rf.maxCount;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
iss >> word;
|
||||
if (word.find("img00:") == string::npos) {
|
||||
return false;
|
||||
}
|
||||
iss >> rf.img00Cnt;
|
||||
if (word.find(selfMatch) != string::npos) {
|
||||
rf.relevantBootCnt = &rf.img00Cnt;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
iss >> word;
|
||||
if (word.find("img01:") == string::npos) {
|
||||
return false;
|
||||
}
|
||||
iss >> rf.img01Cnt;
|
||||
if (word.find(selfMatch) != string::npos) {
|
||||
rf.relevantBootCnt = &rf.img01Cnt;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
iss >> word;
|
||||
if (word.find("img10:") == string::npos) {
|
||||
return false;
|
||||
}
|
||||
iss >> rf.img10Cnt;
|
||||
if (word.find(selfMatch) != string::npos) {
|
||||
rf.relevantBootCnt = &rf.img10Cnt;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
iss >> word;
|
||||
if (word.find("img11:") == string::npos) {
|
||||
return false;
|
||||
}
|
||||
iss >> rf.img11Cnt;
|
||||
if (word.find(selfMatch) != string::npos) {
|
||||
rf.relevantBootCnt = &rf.img11Cnt;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 6: {
|
||||
iss >> word;
|
||||
if (word.find("bootflag:") == string::npos) {
|
||||
return false;
|
||||
}
|
||||
iss >> rf.bootFlag;
|
||||
break;
|
||||
}
|
||||
case 7: {
|
||||
iss >> word;
|
||||
int copyRaw = 0;
|
||||
int chipRaw = 0;
|
||||
if (word.find("last:") == string::npos) {
|
||||
return false;
|
||||
}
|
||||
iss >> chipRaw;
|
||||
if (iss.fail()) {
|
||||
return false;
|
||||
}
|
||||
iss >> copyRaw;
|
||||
if (iss.fail()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (chipRaw > 1 or copyRaw > 1) {
|
||||
return false;
|
||||
}
|
||||
rf.lastChip = static_cast<xsc::Chip>(chipRaw);
|
||||
rf.lastCopy = static_cast<xsc::Copy>(copyRaw);
|
||||
}
|
||||
}
|
||||
if (iss.fail()) {
|
||||
return false;
|
||||
}
|
||||
lineIdx++;
|
||||
}
|
||||
if (lineIdx < 8) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CoreController::resetRebootCount(xsc::Chip tgtChip, xsc::Copy tgtCopy) {
|
||||
std::string path = sdcMan->getCurrentMountPrefix(sdInfo.pref) + REBOOT_FILE;
|
||||
// Disable the reboot file mechanism
|
||||
parseRebootFile(path, rebootFile);
|
||||
if (tgtChip == xsc::ALL_CHIP and tgtCopy == xsc::ALL_COPY) {
|
||||
rebootFile.img00Cnt = 0;
|
||||
rebootFile.img01Cnt = 0;
|
||||
rebootFile.img10Cnt = 0;
|
||||
rebootFile.img11Cnt = 0;
|
||||
} else {
|
||||
if (tgtChip == xsc::CHIP_0) {
|
||||
if (tgtCopy == xsc::COPY_0) {
|
||||
rebootFile.img00Cnt = 0;
|
||||
} else {
|
||||
rebootFile.img01Cnt = 0;
|
||||
}
|
||||
} else {
|
||||
if (tgtCopy == xsc::COPY_0) {
|
||||
rebootFile.img10Cnt = 0;
|
||||
} else {
|
||||
rebootFile.img11Cnt = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
rewriteRebootFile(rebootFile);
|
||||
}
|
||||
|
||||
void CoreController::rewriteRebootFile(RebootFile file) {
|
||||
std::string path = sdcMan->getCurrentMountPrefix(sdInfo.pref) + REBOOT_FILE;
|
||||
std::ofstream rebootFile(path);
|
||||
if (rebootFile.is_open()) {
|
||||
// Initiate reboot file first. Reboot handling will be on on initialization
|
||||
rebootFile << "on: " << file.enabled << "\nmaxcnt: " << file.maxCount
|
||||
<< "\nimg00: " << file.img00Cnt << "\nimg01: " << file.img01Cnt
|
||||
<< "\nimg10: " << file.img10Cnt << "\nimg11: " << file.img11Cnt
|
||||
<< "\nbootflag: " << file.bootFlag << "\nlast: " << static_cast<int>(file.lastChip)
|
||||
<< " " << static_cast<int>(file.lastCopy) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t CoreController::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
|
||||
const uint8_t *data, size_t size) {
|
||||
switch (actionId) {
|
||||
case (SWITCH_REBOOT_FILE_HANDLING): {
|
||||
if (size < 1) {
|
||||
return HasActionsIF::INVALID_PARAMETERS;
|
||||
}
|
||||
std::string path = sdcMan->getCurrentMountPrefix(sdInfo.pref) + REBOOT_FILE;
|
||||
// Disable the reboot file mechanism
|
||||
parseRebootFile(path, rebootFile);
|
||||
if (data[0] == 0) {
|
||||
rebootFile.enabled = false;
|
||||
rewriteRebootFile(rebootFile);
|
||||
} else if (data[0] == 1) {
|
||||
rebootFile.enabled = true;
|
||||
rewriteRebootFile(rebootFile);
|
||||
} else {
|
||||
return HasActionsIF::INVALID_PARAMETERS;
|
||||
}
|
||||
return HasActionsIF::EXECUTION_FINISHED;
|
||||
}
|
||||
case (RESET_ALL_REBOOT_COUNTERS): {
|
||||
resetRebootCount(xsc::ALL_CHIP, xsc::ALL_COPY);
|
||||
return HasActionsIF::EXECUTION_FINISHED;
|
||||
}
|
||||
case (RESET_REBOOT_COUNTER_00): {
|
||||
resetRebootCount(xsc::CHIP_0, xsc::COPY_0);
|
||||
return HasActionsIF::EXECUTION_FINISHED;
|
||||
}
|
||||
case (RESET_REBOOT_COUNTER_01): {
|
||||
resetRebootCount(xsc::CHIP_0, xsc::COPY_1);
|
||||
return HasActionsIF::EXECUTION_FINISHED;
|
||||
}
|
||||
case (RESET_REBOOT_COUNTER_10): {
|
||||
resetRebootCount(xsc::CHIP_1, xsc::COPY_0);
|
||||
return HasActionsIF::EXECUTION_FINISHED;
|
||||
}
|
||||
case (RESET_REBOOT_COUNTER_11): {
|
||||
resetRebootCount(xsc::CHIP_1, xsc::COPY_1);
|
||||
return HasActionsIF::EXECUTION_FINISHED;
|
||||
}
|
||||
case(SET_MAX_REBOOT_CNT): {
|
||||
if(size < 1) {
|
||||
return HasActionsIF::INVALID_PARAMETERS;
|
||||
}
|
||||
std::string path = sdcMan->getCurrentMountPrefix(sdInfo.pref) + REBOOT_FILE;
|
||||
// Disable the reboot file mechanism
|
||||
parseRebootFile(path, rebootFile);
|
||||
rebootFile.maxCount = data[0];
|
||||
rewriteRebootFile(rebootFile);
|
||||
return HasActionsIF::EXECUTION_FINISHED;
|
||||
}
|
||||
default: {
|
||||
return HasActionsIF::INVALID_ACTION_ID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CoreController::setCurrentBootCopy(xsc::Chip chip, xsc::Copy copy) {
|
||||
CURRENT_CHIP = chip;
|
||||
CURRENT_COPY = copy;
|
||||
}
|
75
unittest/rebootLogic/src/CoreController.h
Normal file
75
unittest/rebootLogic/src/CoreController.h
Normal file
@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include "definitions.h"
|
||||
#include "SdCardManager.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
namespace xsc {
|
||||
|
||||
enum Chip : int { CHIP_0, CHIP_1, NO_CHIP, SELF_CHIP, ALL_CHIP };
|
||||
enum Copy : int { COPY_0, COPY_1, NO_COPY, SELF_COPY, ALL_COPY };
|
||||
|
||||
} // namespace xsc
|
||||
|
||||
|
||||
struct RebootFile {
|
||||
static constexpr uint8_t DEFAULT_MAX_BOOT_CNT = 10;
|
||||
|
||||
bool enabled = false;
|
||||
size_t maxCount = DEFAULT_MAX_BOOT_CNT;
|
||||
uint32_t img00Cnt = 0;
|
||||
uint32_t img01Cnt = 0;
|
||||
uint32_t img10Cnt = 0;
|
||||
uint32_t img11Cnt = 0;
|
||||
uint32_t* relevantBootCnt = &img00Cnt;
|
||||
bool bootFlag = false;
|
||||
xsc::Chip lastChip = xsc::Chip::CHIP_0;
|
||||
xsc::Copy lastCopy = xsc::Copy::COPY_0;
|
||||
};
|
||||
|
||||
class SdCardManager;
|
||||
|
||||
class CoreController {
|
||||
public:
|
||||
static constexpr char REBOOT_FILE[] = "/conf/reboot.txt";
|
||||
//! [EXPORT] : [COMMENT] The reboot mechanism was triggered.
|
||||
//! P1: First 16 bits: Last Chip, Last 16 bits: Last Copy,
|
||||
//! P2: Each byte is the respective reboot count for the slots
|
||||
static constexpr Event REBOOT_MECHANISM_TRIGGERED = 1;
|
||||
static xsc::Chip CURRENT_CHIP;
|
||||
static xsc::Copy CURRENT_COPY;
|
||||
|
||||
static constexpr ActionId_t SWITCH_REBOOT_FILE_HANDLING = 5;
|
||||
static constexpr ActionId_t RESET_ALL_REBOOT_COUNTERS = 6;
|
||||
static constexpr ActionId_t RESET_REBOOT_COUNTER_00 = 7;
|
||||
static constexpr ActionId_t RESET_REBOOT_COUNTER_01 = 8;
|
||||
static constexpr ActionId_t RESET_REBOOT_COUNTER_10 = 9;
|
||||
static constexpr ActionId_t RESET_REBOOT_COUNTER_11 = 10;
|
||||
static constexpr ActionId_t SET_MAX_REBOOT_CNT = 11;
|
||||
|
||||
CoreController();
|
||||
|
||||
static void setCurrentBootCopy(xsc::Chip chip, xsc::Copy copy);
|
||||
ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
|
||||
const uint8_t* data, size_t size);
|
||||
void performRebootFileHandling(bool recreateFile);
|
||||
void determineAndExecuteReboot(RebootFile& rf, bool& needsReboot, xsc::Chip& tgtChip,
|
||||
xsc::Copy& tgtCopy);
|
||||
void resetRebootCount(xsc::Chip tgtChip, xsc::Copy tgtCopy);
|
||||
bool parseRebootFile(std::string path, RebootFile& file);
|
||||
void rewriteRebootFile(RebootFile file);
|
||||
private:
|
||||
struct SdInfo {
|
||||
sd::SdCard pref = sd::SdCard::NONE;
|
||||
sd::SdState prefState = sd::SdState::OFF;
|
||||
sd::SdCard other = sd::SdCard::NONE;
|
||||
sd::SdState otherState = sd::SdState::OFF;
|
||||
} sdInfo;
|
||||
|
||||
SdCardManager* sdcMan = nullptr;
|
||||
RebootFile rebootFile = {};
|
||||
bool doPerformRebootFileHandling = true;
|
||||
};
|
9
unittest/rebootLogic/src/HasActionsIF.h
Normal file
9
unittest/rebootLogic/src/HasActionsIF.h
Normal file
@ -0,0 +1,9 @@
|
||||
#include "definitions.h"
|
||||
|
||||
class HasActionsIF {
|
||||
public:
|
||||
static const ReturnValue_t IS_BUSY = 1;
|
||||
static const ReturnValue_t INVALID_PARAMETERS = 2;
|
||||
static const ReturnValue_t EXECUTION_FINISHED = 3;
|
||||
static const ReturnValue_t INVALID_ACTION_ID = 4;
|
||||
};
|
9
unittest/rebootLogic/src/SdCardManager.cpp
Normal file
9
unittest/rebootLogic/src/SdCardManager.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
#include "SdCardManager.h"
|
||||
|
||||
std::string SdCardManager::getCurrentMountPrefix(sd::SdCard prefSdCard) {
|
||||
return "/tmp";
|
||||
}
|
||||
|
||||
bool SdCardManager::isSdCardMounted(sd::SdCard sdCard) {
|
||||
return true;
|
||||
}
|
23
unittest/rebootLogic/src/SdCardManager.h
Normal file
23
unittest/rebootLogic/src/SdCardManager.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace sd {
|
||||
|
||||
enum SdState : uint8_t {
|
||||
OFF = 0,
|
||||
ON = 1,
|
||||
// A mounted SD card is on as well
|
||||
MOUNTED = 2
|
||||
};
|
||||
|
||||
enum SdCard : uint8_t { SLOT_0 = 0, SLOT_1 = 1, BOTH, NONE };
|
||||
|
||||
} // namespace sd
|
||||
|
||||
class SdCardManager {
|
||||
public:
|
||||
std::string getCurrentMountPrefix(sd::SdCard prefSdCard);
|
||||
bool isSdCardMounted(sd::SdCard sdCard);
|
||||
};
|
1
unittest/rebootLogic/src/conf.h
Normal file
1
unittest/rebootLogic/src/conf.h
Normal file
@ -0,0 +1 @@
|
||||
#define OBSW_VERBOSE_LEVEL 1
|
6
unittest/rebootLogic/src/definitions.h
Normal file
6
unittest/rebootLogic/src/definitions.h
Normal file
@ -0,0 +1,6 @@
|
||||
#include <cstdint>
|
||||
|
||||
using Event = uint32_t;
|
||||
using ActionId_t = uint32_t;
|
||||
using MessageQueueId_t = uint32_t;
|
||||
using ReturnValue_t = uint16_t;
|
20
unittest/rebootLogic/src/event.cpp
Normal file
20
unittest/rebootLogic/src/event.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
#include "event.h"
|
||||
#include <queue>
|
||||
|
||||
std::queue<EventInfo> EVENT_QUEUE = {};
|
||||
|
||||
void triggerEvent(Event event, uint32_t p1, uint32_t p2) {
|
||||
EventInfo info = {};
|
||||
info.event = event;
|
||||
info.p1 = p1;
|
||||
info.p2 = p2;
|
||||
EVENT_QUEUE.push(info);
|
||||
}
|
||||
|
||||
void eventWasCalled(EventInfo& eventInfo, uint32_t& numEvents) {
|
||||
numEvents = EVENT_QUEUE.size();
|
||||
if(not EVENT_QUEUE.empty()) {
|
||||
eventInfo = std::move(EVENT_QUEUE.back());
|
||||
EVENT_QUEUE.pop();
|
||||
}
|
||||
}
|
40
unittest/rebootLogic/src/event.h
Normal file
40
unittest/rebootLogic/src/event.h
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include "definitions.h"
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
|
||||
struct EventInfo {
|
||||
// That was just for testing, follow rule of 0
|
||||
/*
|
||||
EventInfo () {}
|
||||
|
||||
EventInfo (const EventInfo& other): event(other.event), p1(other.p1), p2(other.p2) {
|
||||
std::cout << "Event info copy ctor called" << std::endl;
|
||||
}
|
||||
|
||||
EventInfo &operator= (const EventInfo& other) {
|
||||
std::cout << "Event info assignment ctor called" << std::endl;
|
||||
this->event = other.event;
|
||||
this->p1 = other.p1;
|
||||
this->p2 = other.p2;
|
||||
return *this;
|
||||
}
|
||||
|
||||
EventInfo &operator= (EventInfo&& other) {
|
||||
std::cout << "Event info move ctor called" << std::endl;
|
||||
this->event = other.event;
|
||||
this->p1 = other.p1;
|
||||
this->p2 = other.p2;
|
||||
return *this;
|
||||
}
|
||||
*/
|
||||
|
||||
uint32_t event = 0;
|
||||
uint32_t p1 = 0;
|
||||
uint32_t p2 = 0;
|
||||
};
|
||||
|
||||
void triggerEvent(Event event, uint32_t p1, uint32_t p2);
|
||||
|
||||
void eventWasCalled(EventInfo& eventInfo, uint32_t& numEvents);
|
23
unittest/rebootLogic/src/libxiphos.cpp
Normal file
23
unittest/rebootLogic/src/libxiphos.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include "libxiphos.h"
|
||||
#include "CoreController.h"
|
||||
|
||||
bool rebootWasCalled = false;
|
||||
xsc_libnor_chip_t lastChip;
|
||||
xsc_libnor_copy_t lastCopy;
|
||||
|
||||
bool getRebootWasCalled(xsc_libnor_chip_t& tgtChip, xsc_libnor_copy_t& tgtCopy) {
|
||||
tgtChip = lastChip;
|
||||
tgtCopy = lastCopy;
|
||||
bool tmp = rebootWasCalled;
|
||||
if(rebootWasCalled) {
|
||||
rebootWasCalled = false;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void xsc_boot_copy(xsc_libnor_chip_t boot_chip, xsc_libnor_copy_t boot_copy) {
|
||||
rebootWasCalled = true;
|
||||
lastChip = boot_chip;
|
||||
lastCopy = boot_copy;
|
||||
CoreController::setCurrentBootCopy(static_cast<xsc::Chip>(boot_chip), static_cast<xsc::Copy>(boot_copy));
|
||||
}
|
25
unittest/rebootLogic/src/libxiphos.h
Normal file
25
unittest/rebootLogic/src/libxiphos.h
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
/** Type for identifying the nominal or the gold (redundant) flash copy */
|
||||
typedef enum {
|
||||
XSC_LIBNOR_COPY_NOMINAL,
|
||||
XSC_LIBNOR_COPY_GOLD,
|
||||
XSC_LIBNOR_COPY_TOTAL_NUMBER
|
||||
} xsc_libnor_copy_t;
|
||||
|
||||
/** Type for identifying on of the two NOR flash chips */
|
||||
typedef enum {
|
||||
XSC_LIBNOR_CHIP_0, /* First NOR flash chip */
|
||||
XSC_LIBNOR_CHIP_1, /* Second NOR flash chip */
|
||||
XSC_LIBNOR_CHIP_TOTAL_NUMBER
|
||||
} xsc_libnor_chip_t;
|
||||
|
||||
/**
|
||||
* @brief Used to verify whether reboot function was called
|
||||
*
|
||||
* @param tgtChip
|
||||
* @param tgtCopy
|
||||
*/
|
||||
bool getRebootWasCalled(xsc_libnor_chip_t& tgtChip, xsc_libnor_copy_t& tgtCopy);
|
||||
|
||||
void xsc_boot_copy(xsc_libnor_chip_t boot_chip, xsc_libnor_copy_t boot_copy);
|
267
unittest/rebootLogic/src/main.cpp
Normal file
267
unittest/rebootLogic/src/main.cpp
Normal file
@ -0,0 +1,267 @@
|
||||
#include "CoreController.h"
|
||||
#include "libxiphos.h"
|
||||
#include "HasActionsIF.h"
|
||||
#include "event.h"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
|
||||
static constexpr bool CAT_FILE_TO_CONSOLE = false;
|
||||
const std::string CONF_PATH = "/tmp/conf";
|
||||
const std::string REBOOT_FILE = CONF_PATH + "/reboot.txt";
|
||||
|
||||
void catFileToConsole();
|
||||
|
||||
TEST_CASE( "Core Controller Reboot File Handling", "[reboot-file]" ) {
|
||||
if(not std::filesystem::exists(CONF_PATH)) {
|
||||
std::filesystem::create_directory(CONF_PATH);
|
||||
}
|
||||
CoreController ctrl;
|
||||
|
||||
|
||||
SECTION ("Primary") {
|
||||
xsc_libnor_chip_t chip;
|
||||
xsc_libnor_copy_t copy;
|
||||
RebootFile rf = {};
|
||||
ctrl.rewriteRebootFile(rf);
|
||||
REQUIRE(rf.enabled == 0);
|
||||
REQUIRE(rf.maxCount == RebootFile::DEFAULT_MAX_BOOT_CNT);
|
||||
REQUIRE(rf.img00Cnt == 0);
|
||||
REQUIRE(rf.img01Cnt == 0);
|
||||
REQUIRE(rf.img10Cnt == 0);
|
||||
REQUIRE(rf.img11Cnt == 0);
|
||||
REQUIRE(rf.bootFlag == 0);
|
||||
REQUIRE(rf.lastChip == 0);
|
||||
REQUIRE(rf.lastCopy == 0);
|
||||
// This recreates the file but should also increment the boot counter of the current image
|
||||
REQUIRE(ctrl.CURRENT_CHIP == xsc::CHIP_0);
|
||||
REQUIRE(ctrl.CURRENT_COPY == xsc::COPY_0);
|
||||
ctrl.performRebootFileHandling(true);
|
||||
catFileToConsole();
|
||||
ctrl.parseRebootFile(REBOOT_FILE, rf);
|
||||
REQUIRE(rf.enabled == 1);
|
||||
REQUIRE(rf.maxCount == RebootFile::DEFAULT_MAX_BOOT_CNT);
|
||||
REQUIRE(rf.img00Cnt == 1);
|
||||
REQUIRE(rf.img01Cnt == 0);
|
||||
REQUIRE(rf.img10Cnt == 0);
|
||||
REQUIRE(rf.img11Cnt == 0);
|
||||
REQUIRE(rf.bootFlag == 0);
|
||||
REQUIRE(rf.lastChip == 0);
|
||||
REQUIRE(rf.lastCopy == 0);
|
||||
uint8_t newRebootCnt = 3;
|
||||
CHECK(ctrl.executeAction(CoreController::SET_MAX_REBOOT_CNT, 0, &newRebootCnt, 1) == HasActionsIF::EXECUTION_FINISHED);
|
||||
ctrl.parseRebootFile(REBOOT_FILE, rf);
|
||||
REQUIRE(rf.enabled == 1);
|
||||
REQUIRE(rf.maxCount == 3);
|
||||
REQUIRE(not getRebootWasCalled(chip, copy));
|
||||
ctrl.performRebootFileHandling(false);
|
||||
ctrl.performRebootFileHandling(false);
|
||||
ctrl.parseRebootFile(REBOOT_FILE, rf);
|
||||
REQUIRE(rf.enabled == 1);
|
||||
REQUIRE(rf.img00Cnt == 3);
|
||||
REQUIRE(rf.img01Cnt == 0);
|
||||
REQUIRE(rf.img10Cnt == 0);
|
||||
REQUIRE(rf.img11Cnt == 0);
|
||||
REQUIRE(rf.bootFlag == true);
|
||||
REQUIRE(rf.lastChip == xsc::CHIP_0);
|
||||
REQUIRE(rf.lastCopy == xsc::COPY_0);
|
||||
REQUIRE(getRebootWasCalled(chip, copy));
|
||||
REQUIRE(chip == XSC_LIBNOR_CHIP_0);
|
||||
REQUIRE(copy == XSC_LIBNOR_COPY_GOLD);
|
||||
EventInfo info = {};
|
||||
uint32_t numEvents = 0;
|
||||
|
||||
// We are now on image 0 1 and an event will be triggered
|
||||
ctrl.performRebootFileHandling(false);
|
||||
eventWasCalled(info, numEvents);
|
||||
CHECK(numEvents == 1);
|
||||
CHECK(info.event == CoreController::REBOOT_MECHANISM_TRIGGERED);
|
||||
CHECK(static_cast<xsc::Chip>((info.p1 >> 16) & 0xFFFF) == xsc::CHIP_0);
|
||||
CHECK(static_cast<xsc::Copy>(info.p1 & 0xFFFF) == xsc::COPY_0);
|
||||
CHECK(((info.p2 >> 24) & 0xFF) == 3);
|
||||
CHECK(((info.p2 >> 16) & 0xFF) == 1);
|
||||
CHECK(((info.p2 >> 8) & 0xFF) == 0);
|
||||
CHECK((info.p2 & 0xFF) == 0);
|
||||
ctrl.parseRebootFile(REBOOT_FILE, rf);
|
||||
REQUIRE(rf.enabled == 1);
|
||||
REQUIRE(rf.img00Cnt == 3);
|
||||
REQUIRE(rf.img01Cnt == 1);
|
||||
REQUIRE(rf.img10Cnt == 0);
|
||||
REQUIRE(rf.img11Cnt == 0);
|
||||
// Flag was cleared when event was thrown
|
||||
REQUIRE(rf.bootFlag == false);
|
||||
REQUIRE(rf.lastChip == xsc::CHIP_0);
|
||||
REQUIRE(rf.lastCopy == xsc::COPY_0);
|
||||
ctrl.performRebootFileHandling(false);
|
||||
ctrl.performRebootFileHandling(false);
|
||||
ctrl.parseRebootFile(REBOOT_FILE, rf);
|
||||
REQUIRE(rf.enabled == 1);
|
||||
REQUIRE(rf.img00Cnt == 3);
|
||||
REQUIRE(rf.img01Cnt == 3);
|
||||
REQUIRE(rf.img10Cnt == 0);
|
||||
REQUIRE(rf.img11Cnt == 0);
|
||||
|
||||
// We are now on image 1 0 and an event will be triggered
|
||||
ctrl.performRebootFileHandling(false);
|
||||
eventWasCalled(info, numEvents);
|
||||
CHECK(numEvents == 1);
|
||||
CHECK(info.event == CoreController::REBOOT_MECHANISM_TRIGGERED);
|
||||
CHECK(static_cast<xsc::Chip>((info.p1 >> 16) & 0xFFFF) == xsc::CHIP_0);
|
||||
CHECK(static_cast<xsc::Copy>(info.p1 & 0xFFFF) == xsc::COPY_1);
|
||||
CHECK(((info.p2 >> 24) & 0xFF) == 3);
|
||||
CHECK(((info.p2 >> 16) & 0xFF) == 3);
|
||||
CHECK(((info.p2 >> 8) & 0xFF) == 1);
|
||||
CHECK((info.p2 & 0xFF) == 0);
|
||||
ctrl.parseRebootFile(REBOOT_FILE, rf);
|
||||
REQUIRE(rf.enabled == 1);
|
||||
REQUIRE(rf.img00Cnt == 3);
|
||||
REQUIRE(rf.img01Cnt == 3);
|
||||
REQUIRE(rf.img10Cnt == 1);
|
||||
REQUIRE(rf.img11Cnt == 0);
|
||||
ctrl.performRebootFileHandling(false);
|
||||
ctrl.performRebootFileHandling(false);
|
||||
ctrl.parseRebootFile(REBOOT_FILE, rf);
|
||||
REQUIRE(rf.enabled == 1);
|
||||
REQUIRE(rf.img00Cnt == 3);
|
||||
REQUIRE(rf.img01Cnt == 3);
|
||||
REQUIRE(rf.img10Cnt == 3);
|
||||
REQUIRE(rf.img11Cnt == 0);
|
||||
eventWasCalled(info, numEvents);
|
||||
|
||||
// On image 1 1 now
|
||||
ctrl.performRebootFileHandling(false);
|
||||
eventWasCalled(info, numEvents);
|
||||
CHECK(numEvents == 1);
|
||||
CHECK(info.event == CoreController::REBOOT_MECHANISM_TRIGGERED);
|
||||
CHECK(static_cast<xsc::Chip>((info.p1 >> 16) & 0xFFFF) == xsc::CHIP_1);
|
||||
CHECK(static_cast<xsc::Copy>(info.p1 & 0xFFFF) == xsc::COPY_0);
|
||||
CHECK(((info.p2 >> 24) & 0xFF) == 3);
|
||||
CHECK(((info.p2 >> 16) & 0xFF) == 3);
|
||||
CHECK(((info.p2 >> 8) & 0xFF) == 3);
|
||||
CHECK((info.p2 & 0xFF) == 1);
|
||||
|
||||
ctrl.performRebootFileHandling(false);
|
||||
ctrl.performRebootFileHandling(false);
|
||||
// Now it should fall back to 0 0 because all are invalid
|
||||
ctrl.parseRebootFile(REBOOT_FILE, rf);
|
||||
REQUIRE(rf.enabled == 1);
|
||||
REQUIRE(rf.img00Cnt == 3);
|
||||
REQUIRE(rf.img01Cnt == 3);
|
||||
REQUIRE(rf.img10Cnt == 3);
|
||||
REQUIRE(rf.img11Cnt == 3);
|
||||
|
||||
// Should remain on image now
|
||||
ctrl.performRebootFileHandling(false);
|
||||
eventWasCalled(info, numEvents);
|
||||
CHECK(numEvents == 1);
|
||||
CHECK(info.event == CoreController::REBOOT_MECHANISM_TRIGGERED);
|
||||
CHECK(static_cast<xsc::Chip>((info.p1 >> 16) & 0xFFFF) == xsc::CHIP_1);
|
||||
CHECK(static_cast<xsc::Copy>(info.p1 & 0xFFFF) == xsc::COPY_1);
|
||||
CHECK(((info.p2 >> 24) & 0xFF) == 4);
|
||||
CHECK(((info.p2 >> 16) & 0xFF) == 3);
|
||||
CHECK(((info.p2 >> 8) & 0xFF) == 3);
|
||||
CHECK((info.p2 & 0xFF) == 3);
|
||||
ctrl.parseRebootFile(REBOOT_FILE, rf);
|
||||
REQUIRE(rf.img00Cnt == 4);
|
||||
REQUIRE(rf.img01Cnt == 3);
|
||||
REQUIRE(rf.img10Cnt == 3);
|
||||
REQUIRE(rf.img11Cnt == 3);
|
||||
|
||||
// Reset a specific reboot counter
|
||||
ctrl.executeAction(CoreController::RESET_REBOOT_COUNTER_01, 0, nullptr, 0);
|
||||
// Reboot to 0 0 again
|
||||
ctrl.performRebootFileHandling(false);
|
||||
ctrl.parseRebootFile(REBOOT_FILE, rf);
|
||||
REQUIRE(rf.enabled == 1);
|
||||
REQUIRE(rf.img00Cnt == 5);
|
||||
REQUIRE(rf.img01Cnt == 0);
|
||||
REQUIRE(rf.img10Cnt == 3);
|
||||
REQUIRE(rf.img11Cnt == 3);
|
||||
CHECK(CoreController::CURRENT_CHIP == xsc::CHIP_0);
|
||||
CHECK(CoreController::CURRENT_COPY == xsc::COPY_1);
|
||||
ctrl.executeAction(CoreController::RESET_ALL_REBOOT_COUNTERS, 0, nullptr, 0);
|
||||
ctrl.parseRebootFile(REBOOT_FILE, rf);
|
||||
REQUIRE(rf.enabled == 1);
|
||||
REQUIRE(rf.img00Cnt == 0);
|
||||
REQUIRE(rf.img01Cnt == 0);
|
||||
REQUIRE(rf.img10Cnt == 0);
|
||||
REQUIRE(rf.img11Cnt == 0);
|
||||
uint8_t enable = 0;
|
||||
ctrl.executeAction(CoreController::SWITCH_REBOOT_FILE_HANDLING, 0, &enable, 1);
|
||||
ctrl.parseRebootFile(REBOOT_FILE, rf);
|
||||
REQUIRE(rf.enabled == 0);
|
||||
REQUIRE(rf.img00Cnt == 0);
|
||||
REQUIRE(rf.img01Cnt == 0);
|
||||
REQUIRE(rf.img10Cnt == 0);
|
||||
REQUIRE(rf.img11Cnt == 0);
|
||||
|
||||
// Reboot to 1 0 explicitely
|
||||
CoreController::setCurrentBootCopy(xsc::CHIP_1, xsc::COPY_0);
|
||||
// Reboot three times and verify that no reboot is performed
|
||||
ctrl.performRebootFileHandling(false);
|
||||
ctrl.performRebootFileHandling(false);
|
||||
ctrl.performRebootFileHandling(false);
|
||||
ctrl.performRebootFileHandling(false);
|
||||
ctrl.parseRebootFile(REBOOT_FILE, rf);
|
||||
REQUIRE(rf.enabled == 0);
|
||||
REQUIRE(rf.img00Cnt == 0);
|
||||
REQUIRE(rf.img01Cnt == 0);
|
||||
REQUIRE(rf.img10Cnt == 4);
|
||||
REQUIRE(rf.img11Cnt == 0);
|
||||
// Now enable the functionality again and verify it reboots to 1 1
|
||||
enable = 1;
|
||||
ctrl.executeAction(CoreController::SWITCH_REBOOT_FILE_HANDLING, 0, &enable, 1);
|
||||
ctrl.performRebootFileHandling(false);
|
||||
ctrl.parseRebootFile(REBOOT_FILE, rf);
|
||||
REQUIRE(rf.enabled == 1);
|
||||
REQUIRE(rf.img00Cnt == 0);
|
||||
REQUIRE(rf.img01Cnt == 0);
|
||||
REQUIRE(rf.img10Cnt == 5);
|
||||
REQUIRE(rf.img11Cnt == 0);
|
||||
ctrl.performRebootFileHandling(false);
|
||||
ctrl.parseRebootFile(REBOOT_FILE, rf);
|
||||
REQUIRE(rf.enabled == 1);
|
||||
REQUIRE(rf.img00Cnt == 0);
|
||||
REQUIRE(rf.img01Cnt == 0);
|
||||
REQUIRE(rf.img10Cnt == 5);
|
||||
REQUIRE(rf.img11Cnt == 1);
|
||||
ctrl.performRebootFileHandling(false);
|
||||
ctrl.performRebootFileHandling(false);
|
||||
// Should be on 0 0 now
|
||||
CHECK(CoreController::CURRENT_CHIP == xsc::CHIP_0);
|
||||
CHECK(CoreController::CURRENT_COPY == xsc::COPY_0);
|
||||
ctrl.performRebootFileHandling(false);
|
||||
ctrl.parseRebootFile(REBOOT_FILE, rf);
|
||||
REQUIRE(rf.enabled == 1);
|
||||
REQUIRE(rf.img00Cnt == 1);
|
||||
REQUIRE(rf.img01Cnt == 0);
|
||||
REQUIRE(rf.img10Cnt == 5);
|
||||
REQUIRE(rf.img11Cnt == 3);
|
||||
|
||||
// Now reset all reboot counters manually
|
||||
ctrl.executeAction(CoreController::RESET_REBOOT_COUNTER_00, 0, nullptr, 0);
|
||||
ctrl.executeAction(CoreController::RESET_REBOOT_COUNTER_10, 0, nullptr, 0);
|
||||
ctrl.executeAction(CoreController::RESET_REBOOT_COUNTER_11, 0, nullptr, 0);
|
||||
ctrl.parseRebootFile(REBOOT_FILE, rf);
|
||||
REQUIRE(rf.enabled == 1);
|
||||
REQUIRE(rf.img00Cnt == 0);
|
||||
REQUIRE(rf.img01Cnt == 0);
|
||||
REQUIRE(rf.img10Cnt == 0);
|
||||
REQUIRE(rf.img11Cnt == 0);
|
||||
}
|
||||
if(std::filesystem::exists(CONF_PATH)) {
|
||||
std::uintmax_t n = std::filesystem::remove_all(CONF_PATH);
|
||||
CHECK(n == 2);
|
||||
}
|
||||
}
|
||||
|
||||
void catFileToConsole() {
|
||||
if(CAT_FILE_TO_CONSOLE) {
|
||||
std::ifstream file(REBOOT_FILE);
|
||||
if (file.is_open()) {
|
||||
std::cout << file.rdbuf();
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user