diff --git a/.gitignore b/.gitignore
index a5065673..5419ca42 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,8 +12,13 @@
#vscode
/.vscode
+# IntelliJ
+/.idea/*
+
# Python
__pycache__
-.idea
+
+# CLion
+!/.idea/cmake.xml
generators/*.db
diff --git a/.run/Q7S FM.run.xml b/.run/Q7S FM.run.xml
new file mode 100644
index 00000000..ea4ae083
--- /dev/null
+++ b/.run/Q7S FM.run.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7ea6666a..a70cb5ba 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -28,9 +28,46 @@ will consitute of a breaking change warranting a new major release:
- The SD card prefix is now set earlier inside the `CoreController` constructor
- The watchdog handling was moved outside the `CoreController` into the main loop.
+# [v1.32.0]
+
+eive-tmtc: v2.16.1
+
## Fixed
- ADIS1650X: Added missing MDL_RANG pool entry for configuration set
+- Bumped FSFW for bugfix in health service: No execution complete for targeted health announce
+ command.
+- Removed matrix determinant calculation as part of the `MEKF`, which would take about
+ 300ms of runtime
+- Resetting the `MEKF` now also actually resets its stored state
+- Bumped FSFW for bugfix in destination handler: Better error handling and able to process
+ destination folder path.
+
+## Changed
+
+- Added basic persistent TM store for PUS telemetry and basic interface to dump and delete
+ telemetry. Implementation is based on a timed rotating files, with the addition that files
+ might be generated more often if the maximum file size of 8192 bytes is exceeded.
+ PR: https://egit.irs.uni-stuttgart.de/eive/eive-obsw/pulls/320/files
+- Commented out commanding of actuators as part of the `AcsController`
+- Collection sets of the `AcsController` now get updated before running the actual ACS
+ algorithm
+- `GpsController` now always gets scheduled
+- The `CoreController` now initializes the initial clock from the time file as early as possible
+ (in the constructor) if possible, which should usually be the case.
+
+## Added
+
+- Added basic persistent TM store for PUS telemetry and basic interface to dump and delete
+ telemetry.
+ PR: https://egit.irs.uni-stuttgart.de/eive/eive-obsw/pulls/320/files
+- `ExecutableComIfDummy` class to have a dummy for classes like the RTD polling class.
+- Added `AcsController` action command to confirm solar array deployment, which then deletes
+ two files
+- Added `AcsController` action command to reset `MEKF`
+- `GpsCtrlDummy` now initializes the `gpsSet`
+- `RwDummy` now initializes with a non faulty state
+
# [v1.31.1]
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a0768ddd..a9eef222 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,8 +10,8 @@
cmake_minimum_required(VERSION 3.13)
set(OBSW_VERSION_MAJOR 1)
-set(OBSW_VERSION_MINOR 31)
-set(OBSW_VERSION_REVISION 1)
+set(OBSW_VERSION_MINOR 32)
+set(OBSW_VERSION_REVISION 0)
# set(CMAKE_VERBOSE TRUE)
@@ -223,6 +223,7 @@ set(LIB_JSON_PATH ${THIRD_PARTY_FOLDER}/json)
set(FSFW_WARNING_SHADOW_LOCAL_GCC OFF)
set(EIVE_ADD_LINUX_FILES OFF)
+set(FSFW_ADD_TMSTORAGE ON)
# Analyse different OS and architecture/target options, determine BSP_PATH,
# display information about compiler etc.
diff --git a/README.md b/README.md
index b6fa64e9..cd350386 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,7 @@
11. [Q7S OBC](#q7s)
12. [Static Code Analysis](#static-code-analysis)
13. [Eclipse](#eclipse)
+14. [CLion](#clion)
14. [Running the OBSW on a Raspberry Pi](#rpi)
15. [Running OBSW on EGSE](#egse)
16. [Manually preparing sysroots to compile gpsd](#gpsd)
@@ -1229,6 +1230,22 @@ Finally, you can convert the generated `.xml` file to HTML with the following co
cppcheck-htmlreport --file=report.xml --report-dir=cppcheck --source-dir=..
```
+# CLion
+
+CLion is the recommended IDE for the development of the hosted version of EIVE.
+You can also set up CLion for cross-compilation of the primary OBSW.
+
+There is a shared `.idea/cmake.xml` file to get started with this.
+To make cross-compilation work, two special environment variables
+need to be set:
+
+- `ZYNQ_7020_ROOTFS` pointing to the root filesystem
+- `CROSS_COMPILE` pointing to the the full path of the cross-compiler
+ without the specific tool suffix. For example, if the the cross-compiler
+ tools are located at `/opt/q7s-gcc/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin`,
+ this variable would be set
+ to `/opt/q7s-gcc/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/arm-linux-gnueabihf`
+
# Eclipse
When using Eclipse, there are two special build variables in the project properties
diff --git a/bsp_hosted/ObjectFactory.cpp b/bsp_hosted/ObjectFactory.cpp
index d2c3c3da..3f25939e 100644
--- a/bsp_hosted/ObjectFactory.cpp
+++ b/bsp_hosted/ObjectFactory.cpp
@@ -8,6 +8,7 @@
#include
#include
+#include "../mission/utility/DummySdCardManager.h"
#include "OBSWConfig.h"
#include "fsfw/platform.h"
#include "fsfw_tests/integration/task/TestTask.h"
@@ -58,7 +59,8 @@ void ObjectFactory::produce(void* args) {
Factory::setStaticFrameworkObjectIds();
PusTmFunnel* pusFunnel;
CfdpTmFunnel* cfdpFunnel;
- ObjectFactory::produceGenericObjects(nullptr, &pusFunnel, &cfdpFunnel);
+ auto sdcMan = new DummySdCardManager("/tmp");
+ ObjectFactory::produceGenericObjects(nullptr, &pusFunnel, &cfdpFunnel, *sdcMan);
auto* dummyGpioIF = new DummyGpioIF();
auto* dummySwitcher = new DummyPowerSwitcher(objects::PCDU_HANDLER, 18, 0);
diff --git a/bsp_hosted/fsfwconfig/events/translateEvents.cpp b/bsp_hosted/fsfwconfig/events/translateEvents.cpp
index e35a31ef..c979ff5e 100644
--- a/bsp_hosted/fsfwconfig/events/translateEvents.cpp
+++ b/bsp_hosted/fsfwconfig/events/translateEvents.cpp
@@ -1,7 +1,7 @@
/**
- * @brief Auto-generated event translation file. Contains 260 translations.
+ * @brief Auto-generated event translation file. Contains 263 translations.
* @details
- * Generated on: 2023-02-23 15:39:20
+ * Generated on: 2023-02-24 16:57:00
*/
#include "translateEvents.h"
@@ -90,6 +90,8 @@ const char *CHANGE_OF_SETUP_PARAMETER_STRING = "CHANGE_OF_SETUP_PARAMETER";
const char *STORE_ERROR_STRING = "STORE_ERROR";
const char *MSG_QUEUE_ERROR_STRING = "MSG_QUEUE_ERROR";
const char *SERIALIZATION_ERROR_STRING = "SERIALIZATION_ERROR";
+const char *FILESTORE_ERROR_STRING = "FILESTORE_ERROR";
+const char *FILENAME_TOO_LARGE_ERROR_STRING = "FILENAME_TOO_LARGE_ERROR";
const char *SAFE_RATE_VIOLATION_STRING = "SAFE_RATE_VIOLATION";
const char *SAFE_RATE_RECOVERY_STRING = "SAFE_RATE_RECOVERY";
const char *MULTIPLE_RW_INVALID_STRING = "MULTIPLE_RW_INVALID";
@@ -253,6 +255,7 @@ const char *REBOOT_HW_STRING = "REBOOT_HW";
const char *NO_SD_CARD_ACTIVE_STRING = "NO_SD_CARD_ACTIVE";
const char *VERSION_INFO_STRING = "VERSION_INFO";
const char *CURRENT_IMAGE_INFO_STRING = "CURRENT_IMAGE_INFO";
+const char *POSSIBLE_FILE_CORRUPTION_STRING = "POSSIBLE_FILE_CORRUPTION";
const char *NO_VALID_SENSOR_TEMPERATURE_STRING = "NO_VALID_SENSOR_TEMPERATURE";
const char *NO_HEALTHY_HEATER_AVAILABLE_STRING = "NO_HEALTHY_HEATER_AVAILABLE";
const char *SYRLINKS_OVERHEATING_STRING = "SYRLINKS_OVERHEATING";
@@ -433,6 +436,10 @@ const char *translateEvents(Event event) {
return MSG_QUEUE_ERROR_STRING;
case (10802):
return SERIALIZATION_ERROR_STRING;
+ case (10803):
+ return FILESTORE_ERROR_STRING;
+ case (10804):
+ return FILENAME_TOO_LARGE_ERROR_STRING;
case (11200):
return SAFE_RATE_VIOLATION_STRING;
case (11201):
@@ -760,18 +767,20 @@ const char *translateEvents(Event event) {
case (14006):
return CURRENT_IMAGE_INFO_STRING;
case (14100):
+ return POSSIBLE_FILE_CORRUPTION_STRING;
+ case (14200):
return NO_VALID_SENSOR_TEMPERATURE_STRING;
- case (14101):
+ case (14201):
return NO_HEALTHY_HEATER_AVAILABLE_STRING;
- case (14102):
+ case (14202):
return SYRLINKS_OVERHEATING_STRING;
- case (14103):
+ case (14203):
return PLOC_OVERHEATING_STRING;
- case (14104):
+ case (14204):
return OBC_OVERHEATING_STRING;
- case (14105):
+ case (14205):
return HPA_OVERHEATING_STRING;
- case (14106):
+ case (14206):
return PLPCDU_OVERHEATING_STRING;
default:
return "UNKNOWN_EVENT";
diff --git a/bsp_hosted/fsfwconfig/objects/translateObjects.cpp b/bsp_hosted/fsfwconfig/objects/translateObjects.cpp
index 63e56ef2..be60d130 100644
--- a/bsp_hosted/fsfwconfig/objects/translateObjects.cpp
+++ b/bsp_hosted/fsfwconfig/objects/translateObjects.cpp
@@ -1,8 +1,8 @@
/**
* @brief Auto-generated object translation file.
* @details
- * Contains 148 translations.
- * Generated on: 2023-02-23 15:39:20
+ * Contains 154 translations.
+ * Generated on: 2023-02-24 16:57:00
*/
#include "translateObjects.h"
@@ -112,6 +112,7 @@ const char *PUS_SERVICE_5_EVENT_REPORTING_STRING = "PUS_SERVICE_5_EVENT_REPORTIN
const char *PUS_SERVICE_8_FUNCTION_MGMT_STRING = "PUS_SERVICE_8_FUNCTION_MGMT";
const char *PUS_SERVICE_9_TIME_MGMT_STRING = "PUS_SERVICE_9_TIME_MGMT";
const char *PUS_SERVICE_11_TC_SCHEDULER_STRING = "PUS_SERVICE_11_TC_SCHEDULER";
+const char *PUS_SERVICE_15_TM_STORAGE_STRING = "PUS_SERVICE_15_TM_STORAGE";
const char *PUS_SERVICE_17_TEST_STRING = "PUS_SERVICE_17_TEST";
const char *PUS_SERVICE_20_PARAMETERS_STRING = "PUS_SERVICE_20_PARAMETERS";
const char *PUS_SERVICE_200_MODE_MGMT_STRING = "PUS_SERVICE_200_MODE_MGMT";
@@ -150,6 +151,11 @@ const char *ACS_SUBSYSTEM_STRING = "ACS_SUBSYSTEM";
const char *PL_SUBSYSTEM_STRING = "PL_SUBSYSTEM";
const char *TCS_SUBSYSTEM_STRING = "TCS_SUBSYSTEM";
const char *COM_SUBSYSTEM_STRING = "COM_SUBSYSTEM";
+const char *MISC_TM_STORE_STRING = "MISC_TM_STORE";
+const char *OK_TM_STORE_STRING = "OK_TM_STORE";
+const char *NOT_OK_TM_STORE_STRING = "NOT_OK_TM_STORE";
+const char *HK_TM_STORE_STRING = "HK_TM_STORE";
+const char *CFDP_TM_STORE_STRING = "CFDP_TM_STORE";
const char *CCSDS_IP_CORE_BRIDGE_STRING = "CCSDS_IP_CORE_BRIDGE";
const char *THERMAL_TEMP_INSERTER_STRING = "THERMAL_TEMP_INSERTER";
const char *DUMMY_INTERFACE_STRING = "DUMMY_INTERFACE";
@@ -369,6 +375,8 @@ const char *translateObject(object_id_t object) {
return PUS_SERVICE_9_TIME_MGMT_STRING;
case 0x53000011:
return PUS_SERVICE_11_TC_SCHEDULER_STRING;
+ case 0x53000015:
+ return PUS_SERVICE_15_TM_STORAGE_STRING;
case 0x53000017:
return PUS_SERVICE_17_TEST_STRING;
case 0x53000020:
@@ -445,6 +453,16 @@ const char *translateObject(object_id_t object) {
return TCS_SUBSYSTEM_STRING;
case 0x73010004:
return COM_SUBSYSTEM_STRING;
+ case 0x73020001:
+ return MISC_TM_STORE_STRING;
+ case 0x73020002:
+ return OK_TM_STORE_STRING;
+ case 0x73020003:
+ return NOT_OK_TM_STORE_STRING;
+ case 0x73020004:
+ return HK_TM_STORE_STRING;
+ case 0x73030000:
+ return CFDP_TM_STORE_STRING;
case 0x73500000:
return CCSDS_IP_CORE_BRIDGE_STRING;
case 0x90000003:
diff --git a/bsp_hosted/scheduling.cpp b/bsp_hosted/scheduling.cpp
index 270de82e..9f859b6c 100644
--- a/bsp_hosted/scheduling.cpp
+++ b/bsp_hosted/scheduling.cpp
@@ -95,46 +95,43 @@ void scheduling::initTasks() {
sif::error << "Add component UDP Polling failed" << std::endl;
}
- /* PUS Services */
- PeriodicTaskIF* pusVerification = factory->createPeriodicTask(
- "PUS_VERIF", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
- result = pusVerification->addComponent(objects::PUS_SERVICE_1_VERIFICATION);
+ PeriodicTaskIF* pusHighPrio = factory->createPeriodicTask(
+ "PUS_HIGH_PRIO", 60, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
+ result = pusHighPrio->addComponent(objects::PUS_SERVICE_1_VERIFICATION);
if (result != returnvalue::OK) {
sif::error << "Object add component failed" << std::endl;
}
-
- PeriodicTaskIF* eventHandling = factory->createPeriodicTask(
- "EVENTS", 60, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
- result = eventHandling->addComponent(objects::EVENT_MANAGER);
+ result = pusHighPrio->addComponent(objects::EVENT_MANAGER);
if (result != returnvalue::OK) {
- scheduling::printAddObjectError("EVENT_MNGR", objects::EVENT_MANAGER);
+ scheduling::printAddObjectError("EVENT_MGMT", objects::EVENT_MANAGER);
}
- result = eventHandling->addComponent(objects::PUS_SERVICE_5_EVENT_REPORTING);
+ result = pusHighPrio->addComponent(objects::PUS_SERVICE_5_EVENT_REPORTING);
if (result != returnvalue::OK) {
scheduling::printAddObjectError("PUS5", objects::PUS_SERVICE_5_EVENT_REPORTING);
}
-
- PeriodicTaskIF* pusHighPrio = factory->createPeriodicTask(
- "PUS_HIGH_PRIO", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
- result = pusHighPrio->addComponent(objects::PUS_SERVICE_2_DEVICE_ACCESS);
- if (result != returnvalue::OK) {
- scheduling::printAddObjectError("PUS2", objects::PUS_SERVICE_2_DEVICE_ACCESS);
- }
result = pusHighPrio->addComponent(objects::PUS_SERVICE_9_TIME_MGMT);
if (result != returnvalue::OK) {
scheduling::printAddObjectError("PUS9", objects::PUS_SERVICE_9_TIME_MGMT);
}
+
+ PeriodicTaskIF* pusMedPrio = factory->createPeriodicTask(
+ "PUS_MED_PRIO", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.8, missedDeadlineFunc);
+ result = pusHighPrio->addComponent(objects::PUS_SERVICE_2_DEVICE_ACCESS);
+ if (result != returnvalue::OK) {
+ scheduling::printAddObjectError("PUS2", objects::PUS_SERVICE_2_DEVICE_ACCESS);
+ }
result = pusHighPrio->addComponent(objects::PUS_SERVICE_3_HOUSEKEEPING);
if (result != returnvalue::OK) {
scheduling::printAddObjectError("PUS3", objects::PUS_SERVICE_3_HOUSEKEEPING);
}
-
- PeriodicTaskIF* pusMedPrio = factory->createPeriodicTask(
- "PUS_MED_PRIO", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.8, missedDeadlineFunc);
result = pusMedPrio->addComponent(objects::PUS_SERVICE_8_FUNCTION_MGMT);
if (result != returnvalue::OK) {
scheduling::printAddObjectError("PUS8", objects::PUS_SERVICE_8_FUNCTION_MGMT);
}
+ result = pusMedPrio->addComponent(objects::PUS_SERVICE_15_TM_STORAGE);
+ if (result != returnvalue::OK) {
+ scheduling::printAddObjectError("PUS15", objects::PUS_SERVICE_15_TM_STORAGE);
+ }
result = pusMedPrio->addComponent(objects::PUS_SERVICE_200_MODE_MGMT);
if (result != returnvalue::OK) {
scheduling::printAddObjectError("PUS200", objects::PUS_SERVICE_200_MODE_MGMT);
@@ -143,10 +140,7 @@ void scheduling::initTasks() {
if (result != returnvalue::OK) {
scheduling::printAddObjectError("PUS20", objects::PUS_SERVICE_20_PARAMETERS);
}
-
- PeriodicTaskIF* pusLowPrio = factory->createPeriodicTask(
- "PUS_LOW_PRIO", 30, PeriodicTaskIF::MINIMUM_STACK_SIZE, 1.6, missedDeadlineFunc);
- result = pusLowPrio->addComponent(objects::PUS_SERVICE_17_TEST);
+ result = pusMedPrio->addComponent(objects::PUS_SERVICE_17_TEST);
if (result != returnvalue::OK) {
scheduling::printAddObjectError("PUS17", objects::PUS_SERVICE_17_TEST);
}
@@ -220,11 +214,8 @@ void scheduling::initTasks() {
udpPollingTask->startTask();
tcpPollingTask->startTask();
- pusVerification->startTask();
- eventHandling->startTask();
pusHighPrio->startTask();
pusMedPrio->startTask();
- pusLowPrio->startTask();
pstTask->startTask();
thermalTask->startTask();
diff --git a/bsp_linux_board/CMakeLists.txt b/bsp_linux_board/CMakeLists.txt
index 39f06401..9e3ec023 100644
--- a/bsp_linux_board/CMakeLists.txt
+++ b/bsp_linux_board/CMakeLists.txt
@@ -1,5 +1,5 @@
target_sources(${OBSW_NAME} PUBLIC InitMission.cpp main.cpp gpioInit.cpp
- ObjectFactory.cpp RPiSdCardManager.cpp)
+ ObjectFactory.cpp)
add_subdirectory(boardconfig)
add_subdirectory(boardtest)
diff --git a/bsp_linux_board/ObjectFactory.cpp b/bsp_linux_board/ObjectFactory.cpp
index 53db052c..95ea87bb 100644
--- a/bsp_linux_board/ObjectFactory.cpp
+++ b/bsp_linux_board/ObjectFactory.cpp
@@ -82,7 +82,7 @@ void ObjectFactory::produce(void* args) {
#endif
#if OBSW_ADD_SCEX_DEVICE == 1
- auto* sdcMan = new RPiSdCardManager("/tmp");
+ auto* sdcMan = new DummySdCardManager("/tmp");
createScexComponents(uart::DEV, pwrSwitcher, *sdcMan, true, std::nullopt);
#endif
diff --git a/bsp_linux_board/RPiSdCardManager.cpp b/bsp_linux_board/RPiSdCardManager.cpp
deleted file mode 100644
index dfcae8da..00000000
--- a/bsp_linux_board/RPiSdCardManager.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "RPiSdCardManager.h"
-
-RPiSdCardManager::RPiSdCardManager(std::string prefix) : prefix(std::move(prefix)) {}
-
-const std::string& RPiSdCardManager::getCurrentMountPrefix() const { return prefix; }
-
-bool RPiSdCardManager::isSdCardUsable(sd::SdCard sdCard) { return true; }
-
-std::optional RPiSdCardManager::getPreferredSdCard() const { return std::nullopt; }
-
-void RPiSdCardManager::setActiveSdCard(sd::SdCard sdCard) {}
-
-std::optional RPiSdCardManager::getActiveSdCard() const { return std::nullopt; }
diff --git a/bsp_q7s/core/CoreController.cpp b/bsp_q7s/core/CoreController.cpp
index 8379dad2..808935b6 100644
--- a/bsp_q7s/core/CoreController.cpp
+++ b/bsp_q7s/core/CoreController.cpp
@@ -54,6 +54,8 @@ CoreController::CoreController(object_id_t objectId)
currMntPrefix = sdcMan->getCurrentMountPrefix();
getCurrentBootCopy(CURRENT_CHIP, CURRENT_COPY);
+
+ initClockFromTimeFile();
} catch (const std::filesystem::filesystem_error &e) {
sif::error << "CoreController::CoreController: Failed with exception " << e.what() << std::endl;
}
@@ -1196,10 +1198,12 @@ void CoreController::performMountedSdCardOperations() {
if (result != returnvalue::OK) {
sif::warning << "CoreController::CoreController: Boot copy init" << std::endl;
}
- initClockFromTimeFile();
+ if (not timeFileInitDone) {
+ initClockFromTimeFile();
+ }
performRebootFileHandling(false);
}
- timeFileHandler();
+ backupTimeFileHandler();
};
bool someSdCardActive = false;
if (sdInfo.active == sd::SdCard::SLOT_0 and sdcMan->isSdCardUsable(sd::SdCard::SLOT_0)) {
@@ -1713,7 +1717,7 @@ void CoreController::setRebootMechanismLock(bool lock, xsc::Chip tgtChip, xsc::C
rewriteRebootFile(rebootFile);
}
-ReturnValue_t CoreController::timeFileHandler() {
+ReturnValue_t CoreController::backupTimeFileHandler() {
// Always set time. We could only set it if it is updated by GPS, but then the backup time would
// become obsolete on GPS problems.
if (opDivider10.check()) {
@@ -1723,14 +1727,14 @@ ReturnValue_t CoreController::timeFileHandler() {
if (result != returnvalue::OK) {
return result;
}
- std::string fileName = currMntPrefix + TIME_FILE;
+ std::string fileName = currMntPrefix + BACKUP_TIME_FILE;
std::ofstream timeFile(fileName);
if (not timeFile.good()) {
sif::error << "CoreController::timeFileHandler: Error opening time file: " << strerror(errno)
<< std::endl;
return returnvalue::FAILED;
}
- timeFile << "UNIX SECONDS: " << currentTime.tv_sec << std::endl;
+ timeFile << "UNIX SECONDS: " << currentTime.tv_sec + BOOT_OFFSET_SECONDS << std::endl;
}
return returnvalue::OK;
}
@@ -1738,8 +1742,8 @@ ReturnValue_t CoreController::timeFileHandler() {
ReturnValue_t CoreController::initClockFromTimeFile() {
using namespace GpsHyperion;
using namespace std;
- std::string fileName = currMntPrefix + TIME_FILE;
- if (std::filesystem::exists(fileName) and
+ std::string fileName = currMntPrefix + BACKUP_TIME_FILE;
+ if (sdcMan->isSdCardUsable(std::nullopt) and std::filesystem::exists(fileName) and
((gpsFix == FixMode::UNKNOWN or gpsFix == FixMode::NOT_SEEN) or
not utility::timeSanityCheck())) {
ifstream timeFile(fileName);
@@ -1767,6 +1771,7 @@ ReturnValue_t CoreController::initClockFromTimeFile() {
sif::info << "Setting system time from time files: " << std::put_time(time, "%c %Z")
<< std::endl;
#endif
+ timeFileInitDone = true;
return Clock::setClock(¤tTime);
}
return returnvalue::OK;
diff --git a/bsp_q7s/core/CoreController.h b/bsp_q7s/core/CoreController.h
index c90e5ee4..b5bc892d 100644
--- a/bsp_q7s/core/CoreController.h
+++ b/bsp_q7s/core/CoreController.h
@@ -58,13 +58,14 @@ class CoreController : public ExtendedControllerBase {
static constexpr char VERSION_FILE_NAME[] = "version.txt";
static constexpr char REBOOT_FILE_NAME[] = "reboot.txt";
- static constexpr char TIME_FILE_NAME[] = "time.txt";
+ static constexpr char TIME_FILE_NAME[] = "time_backup.txt";
const std::string VERSION_FILE =
"/" + std::string(CONF_FOLDER) + "/" + std::string(VERSION_FILE_NAME);
const std::string REBOOT_FILE =
"/" + std::string(CONF_FOLDER) + "/" + std::string(REBOOT_FILE_NAME);
- const std::string TIME_FILE = "/" + std::string(CONF_FOLDER) + "/" + std::string(TIME_FILE_NAME);
+ const std::string BACKUP_TIME_FILE =
+ "/" + std::string(CONF_FOLDER) + "/" + std::string(TIME_FILE_NAME);
static constexpr char CHIP_0_COPY_0_MOUNT_DIR[] = "/tmp/mntupdate-xdi-qspi0-nom-rootfs";
static constexpr char CHIP_0_COPY_1_MOUNT_DIR[] = "/tmp/mntupdate-xdi-qspi0-gold-rootfs";
@@ -160,6 +161,7 @@ class CoreController : public ExtendedControllerBase {
bool sdInitFinished() const;
private:
+ static constexpr uint32_t BOOT_OFFSET_SECONDS = 15;
static constexpr MutexIF::TimeoutType TIMEOUT_TYPE = MutexIF::TimeoutType::WAITING;
static constexpr uint32_t MUTEX_TIMEOUT = 20;
GpsHyperion::FixMode gpsFix = GpsHyperion::FixMode::UNKNOWN;
@@ -218,6 +220,7 @@ class CoreController : public ExtendedControllerBase {
RebootFile rebootFile = {};
std::string currMntPrefix;
+ bool timeFileInitDone = false;
bool performOneShotSdCardOpsSwitch = false;
uint8_t shortSdCardCdCounter = 0;
#if OBSW_THREAD_TRACING == 1
@@ -255,7 +258,7 @@ class CoreController : public ExtendedControllerBase {
ReturnValue_t initClockFromTimeFile();
ReturnValue_t performSdCardCheck();
- ReturnValue_t timeFileHandler();
+ ReturnValue_t backupTimeFileHandler();
ReturnValue_t initBootCopyFile();
ReturnValue_t initSdCardBlocking();
bool startSdStateMachine(sd::SdCard targetActiveSd, SdCfgMode mode, MessageQueueId_t commander,
diff --git a/bsp_q7s/core/scheduling.cpp b/bsp_q7s/core/scheduling.cpp
index 6dc7fceb..7647af8b 100644
--- a/bsp_q7s/core/scheduling.cpp
+++ b/bsp_q7s/core/scheduling.cpp
@@ -187,14 +187,12 @@ void scheduling::initTasks() {
}
#endif
-#if OBSW_ADD_GPS_CTRL == 1
PeriodicTaskIF* gpsTask = factory->createPeriodicTask(
"GPS_TASK", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE * 2, 0.4, missedDeadlineFunc);
result = gpsTask->addComponent(objects::GPS_CONTROLLER);
if (result != returnvalue::OK) {
scheduling::printAddObjectError("GPS_CTRL", objects::GPS_CONTROLLER);
}
-#endif /* OBSW_ADD_GPS_CTRL */
#if OBSW_ADD_RW == 1
PeriodicTaskIF* rwPolling = factory->createPeriodicTask(
@@ -378,9 +376,7 @@ void scheduling::initTasks() {
#if OBSW_ADD_RW == 1
rwPolling->startTask();
#endif
-#if OBSW_ADD_GPS_CTRL == 1
gpsTask->startTask();
-#endif
acsSysTask->startTask();
if (not tcsSystemTask->isEmpty()) {
tcsSystemTask->startTask();
diff --git a/bsp_q7s/em/emObjectFactory.cpp b/bsp_q7s/em/emObjectFactory.cpp
index 1ab86196..8364533a 100644
--- a/bsp_q7s/em/emObjectFactory.cpp
+++ b/bsp_q7s/em/emObjectFactory.cpp
@@ -3,6 +3,7 @@
#include
#include
#include
+#include
#include "OBSWConfig.h"
#include "bsp_q7s/core/CoreController.h"
@@ -22,7 +23,8 @@ void ObjectFactory::produce(void* args) {
HealthTableIF* healthTable = nullptr;
PusTmFunnel* pusFunnel = nullptr;
CfdpTmFunnel* cfdpFunnel = nullptr;
- ObjectFactory::produceGenericObjects(&healthTable, &pusFunnel, &cfdpFunnel);
+ ObjectFactory::produceGenericObjects(&healthTable, &pusFunnel, &cfdpFunnel,
+ *SdCardManager::instance());
LinuxLibgpioIF* gpioComIF = nullptr;
SerialComIF* uartComIF = nullptr;
diff --git a/bsp_q7s/fmObjectFactory.cpp b/bsp_q7s/fmObjectFactory.cpp
index d640ac35..36e9df64 100644
--- a/bsp_q7s/fmObjectFactory.cpp
+++ b/bsp_q7s/fmObjectFactory.cpp
@@ -18,7 +18,8 @@ void ObjectFactory::produce(void* args) {
HealthTableIF* healthTable = nullptr;
PusTmFunnel* pusFunnel = nullptr;
CfdpTmFunnel* cfdpFunnel = nullptr;
- ObjectFactory::produceGenericObjects(&healthTable, &pusFunnel, &cfdpFunnel);
+ ObjectFactory::produceGenericObjects(&healthTable, &pusFunnel, &cfdpFunnel,
+ *SdCardManager::instance());
LinuxLibgpioIF* gpioComIF = nullptr;
SerialComIF* uartComIF = nullptr;
diff --git a/bsp_q7s/fs/SdCardManager.cpp b/bsp_q7s/fs/SdCardManager.cpp
index c0b1184e..9e5d05bc 100644
--- a/bsp_q7s/fs/SdCardManager.cpp
+++ b/bsp_q7s/fs/SdCardManager.cpp
@@ -410,9 +410,12 @@ ReturnValue_t SdCardManager::updateSdCardStateFile() {
return result;
}
-const std::string& SdCardManager::getCurrentMountPrefix() const {
+const char* SdCardManager::getCurrentMountPrefix() const {
MutexGuard mg(mutex);
- return currentPrefix;
+ if (currentPrefix.has_value()) {
+ return currentPrefix.value().c_str();
+ }
+ return nullptr;
}
SdCardManager::OpStatus SdCardManager::checkCurrentOp(Operations& currentOp) {
diff --git a/bsp_q7s/fs/SdCardManager.h b/bsp_q7s/fs/SdCardManager.h
index 749cae62..77055589 100644
--- a/bsp_q7s/fs/SdCardManager.h
+++ b/bsp_q7s/fs/SdCardManager.h
@@ -187,7 +187,7 @@ class SdCardManager : public SystemObject, public SdCardMountedIF {
* @param prefSdCardPtr
* @return
*/
- const std::string& getCurrentMountPrefix() const override;
+ const char* getCurrentMountPrefix() const override;
OpStatus checkCurrentOp(Operations& currentOp);
@@ -232,7 +232,7 @@ class SdCardManager : public SystemObject, public SdCardMountedIF {
void processSdStatusLine(SdStatePair& active, std::string& line, uint8_t& idx,
sd::SdCard& currentSd);
- std::string currentPrefix;
+ std::optional currentPrefix;
static SdCardManager* INSTANCE;
};
diff --git a/bsp_q7s/fs/helpers.cpp b/bsp_q7s/fs/helpers.cpp
index f1f31eba..19c2f67e 100644
--- a/bsp_q7s/fs/helpers.cpp
+++ b/bsp_q7s/fs/helpers.cpp
@@ -3,6 +3,9 @@
std::filesystem::path fshelpers::getPrefixedPath(SdCardManager &man,
std::filesystem::path pathWihtoutPrefix) {
auto prefix = man.getCurrentMountPrefix();
+ if (prefix == nullptr) {
+ return pathWihtoutPrefix;
+ }
auto resPath = prefix / pathWihtoutPrefix;
return resPath;
}
diff --git a/common/config/eive/definitions.h b/common/config/eive/definitions.h
index edeb3765..4f2c948e 100644
--- a/common/config/eive/definitions.h
+++ b/common/config/eive/definitions.h
@@ -61,8 +61,8 @@ static constexpr uint32_t SCHED_BLOCK_1_SUS_READ_MS = 15;
static constexpr uint32_t SCHED_BLOCK_2_SENSOR_READ_MS = 30;
static constexpr uint32_t SCHED_BLOCK_3_READ_IMTQ_MGM_MS = 42;
static constexpr uint32_t SCHED_BLOCK_4_ACS_CTRL_MS = 45;
-static constexpr uint32_t SCHED_BLOCK_5_ACTUATOR_MS = 50;
-static constexpr uint32_t SCHED_BLOCK_6_IMTQ_BLOCK_2_MS = 90;
+static constexpr uint32_t SCHED_BLOCK_5_ACTUATOR_MS = 55;
+static constexpr uint32_t SCHED_BLOCK_6_IMTQ_BLOCK_2_MS = 95;
static constexpr uint32_t SCHED_BLOCK_RTD = 150;
static constexpr uint32_t SCHED_BLOCK_7_RW_READ_MS = 300;
diff --git a/common/config/eive/eventSubsystemIds.h b/common/config/eive/eventSubsystemIds.h
index 32397f9f..eb270acb 100644
--- a/common/config/eive/eventSubsystemIds.h
+++ b/common/config/eive/eventSubsystemIds.h
@@ -36,7 +36,8 @@ enum : uint8_t {
SCEX_HANDLER = 138,
CONFIGHANDLER = 139,
CORE = 140,
- TCS_CONTROLLER = 141,
+ PERSISTENT_TM_STORE = 141,
+ TCS_CONTROLLER = 142,
COMMON_SUBSYSTEM_ID_END
};
diff --git a/common/config/eive/objects.h b/common/config/eive/objects.h
index 105c78cc..08f07d3d 100644
--- a/common/config/eive/objects.h
+++ b/common/config/eive/objects.h
@@ -152,6 +152,11 @@ enum commonObjects : uint32_t {
CFDP_TM_FUNNEL = 0x73000102,
CFDP_HANDLER = 0x73000205,
CFDP_DISTRIBUTOR = 0x73000206,
+ MISC_TM_STORE = 0x73020001,
+ OK_TM_STORE = 0x73020002,
+ NOT_OK_TM_STORE = 0x73020003,
+ HK_TM_STORE = 0x73020004,
+ CFDP_TM_STORE = 0x73030000,
// Other stuff
THERMAL_TEMP_INSERTER = 0x90000003,
diff --git a/common/config/eive/resultClassIds.h b/common/config/eive/resultClassIds.h
index e4dfb927..310d9e0b 100644
--- a/common/config/eive/resultClassIds.h
+++ b/common/config/eive/resultClassIds.h
@@ -35,14 +35,13 @@ enum commonClassIds : uint8_t {
SA_DEPL_HANDLER, // SADPL
MPSOC_RETURN_VALUES_IF, // MPSOCRTVIF
SUPV_RETURN_VALUES_IF, // SPVRTVIF
- ACS_KALMAN, // ACSKAL
+ ACS_CTRL, // ACSCTRL
+ ACS_MEKF, // ACSMEKF
ACS_SAFE, // ACSSAF
ACS_PTG, // ACSPTG
ACS_DETUMBLE, // ACSDTB
- ACS_MEKF, // ACSMEK
COMMON_CLASS_ID_END // [EXPORT] : [END]
};
-
}
#endif /* COMMON_CONFIG_COMMONCLASSIDS_H_ */
diff --git a/common/config/tmtc/pusIds.h b/common/config/tmtc/pusIds.h
index 0891992d..b44d7e20 100644
--- a/common/config/tmtc/pusIds.h
+++ b/common/config/tmtc/pusIds.h
@@ -12,6 +12,7 @@ enum Ids {
PUS_SERVICE_8 = 8,
PUS_SERVICE_9 = 9,
PUS_SERVICE_11 = 11,
+ PUS_SERVICE_15 = 15,
PUS_SERVICE_17 = 17,
PUS_SERVICE_19 = 19,
PUS_SERVICE_20 = 20,
diff --git a/dummies/CMakeLists.txt b/dummies/CMakeLists.txt
index 810cc048..41cb3328 100644
--- a/dummies/CMakeLists.txt
+++ b/dummies/CMakeLists.txt
@@ -20,6 +20,7 @@ target_sources(
GyroL3GD20Dummy.cpp
MgmLIS3MDLDummy.cpp
PlPcduDummy.cpp
+ ExecutableComIfDummy.cpp
ScexDummy.cpp
CoreControllerDummy.cpp
PlocMpsocDummy.cpp
diff --git a/dummies/ExecutableComIfDummy.cpp b/dummies/ExecutableComIfDummy.cpp
new file mode 100644
index 00000000..becb4a73
--- /dev/null
+++ b/dummies/ExecutableComIfDummy.cpp
@@ -0,0 +1,27 @@
+#include
+
+ExecutableComIfDummy::ExecutableComIfDummy(object_id_t objectId) : SystemObject(objectId) {}
+
+ReturnValue_t ExecutableComIfDummy::initializeInterface(CookieIF *cookie) {
+ return returnvalue::OK;
+}
+
+ReturnValue_t ExecutableComIfDummy::sendMessage(CookieIF *cookie, const uint8_t *sendData,
+ size_t sendLen) {
+ return returnvalue::OK;
+}
+
+ReturnValue_t ExecutableComIfDummy::getSendSuccess(CookieIF *cookie) { return returnvalue::OK; }
+
+ReturnValue_t ExecutableComIfDummy::requestReceiveMessage(CookieIF *cookie, size_t requestLen) {
+ return returnvalue::OK;
+}
+
+ReturnValue_t ExecutableComIfDummy::performOperation(uint8_t operationCode) {
+ return returnvalue::OK;
+}
+
+ReturnValue_t ExecutableComIfDummy::readReceivedMessage(CookieIF *cookie, uint8_t **buffer,
+ size_t *size) {
+ return returnvalue::OK;
+}
diff --git a/dummies/ExecutableComIfDummy.h b/dummies/ExecutableComIfDummy.h
new file mode 100644
index 00000000..80e667d7
--- /dev/null
+++ b/dummies/ExecutableComIfDummy.h
@@ -0,0 +1,21 @@
+#ifndef DUMMIES_EXECUTABLECOMIFDUMMY_H_
+#define DUMMIES_EXECUTABLECOMIFDUMMY_H_
+
+#include
+#include
+#include
+
+class ExecutableComIfDummy : public ExecutableObjectIF,
+ public DeviceCommunicationIF,
+ public SystemObject {
+ public:
+ ExecutableComIfDummy(object_id_t objectId);
+ ReturnValue_t performOperation(uint8_t operationCode = 0) override;
+ ReturnValue_t initializeInterface(CookieIF *cookie) override;
+ ReturnValue_t sendMessage(CookieIF *cookie, const uint8_t *sendData, size_t sendLen) override;
+ ReturnValue_t getSendSuccess(CookieIF *cookie) override;
+ ReturnValue_t requestReceiveMessage(CookieIF *cookie, size_t requestLen) override;
+ ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) override;
+};
+
+#endif /* DUMMIES_EXECUTABLECOMIFDUMMY_H_ */
diff --git a/dummies/GpsCtrlDummy.cpp b/dummies/GpsCtrlDummy.cpp
index e69261b4..4ae8dc6f 100644
--- a/dummies/GpsCtrlDummy.cpp
+++ b/dummies/GpsCtrlDummy.cpp
@@ -1,6 +1,7 @@
#include "GpsCtrlDummy.h"
-GpsCtrlDummy::GpsCtrlDummy(object_id_t objectId) : ExtendedControllerBase(objectId, 20) {}
+GpsCtrlDummy::GpsCtrlDummy(object_id_t objectId)
+ : ExtendedControllerBase(objectId, 20), gpsSet(this) {}
ReturnValue_t GpsCtrlDummy::handleCommandMessage(CommandMessage* message) {
return returnvalue::OK;
@@ -13,9 +14,23 @@ ReturnValue_t GpsCtrlDummy::checkModeCommand(Mode_t mode, Submode_t submode,
return returnvalue::OK;
}
+LocalPoolDataSetBase* GpsCtrlDummy::getDataSetHandle(sid_t sid) { return &gpsSet; }
+
ReturnValue_t GpsCtrlDummy::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) {
+ localDataPoolMap.emplace(GpsHyperion::ALTITUDE, new PoolEntry({537222.3469}, true));
+ localDataPoolMap.emplace(GpsHyperion::LONGITUDE, new PoolEntry({-8.8579}, true));
+ localDataPoolMap.emplace(GpsHyperion::LATITUDE, new PoolEntry({49.5952}, true));
+ localDataPoolMap.emplace(GpsHyperion::SPEED, new PoolEntry({0}));
+ localDataPoolMap.emplace(GpsHyperion::YEAR, new PoolEntry({2023}, true));
+ localDataPoolMap.emplace(GpsHyperion::MONTH, new PoolEntry({5}, true));
+ localDataPoolMap.emplace(GpsHyperion::DAY, new PoolEntry({16}, true));
+ localDataPoolMap.emplace(GpsHyperion::HOURS, new PoolEntry({1}, true));
+ localDataPoolMap.emplace(GpsHyperion::MINUTES, new PoolEntry({0}, true));
+ localDataPoolMap.emplace(GpsHyperion::SECONDS, new PoolEntry({0}, true));
+ localDataPoolMap.emplace(GpsHyperion::UNIX_SECONDS, new PoolEntry({1684191600}, true));
+ localDataPoolMap.emplace(GpsHyperion::SATS_IN_USE, new PoolEntry());
+ localDataPoolMap.emplace(GpsHyperion::SATS_IN_VIEW, new PoolEntry());
+ localDataPoolMap.emplace(GpsHyperion::FIX_MODE, new PoolEntry());
return returnvalue::OK;
}
-
-LocalPoolDataSetBase* GpsCtrlDummy::getDataSetHandle(sid_t sid) { return nullptr; }
diff --git a/dummies/GpsCtrlDummy.h b/dummies/GpsCtrlDummy.h
index 128a9a85..4b7fc1bf 100644
--- a/dummies/GpsCtrlDummy.h
+++ b/dummies/GpsCtrlDummy.h
@@ -2,12 +2,15 @@
#define DUMMIES_GPSCTRLDUMMY_H_
#include
+#include
class GpsCtrlDummy : public ExtendedControllerBase {
public:
GpsCtrlDummy(object_id_t objectId);
private:
+ GpsPrimaryDataset gpsSet;
+
ReturnValue_t handleCommandMessage(CommandMessage* message) override;
void performControlOperation() override;
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
diff --git a/dummies/PduDummy.cpp b/dummies/PduDummy.cpp
index 1c26728c..42147222 100644
--- a/dummies/PduDummy.cpp
+++ b/dummies/PduDummy.cpp
@@ -3,7 +3,8 @@
#include
PduDummy::PduDummy(object_id_t objectId, object_id_t comif, CookieIF *comCookie)
- : DeviceHandlerBase(objectId, comif, comCookie) {}
+ : DeviceHandlerBase(objectId, comif, comCookie),
+ coreHk(this, static_cast(P60System::SetIds::CORE)) {}
PduDummy::~PduDummy() {}
@@ -38,5 +39,7 @@ uint32_t PduDummy::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) { return
ReturnValue_t PduDummy::initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
LocalDataPoolManager &poolManager) {
localDataPoolMap.emplace(PDU::pool::PDU_TEMPERATURE, new PoolEntry({0}));
+ localDataPoolMap.emplace(PDU::pool::PDU_VOLTAGES, &pduVoltages);
+ localDataPoolMap.emplace(PDU::pool::PDU_CURRENTS, &pduCurrents);
return returnvalue::OK;
}
diff --git a/dummies/PduDummy.h b/dummies/PduDummy.h
index 3e193e7c..751896cd 100644
--- a/dummies/PduDummy.h
+++ b/dummies/PduDummy.h
@@ -3,6 +3,8 @@
#include
+#include "mission/devices/devicedefinitions/GomspaceDefinitions.h"
+
class PduDummy : public DeviceHandlerBase {
public:
static const DeviceCommandId_t SIMPLE_COMMAND = 1;
@@ -15,6 +17,10 @@ class PduDummy : public DeviceHandlerBase {
virtual ~PduDummy();
protected:
+ PDU::PduCoreHk coreHk;
+ PoolEntry pduVoltages = PoolEntry(9);
+ PoolEntry pduCurrents = PoolEntry(9);
+
void doStartUp() override;
void doShutDown() override;
ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t *id) override;
diff --git a/dummies/RwDummy.cpp b/dummies/RwDummy.cpp
index 54e7ac83..d90f3f7c 100644
--- a/dummies/RwDummy.cpp
+++ b/dummies/RwDummy.cpp
@@ -41,7 +41,7 @@ ReturnValue_t RwDummy::initializeLocalDataPool(localpool::DataPool &localDataPoo
localDataPoolMap.emplace(rws::CURR_SPEED, new PoolEntry({0}));
localDataPoolMap.emplace(rws::REFERENCE_SPEED, new PoolEntry({0}));
- localDataPoolMap.emplace(rws::STATE, new PoolEntry({0}));
+ localDataPoolMap.emplace(rws::STATE, new PoolEntry({1}, true));
localDataPoolMap.emplace(rws::CLC_MODE, new PoolEntry({0}));
localDataPoolMap.emplace(rws::LAST_RESET_STATUS, new PoolEntry({0}));
diff --git a/dummies/SusDummy.cpp b/dummies/SusDummy.cpp
index c0aed6dd..7c271b21 100644
--- a/dummies/SusDummy.cpp
+++ b/dummies/SusDummy.cpp
@@ -37,7 +37,7 @@ ReturnValue_t SusDummy::initializeLocalDataPool(localpool::DataPool &localDataPo
LocalDataPoolManager &poolManager) {
localDataPoolMap.emplace(SUS::SusPoolIds::TEMPERATURE_C, new PoolEntry({0}, 1, true));
localDataPoolMap.emplace(SUS::SusPoolIds::CHANNEL_VEC,
- new PoolEntry({0, 0, 0, 0, 0, 0}, true));
+ new PoolEntry({2603, 781, 2760, 2048, 4056, 0}, true));
return returnvalue::OK;
}
diff --git a/dummies/helpers.cpp b/dummies/helpers.cpp
index a5b84451..f93a8127 100644
--- a/dummies/helpers.cpp
+++ b/dummies/helpers.cpp
@@ -5,6 +5,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -45,7 +46,7 @@ void dummy::createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitcher, GpioIF* gpio
new CoreControllerDummy(objects::CORE_CONTROLLER);
}
if (cfg.addRtdComIFDummy) {
- new ComIFDummy(objects::SPI_RTD_COM_IF);
+ new ExecutableComIfDummy(objects::SPI_RTD_COM_IF);
}
std::array rwIds = {objects::RW1, objects::RW2, objects::RW3, objects::RW4};
std::array rws;
diff --git a/fsfw b/fsfw
index bd208038..bdfe31db 160000
--- a/fsfw
+++ b/fsfw
@@ -1 +1 @@
-Subproject commit bd208038dd85a94dce8c763397ad5ac7eae76402
+Subproject commit bdfe31dba48039b60fe700e7d03bfb95e9549688
diff --git a/generators/.gitignore b/generators/.gitignore
index 889fd273..c5e80e62 100644
--- a/generators/.gitignore
+++ b/generators/.gitignore
@@ -1,2 +1,4 @@
.~lock*
/venv
+/.idea/*
+!/.idea/runConfigurations
diff --git a/generators/bsp_hosted_events.csv b/generators/bsp_hosted_events.csv
index 4542daa6..6d26ed51 100644
--- a/generators/bsp_hosted_events.csv
+++ b/generators/bsp_hosted_events.csv
@@ -84,6 +84,8 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path
10800;0x2a30;STORE_ERROR;LOW;No description;fsfw/src/fsfw/cfdp/handler/defs.h
10801;0x2a31;MSG_QUEUE_ERROR;LOW;No description;fsfw/src/fsfw/cfdp/handler/defs.h
10802;0x2a32;SERIALIZATION_ERROR;LOW;No description;fsfw/src/fsfw/cfdp/handler/defs.h
+10803;0x2a33;FILESTORE_ERROR;LOW;No description;fsfw/src/fsfw/cfdp/handler/defs.h
+10804;0x2a34;FILENAME_TOO_LARGE_ERROR;LOW;P1: Transaction step ID, P2: 0 for source file name, 1 for dest file name;fsfw/src/fsfw/cfdp/handler/defs.h
11200;0x2bc0;SAFE_RATE_VIOLATION;MEDIUM;No description;mission/acsDefs.h
11201;0x2bc1;SAFE_RATE_RECOVERY;MEDIUM;No description;mission/acsDefs.h
11202;0x2bc2;MULTIPLE_RW_INVALID;HIGH;No description;mission/acsDefs.h
@@ -252,10 +254,11 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path
14004;0x36b4;NO_SD_CARD_ACTIVE;HIGH;No SD card was active. Core controller will attempt to re-initialize a SD card.;bsp_q7s/core/CoreController.h
14005;0x36b5;VERSION_INFO;INFO;P1: Byte 0: Major, Byte 1: Minor, Byte 2: Patch, Byte 3: Has Git Hash P2: First four letters of Git SHA is the last byte of P1 is set.;bsp_q7s/core/CoreController.h
14006;0x36b6;CURRENT_IMAGE_INFO;INFO;P1: Current Chip, P2: Current Copy;bsp_q7s/core/CoreController.h
-14100;0x3714;NO_VALID_SENSOR_TEMPERATURE;MEDIUM;No description;mission/controller/ThermalController.h
-14101;0x3715;NO_HEALTHY_HEATER_AVAILABLE;MEDIUM;No description;mission/controller/ThermalController.h
-14102;0x3716;SYRLINKS_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
-14103;0x3717;PLOC_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
-14104;0x3718;OBC_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
-14105;0x3719;HPA_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
-14106;0x371a;PLPCDU_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
+14100;0x3714;POSSIBLE_FILE_CORRUPTION;LOW;P1: Result code of TM packet parser. P2: Timestamp of possibly corrupt file as a unix timestamp.;mission/tmtc/PersistentTmStore.h
+14200;0x3778;NO_VALID_SENSOR_TEMPERATURE;MEDIUM;No description;mission/controller/ThermalController.h
+14201;0x3779;NO_HEALTHY_HEATER_AVAILABLE;MEDIUM;No description;mission/controller/ThermalController.h
+14202;0x377a;SYRLINKS_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
+14203;0x377b;PLOC_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
+14204;0x377c;OBC_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
+14205;0x377d;HPA_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
+14206;0x377e;PLPCDU_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
diff --git a/generators/bsp_hosted_objects.csv b/generators/bsp_hosted_objects.csv
index d4c5ca74..f6c11782 100644
--- a/generators/bsp_hosted_objects.csv
+++ b/generators/bsp_hosted_objects.csv
@@ -104,6 +104,7 @@
0x53000008;PUS_SERVICE_8_FUNCTION_MGMT
0x53000009;PUS_SERVICE_9_TIME_MGMT
0x53000011;PUS_SERVICE_11_TC_SCHEDULER
+0x53000015;PUS_SERVICE_15_TM_STORAGE
0x53000017;PUS_SERVICE_17_TEST
0x53000020;PUS_SERVICE_20_PARAMETERS
0x53000200;PUS_SERVICE_200_MODE_MGMT
@@ -142,6 +143,11 @@
0x73010002;PL_SUBSYSTEM
0x73010003;TCS_SUBSYSTEM
0x73010004;COM_SUBSYSTEM
+0x73020001;MISC_TM_STORE
+0x73020002;OK_TM_STORE
+0x73020003;NOT_OK_TM_STORE
+0x73020004;HK_TM_STORE
+0x73030000;CFDP_TM_STORE
0x73500000;CCSDS_IP_CORE_BRIDGE
0x90000003;THERMAL_TEMP_INSERTER
0xCAFECAFE;DUMMY_INTERFACE
diff --git a/generators/bsp_hosted_returnvalues.csv b/generators/bsp_hosted_returnvalues.csv
index 4c6d37e8..86c3f699 100644
--- a/generators/bsp_hosted_returnvalues.csv
+++ b/generators/bsp_hosted_returnvalues.csv
@@ -49,16 +49,17 @@ Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path
0x4fa4;HEATER_MainSwitchSetTimeout;No description;164;HEATER_HANDLER;mission/devices/HeaterHandler.h
0x4fa5;HEATER_CommandAlreadyWaiting;No description;165;HEATER_HANDLER;mission/devices/HeaterHandler.h
0x60a0;CCSDS_CommandNotImplemented;Received action message with unknown action id;160;CCSDS_HANDLER;mission/tmtc/CcsdsIpCoreHandler.h
-0x6a01;ACSSAF_SafectrlMekfInputInvalid;No description;1;ACS_SAFE;mission/controller/acs/control/SafeCtrl.h
-0x6b01;ACSPTG_PtgctrlMekfInputInvalid;No description;1;ACS_PTG;mission/controller/acs/control/PtgCtrl.h
-0x6c01;ACSDTB_DetumbleNoSensordata;No description;1;ACS_DETUMBLE;mission/controller/acs/control/Detumble.h
-0x6902;ACSKAL_KalmanUninitialized;No description;2;ACS_KALMAN;mission/controller/acs/MultiplicativeKalmanFilter.h
-0x6903;ACSKAL_KalmanNoGyrData;No description;3;ACS_KALMAN;mission/controller/acs/MultiplicativeKalmanFilter.h
-0x6904;ACSKAL_KalmanNoModelVectors;No description;4;ACS_KALMAN;mission/controller/acs/MultiplicativeKalmanFilter.h
-0x6905;ACSKAL_KalmanNoSusMgmStrData;No description;5;ACS_KALMAN;mission/controller/acs/MultiplicativeKalmanFilter.h
-0x6906;ACSKAL_KalmanCovarianceInversionFailed;No description;6;ACS_KALMAN;mission/controller/acs/MultiplicativeKalmanFilter.h
-0x6907;ACSKAL_KalmanInitialized;No description;7;ACS_KALMAN;mission/controller/acs/MultiplicativeKalmanFilter.h
-0x6908;ACSKAL_KalmanRunning;No description;8;ACS_KALMAN;mission/controller/acs/MultiplicativeKalmanFilter.h
+0x6b01;ACSSAF_SafectrlMekfInputInvalid;No description;1;ACS_SAFE;mission/controller/acs/control/SafeCtrl.h
+0x6c01;ACSPTG_PtgctrlMekfInputInvalid;No description;1;ACS_PTG;mission/controller/acs/control/PtgCtrl.h
+0x6d01;ACSDTB_DetumbleNoSensordata;No description;1;ACS_DETUMBLE;mission/controller/acs/control/Detumble.h
+0x6a02;ACSMEKF_MekfUninitialized;No description;2;ACS_MEKF;mission/controller/acs/MultiplicativeKalmanFilter.h
+0x6a03;ACSMEKF_MekfNoGyrData;No description;3;ACS_MEKF;mission/controller/acs/MultiplicativeKalmanFilter.h
+0x6a04;ACSMEKF_MekfNoModelVectors;No description;4;ACS_MEKF;mission/controller/acs/MultiplicativeKalmanFilter.h
+0x6a05;ACSMEKF_MekfNoSusMgmStrData;No description;5;ACS_MEKF;mission/controller/acs/MultiplicativeKalmanFilter.h
+0x6a06;ACSMEKF_MekfCovarianceInversionFailed;No description;6;ACS_MEKF;mission/controller/acs/MultiplicativeKalmanFilter.h
+0x6a07;ACSMEKF_MekfInitialized;No description;7;ACS_MEKF;mission/controller/acs/MultiplicativeKalmanFilter.h
+0x6a08;ACSMEKF_MekfRunning;No description;8;ACS_MEKF;mission/controller/acs/MultiplicativeKalmanFilter.h
+0x6900;ACSCTRL_FileDeletionFailed;No description;0;ACS_CTRL;mission/controller/AcsController.h
0x4500;HSPI_OpeningFileFailed;No description;0;HAL_SPI;fsfw/src/fsfw_hal/linux/spi/SpiComIF.h
0x4501;HSPI_FullDuplexTransferFailed;No description;1;HAL_SPI;fsfw/src/fsfw_hal/linux/spi/SpiComIF.h
0x4502;HSPI_HalfDuplexTransferFailed;No description;2;HAL_SPI;fsfw/src/fsfw_hal/linux/spi/SpiComIF.h
diff --git a/generators/bsp_q7s_events.csv b/generators/bsp_q7s_events.csv
index 4542daa6..6d26ed51 100644
--- a/generators/bsp_q7s_events.csv
+++ b/generators/bsp_q7s_events.csv
@@ -84,6 +84,8 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path
10800;0x2a30;STORE_ERROR;LOW;No description;fsfw/src/fsfw/cfdp/handler/defs.h
10801;0x2a31;MSG_QUEUE_ERROR;LOW;No description;fsfw/src/fsfw/cfdp/handler/defs.h
10802;0x2a32;SERIALIZATION_ERROR;LOW;No description;fsfw/src/fsfw/cfdp/handler/defs.h
+10803;0x2a33;FILESTORE_ERROR;LOW;No description;fsfw/src/fsfw/cfdp/handler/defs.h
+10804;0x2a34;FILENAME_TOO_LARGE_ERROR;LOW;P1: Transaction step ID, P2: 0 for source file name, 1 for dest file name;fsfw/src/fsfw/cfdp/handler/defs.h
11200;0x2bc0;SAFE_RATE_VIOLATION;MEDIUM;No description;mission/acsDefs.h
11201;0x2bc1;SAFE_RATE_RECOVERY;MEDIUM;No description;mission/acsDefs.h
11202;0x2bc2;MULTIPLE_RW_INVALID;HIGH;No description;mission/acsDefs.h
@@ -252,10 +254,11 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path
14004;0x36b4;NO_SD_CARD_ACTIVE;HIGH;No SD card was active. Core controller will attempt to re-initialize a SD card.;bsp_q7s/core/CoreController.h
14005;0x36b5;VERSION_INFO;INFO;P1: Byte 0: Major, Byte 1: Minor, Byte 2: Patch, Byte 3: Has Git Hash P2: First four letters of Git SHA is the last byte of P1 is set.;bsp_q7s/core/CoreController.h
14006;0x36b6;CURRENT_IMAGE_INFO;INFO;P1: Current Chip, P2: Current Copy;bsp_q7s/core/CoreController.h
-14100;0x3714;NO_VALID_SENSOR_TEMPERATURE;MEDIUM;No description;mission/controller/ThermalController.h
-14101;0x3715;NO_HEALTHY_HEATER_AVAILABLE;MEDIUM;No description;mission/controller/ThermalController.h
-14102;0x3716;SYRLINKS_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
-14103;0x3717;PLOC_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
-14104;0x3718;OBC_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
-14105;0x3719;HPA_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
-14106;0x371a;PLPCDU_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
+14100;0x3714;POSSIBLE_FILE_CORRUPTION;LOW;P1: Result code of TM packet parser. P2: Timestamp of possibly corrupt file as a unix timestamp.;mission/tmtc/PersistentTmStore.h
+14200;0x3778;NO_VALID_SENSOR_TEMPERATURE;MEDIUM;No description;mission/controller/ThermalController.h
+14201;0x3779;NO_HEALTHY_HEATER_AVAILABLE;MEDIUM;No description;mission/controller/ThermalController.h
+14202;0x377a;SYRLINKS_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
+14203;0x377b;PLOC_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
+14204;0x377c;OBC_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
+14205;0x377d;HPA_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
+14206;0x377e;PLPCDU_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
diff --git a/generators/bsp_q7s_objects.csv b/generators/bsp_q7s_objects.csv
index 91e3a505..2bc03e8f 100644
--- a/generators/bsp_q7s_objects.csv
+++ b/generators/bsp_q7s_objects.csv
@@ -102,6 +102,7 @@
0x53000008;PUS_SERVICE_8_FUNCTION_MGMT
0x53000009;PUS_SERVICE_9_TIME_MGMT
0x53000011;PUS_SERVICE_11_TC_SCHEDULER
+0x53000015;PUS_SERVICE_15_TM_STORAGE
0x53000017;PUS_SERVICE_17_TEST
0x53000020;PUS_SERVICE_20_PARAMETERS
0x53000200;PUS_SERVICE_200_MODE_MGMT
@@ -148,6 +149,11 @@
0x73010002;PL_SUBSYSTEM
0x73010003;TCS_SUBSYSTEM
0x73010004;COM_SUBSYSTEM
+0x73020001;MISC_TM_STORE
+0x73020002;OK_TM_STORE
+0x73020003;NOT_OK_TM_STORE
+0x73020004;HK_TM_STORE
+0x73030000;CFDP_TM_STORE
0x73500000;CCSDS_IP_CORE_BRIDGE
0x90000003;THERMAL_TEMP_INSERTER
0xFFFFFFFF;NO_OBJECT
diff --git a/generators/bsp_q7s_returnvalues.csv b/generators/bsp_q7s_returnvalues.csv
index 6f215a94..4abc2ff7 100644
--- a/generators/bsp_q7s_returnvalues.csv
+++ b/generators/bsp_q7s_returnvalues.csv
@@ -49,16 +49,17 @@ Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path
0x4fa4;HEATER_MainSwitchSetTimeout;No description;164;HEATER_HANDLER;mission/devices/HeaterHandler.h
0x4fa5;HEATER_CommandAlreadyWaiting;No description;165;HEATER_HANDLER;mission/devices/HeaterHandler.h
0x60a0;CCSDS_CommandNotImplemented;Received action message with unknown action id;160;CCSDS_HANDLER;mission/tmtc/CcsdsIpCoreHandler.h
-0x6a01;ACSSAF_SafectrlMekfInputInvalid;No description;1;ACS_SAFE;mission/controller/acs/control/SafeCtrl.h
-0x6b01;ACSPTG_PtgctrlMekfInputInvalid;No description;1;ACS_PTG;mission/controller/acs/control/PtgCtrl.h
-0x6c01;ACSDTB_DetumbleNoSensordata;No description;1;ACS_DETUMBLE;mission/controller/acs/control/Detumble.h
-0x6902;ACSKAL_KalmanUninitialized;No description;2;ACS_KALMAN;mission/controller/acs/MultiplicativeKalmanFilter.h
-0x6903;ACSKAL_KalmanNoGyrData;No description;3;ACS_KALMAN;mission/controller/acs/MultiplicativeKalmanFilter.h
-0x6904;ACSKAL_KalmanNoModelVectors;No description;4;ACS_KALMAN;mission/controller/acs/MultiplicativeKalmanFilter.h
-0x6905;ACSKAL_KalmanNoSusMgmStrData;No description;5;ACS_KALMAN;mission/controller/acs/MultiplicativeKalmanFilter.h
-0x6906;ACSKAL_KalmanCovarianceInversionFailed;No description;6;ACS_KALMAN;mission/controller/acs/MultiplicativeKalmanFilter.h
-0x6907;ACSKAL_KalmanInitialized;No description;7;ACS_KALMAN;mission/controller/acs/MultiplicativeKalmanFilter.h
-0x6908;ACSKAL_KalmanRunning;No description;8;ACS_KALMAN;mission/controller/acs/MultiplicativeKalmanFilter.h
+0x6b01;ACSSAF_SafectrlMekfInputInvalid;No description;1;ACS_SAFE;mission/controller/acs/control/SafeCtrl.h
+0x6c01;ACSPTG_PtgctrlMekfInputInvalid;No description;1;ACS_PTG;mission/controller/acs/control/PtgCtrl.h
+0x6d01;ACSDTB_DetumbleNoSensordata;No description;1;ACS_DETUMBLE;mission/controller/acs/control/Detumble.h
+0x6a02;ACSMEKF_MekfUninitialized;No description;2;ACS_MEKF;mission/controller/acs/MultiplicativeKalmanFilter.h
+0x6a03;ACSMEKF_MekfNoGyrData;No description;3;ACS_MEKF;mission/controller/acs/MultiplicativeKalmanFilter.h
+0x6a04;ACSMEKF_MekfNoModelVectors;No description;4;ACS_MEKF;mission/controller/acs/MultiplicativeKalmanFilter.h
+0x6a05;ACSMEKF_MekfNoSusMgmStrData;No description;5;ACS_MEKF;mission/controller/acs/MultiplicativeKalmanFilter.h
+0x6a06;ACSMEKF_MekfCovarianceInversionFailed;No description;6;ACS_MEKF;mission/controller/acs/MultiplicativeKalmanFilter.h
+0x6a07;ACSMEKF_MekfInitialized;No description;7;ACS_MEKF;mission/controller/acs/MultiplicativeKalmanFilter.h
+0x6a08;ACSMEKF_MekfRunning;No description;8;ACS_MEKF;mission/controller/acs/MultiplicativeKalmanFilter.h
+0x6900;ACSCTRL_FileDeletionFailed;No description;0;ACS_CTRL;mission/controller/AcsController.h
0x4500;HSPI_OpeningFileFailed;No description;0;HAL_SPI;fsfw/src/fsfw_hal/linux/spi/SpiComIF.h
0x4501;HSPI_FullDuplexTransferFailed;No description;1;HAL_SPI;fsfw/src/fsfw_hal/linux/spi/SpiComIF.h
0x4502;HSPI_HalfDuplexTransferFailed;No description;2;HAL_SPI;fsfw/src/fsfw_hal/linux/spi/SpiComIF.h
diff --git a/generators/events/translateEvents.cpp b/generators/events/translateEvents.cpp
index e35a31ef..c979ff5e 100644
--- a/generators/events/translateEvents.cpp
+++ b/generators/events/translateEvents.cpp
@@ -1,7 +1,7 @@
/**
- * @brief Auto-generated event translation file. Contains 260 translations.
+ * @brief Auto-generated event translation file. Contains 263 translations.
* @details
- * Generated on: 2023-02-23 15:39:20
+ * Generated on: 2023-02-24 16:57:00
*/
#include "translateEvents.h"
@@ -90,6 +90,8 @@ const char *CHANGE_OF_SETUP_PARAMETER_STRING = "CHANGE_OF_SETUP_PARAMETER";
const char *STORE_ERROR_STRING = "STORE_ERROR";
const char *MSG_QUEUE_ERROR_STRING = "MSG_QUEUE_ERROR";
const char *SERIALIZATION_ERROR_STRING = "SERIALIZATION_ERROR";
+const char *FILESTORE_ERROR_STRING = "FILESTORE_ERROR";
+const char *FILENAME_TOO_LARGE_ERROR_STRING = "FILENAME_TOO_LARGE_ERROR";
const char *SAFE_RATE_VIOLATION_STRING = "SAFE_RATE_VIOLATION";
const char *SAFE_RATE_RECOVERY_STRING = "SAFE_RATE_RECOVERY";
const char *MULTIPLE_RW_INVALID_STRING = "MULTIPLE_RW_INVALID";
@@ -253,6 +255,7 @@ const char *REBOOT_HW_STRING = "REBOOT_HW";
const char *NO_SD_CARD_ACTIVE_STRING = "NO_SD_CARD_ACTIVE";
const char *VERSION_INFO_STRING = "VERSION_INFO";
const char *CURRENT_IMAGE_INFO_STRING = "CURRENT_IMAGE_INFO";
+const char *POSSIBLE_FILE_CORRUPTION_STRING = "POSSIBLE_FILE_CORRUPTION";
const char *NO_VALID_SENSOR_TEMPERATURE_STRING = "NO_VALID_SENSOR_TEMPERATURE";
const char *NO_HEALTHY_HEATER_AVAILABLE_STRING = "NO_HEALTHY_HEATER_AVAILABLE";
const char *SYRLINKS_OVERHEATING_STRING = "SYRLINKS_OVERHEATING";
@@ -433,6 +436,10 @@ const char *translateEvents(Event event) {
return MSG_QUEUE_ERROR_STRING;
case (10802):
return SERIALIZATION_ERROR_STRING;
+ case (10803):
+ return FILESTORE_ERROR_STRING;
+ case (10804):
+ return FILENAME_TOO_LARGE_ERROR_STRING;
case (11200):
return SAFE_RATE_VIOLATION_STRING;
case (11201):
@@ -760,18 +767,20 @@ const char *translateEvents(Event event) {
case (14006):
return CURRENT_IMAGE_INFO_STRING;
case (14100):
+ return POSSIBLE_FILE_CORRUPTION_STRING;
+ case (14200):
return NO_VALID_SENSOR_TEMPERATURE_STRING;
- case (14101):
+ case (14201):
return NO_HEALTHY_HEATER_AVAILABLE_STRING;
- case (14102):
+ case (14202):
return SYRLINKS_OVERHEATING_STRING;
- case (14103):
+ case (14203):
return PLOC_OVERHEATING_STRING;
- case (14104):
+ case (14204):
return OBC_OVERHEATING_STRING;
- case (14105):
+ case (14205):
return HPA_OVERHEATING_STRING;
- case (14106):
+ case (14206):
return PLPCDU_OVERHEATING_STRING;
default:
return "UNKNOWN_EVENT";
diff --git a/generators/objects/translateObjects.cpp b/generators/objects/translateObjects.cpp
index 70bcf3ad..93c4fb0f 100644
--- a/generators/objects/translateObjects.cpp
+++ b/generators/objects/translateObjects.cpp
@@ -1,8 +1,8 @@
/**
* @brief Auto-generated object translation file.
* @details
- * Contains 153 translations.
- * Generated on: 2023-02-23 15:39:20
+ * Contains 159 translations.
+ * Generated on: 2023-02-24 16:57:00
*/
#include "translateObjects.h"
@@ -110,6 +110,7 @@ const char *PUS_SERVICE_5_EVENT_REPORTING_STRING = "PUS_SERVICE_5_EVENT_REPORTIN
const char *PUS_SERVICE_8_FUNCTION_MGMT_STRING = "PUS_SERVICE_8_FUNCTION_MGMT";
const char *PUS_SERVICE_9_TIME_MGMT_STRING = "PUS_SERVICE_9_TIME_MGMT";
const char *PUS_SERVICE_11_TC_SCHEDULER_STRING = "PUS_SERVICE_11_TC_SCHEDULER";
+const char *PUS_SERVICE_15_TM_STORAGE_STRING = "PUS_SERVICE_15_TM_STORAGE";
const char *PUS_SERVICE_17_TEST_STRING = "PUS_SERVICE_17_TEST";
const char *PUS_SERVICE_20_PARAMETERS_STRING = "PUS_SERVICE_20_PARAMETERS";
const char *PUS_SERVICE_200_MODE_MGMT_STRING = "PUS_SERVICE_200_MODE_MGMT";
@@ -156,6 +157,11 @@ const char *ACS_SUBSYSTEM_STRING = "ACS_SUBSYSTEM";
const char *PL_SUBSYSTEM_STRING = "PL_SUBSYSTEM";
const char *TCS_SUBSYSTEM_STRING = "TCS_SUBSYSTEM";
const char *COM_SUBSYSTEM_STRING = "COM_SUBSYSTEM";
+const char *MISC_TM_STORE_STRING = "MISC_TM_STORE";
+const char *OK_TM_STORE_STRING = "OK_TM_STORE";
+const char *NOT_OK_TM_STORE_STRING = "NOT_OK_TM_STORE";
+const char *HK_TM_STORE_STRING = "HK_TM_STORE";
+const char *CFDP_TM_STORE_STRING = "CFDP_TM_STORE";
const char *CCSDS_IP_CORE_BRIDGE_STRING = "CCSDS_IP_CORE_BRIDGE";
const char *THERMAL_TEMP_INSERTER_STRING = "THERMAL_TEMP_INSERTER";
const char *NO_OBJECT_STRING = "NO_OBJECT";
@@ -370,6 +376,8 @@ const char *translateObject(object_id_t object) {
return PUS_SERVICE_9_TIME_MGMT_STRING;
case 0x53000011:
return PUS_SERVICE_11_TC_SCHEDULER_STRING;
+ case 0x53000015:
+ return PUS_SERVICE_15_TM_STORAGE_STRING;
case 0x53000017:
return PUS_SERVICE_17_TEST_STRING;
case 0x53000020:
@@ -462,6 +470,16 @@ const char *translateObject(object_id_t object) {
return TCS_SUBSYSTEM_STRING;
case 0x73010004:
return COM_SUBSYSTEM_STRING;
+ case 0x73020001:
+ return MISC_TM_STORE_STRING;
+ case 0x73020002:
+ return OK_TM_STORE_STRING;
+ case 0x73020003:
+ return NOT_OK_TM_STORE_STRING;
+ case 0x73020004:
+ return HK_TM_STORE_STRING;
+ case 0x73030000:
+ return CFDP_TM_STORE_STRING;
case 0x73500000:
return CCSDS_IP_CORE_BRIDGE_STRING;
case 0x90000003:
diff --git a/linux/devices/ploc/PlocSupervisorHandler.cpp b/linux/devices/ploc/PlocSupervisorHandler.cpp
index 086ef661..06a4cf07 100644
--- a/linux/devices/ploc/PlocSupervisorHandler.cpp
+++ b/linux/devices/ploc/PlocSupervisorHandler.cpp
@@ -1742,18 +1742,21 @@ ReturnValue_t PlocSupervisorHandler::createMramDumpFile() {
std::string filename = "mram-dump--" + timeStamp + ".bin";
#ifdef XIPHOS_Q7S
- std::string currentMountPrefix = sdcMan->getCurrentMountPrefix();
+ const char* currentMountPrefix = sdcMan->getCurrentMountPrefix();
#else
- std::string currentMountPrefix("/mnt/sd0");
+ const char* currentMountPrefix = "/mnt/sd0";
#endif /* BOARD_TE0720 == 0 */
+ if (currentMountPrefix == nullptr) {
+ return returnvalue::FAILED;
+ }
// Check if path to PLOC directory exists
- if (not std::filesystem::exists(std::string(currentMountPrefix + "/" + supervisorFilePath))) {
+ if (not std::filesystem::exists(std::string(currentMountPrefix) + "/" + supervisorFilePath)) {
sif::warning << "PlocSupervisorHandler::createMramDumpFile: Supervisor path does not exist"
<< std::endl;
return result::PATH_DOES_NOT_EXIST;
}
- activeMramFile = currentMountPrefix + "/" + supervisorFilePath + "/" + filename;
+ activeMramFile = std::string(currentMountPrefix) + "/" + supervisorFilePath + "/" + filename;
// Create new file
std::ofstream file(activeMramFile, std::ios_base::out);
file.close();
diff --git a/linux/fsfwconfig/FSFWConfig.h.in b/linux/fsfwconfig/FSFWConfig.h.in
index 387ef724..677cf0af 100644
--- a/linux/fsfwconfig/FSFWConfig.h.in
+++ b/linux/fsfwconfig/FSFWConfig.h.in
@@ -42,7 +42,7 @@
//! When using the newlib nano library, C99 support for stdio facilities
//! will not be provided. This define should be set to 1 if this is the case.
-#define FSFW_NO_C99_IO 1
+#define FSFW_NO_C99_IO 0
//! Specify whether a special mode store is used for Subsystem components.
#define FSFW_USE_MODESTORE 0
diff --git a/linux/fsfwconfig/events/translateEvents.cpp b/linux/fsfwconfig/events/translateEvents.cpp
index e35a31ef..c979ff5e 100644
--- a/linux/fsfwconfig/events/translateEvents.cpp
+++ b/linux/fsfwconfig/events/translateEvents.cpp
@@ -1,7 +1,7 @@
/**
- * @brief Auto-generated event translation file. Contains 260 translations.
+ * @brief Auto-generated event translation file. Contains 263 translations.
* @details
- * Generated on: 2023-02-23 15:39:20
+ * Generated on: 2023-02-24 16:57:00
*/
#include "translateEvents.h"
@@ -90,6 +90,8 @@ const char *CHANGE_OF_SETUP_PARAMETER_STRING = "CHANGE_OF_SETUP_PARAMETER";
const char *STORE_ERROR_STRING = "STORE_ERROR";
const char *MSG_QUEUE_ERROR_STRING = "MSG_QUEUE_ERROR";
const char *SERIALIZATION_ERROR_STRING = "SERIALIZATION_ERROR";
+const char *FILESTORE_ERROR_STRING = "FILESTORE_ERROR";
+const char *FILENAME_TOO_LARGE_ERROR_STRING = "FILENAME_TOO_LARGE_ERROR";
const char *SAFE_RATE_VIOLATION_STRING = "SAFE_RATE_VIOLATION";
const char *SAFE_RATE_RECOVERY_STRING = "SAFE_RATE_RECOVERY";
const char *MULTIPLE_RW_INVALID_STRING = "MULTIPLE_RW_INVALID";
@@ -253,6 +255,7 @@ const char *REBOOT_HW_STRING = "REBOOT_HW";
const char *NO_SD_CARD_ACTIVE_STRING = "NO_SD_CARD_ACTIVE";
const char *VERSION_INFO_STRING = "VERSION_INFO";
const char *CURRENT_IMAGE_INFO_STRING = "CURRENT_IMAGE_INFO";
+const char *POSSIBLE_FILE_CORRUPTION_STRING = "POSSIBLE_FILE_CORRUPTION";
const char *NO_VALID_SENSOR_TEMPERATURE_STRING = "NO_VALID_SENSOR_TEMPERATURE";
const char *NO_HEALTHY_HEATER_AVAILABLE_STRING = "NO_HEALTHY_HEATER_AVAILABLE";
const char *SYRLINKS_OVERHEATING_STRING = "SYRLINKS_OVERHEATING";
@@ -433,6 +436,10 @@ const char *translateEvents(Event event) {
return MSG_QUEUE_ERROR_STRING;
case (10802):
return SERIALIZATION_ERROR_STRING;
+ case (10803):
+ return FILESTORE_ERROR_STRING;
+ case (10804):
+ return FILENAME_TOO_LARGE_ERROR_STRING;
case (11200):
return SAFE_RATE_VIOLATION_STRING;
case (11201):
@@ -760,18 +767,20 @@ const char *translateEvents(Event event) {
case (14006):
return CURRENT_IMAGE_INFO_STRING;
case (14100):
+ return POSSIBLE_FILE_CORRUPTION_STRING;
+ case (14200):
return NO_VALID_SENSOR_TEMPERATURE_STRING;
- case (14101):
+ case (14201):
return NO_HEALTHY_HEATER_AVAILABLE_STRING;
- case (14102):
+ case (14202):
return SYRLINKS_OVERHEATING_STRING;
- case (14103):
+ case (14203):
return PLOC_OVERHEATING_STRING;
- case (14104):
+ case (14204):
return OBC_OVERHEATING_STRING;
- case (14105):
+ case (14205):
return HPA_OVERHEATING_STRING;
- case (14106):
+ case (14206):
return PLPCDU_OVERHEATING_STRING;
default:
return "UNKNOWN_EVENT";
diff --git a/linux/fsfwconfig/objects/translateObjects.cpp b/linux/fsfwconfig/objects/translateObjects.cpp
index 70bcf3ad..93c4fb0f 100644
--- a/linux/fsfwconfig/objects/translateObjects.cpp
+++ b/linux/fsfwconfig/objects/translateObjects.cpp
@@ -1,8 +1,8 @@
/**
* @brief Auto-generated object translation file.
* @details
- * Contains 153 translations.
- * Generated on: 2023-02-23 15:39:20
+ * Contains 159 translations.
+ * Generated on: 2023-02-24 16:57:00
*/
#include "translateObjects.h"
@@ -110,6 +110,7 @@ const char *PUS_SERVICE_5_EVENT_REPORTING_STRING = "PUS_SERVICE_5_EVENT_REPORTIN
const char *PUS_SERVICE_8_FUNCTION_MGMT_STRING = "PUS_SERVICE_8_FUNCTION_MGMT";
const char *PUS_SERVICE_9_TIME_MGMT_STRING = "PUS_SERVICE_9_TIME_MGMT";
const char *PUS_SERVICE_11_TC_SCHEDULER_STRING = "PUS_SERVICE_11_TC_SCHEDULER";
+const char *PUS_SERVICE_15_TM_STORAGE_STRING = "PUS_SERVICE_15_TM_STORAGE";
const char *PUS_SERVICE_17_TEST_STRING = "PUS_SERVICE_17_TEST";
const char *PUS_SERVICE_20_PARAMETERS_STRING = "PUS_SERVICE_20_PARAMETERS";
const char *PUS_SERVICE_200_MODE_MGMT_STRING = "PUS_SERVICE_200_MODE_MGMT";
@@ -156,6 +157,11 @@ const char *ACS_SUBSYSTEM_STRING = "ACS_SUBSYSTEM";
const char *PL_SUBSYSTEM_STRING = "PL_SUBSYSTEM";
const char *TCS_SUBSYSTEM_STRING = "TCS_SUBSYSTEM";
const char *COM_SUBSYSTEM_STRING = "COM_SUBSYSTEM";
+const char *MISC_TM_STORE_STRING = "MISC_TM_STORE";
+const char *OK_TM_STORE_STRING = "OK_TM_STORE";
+const char *NOT_OK_TM_STORE_STRING = "NOT_OK_TM_STORE";
+const char *HK_TM_STORE_STRING = "HK_TM_STORE";
+const char *CFDP_TM_STORE_STRING = "CFDP_TM_STORE";
const char *CCSDS_IP_CORE_BRIDGE_STRING = "CCSDS_IP_CORE_BRIDGE";
const char *THERMAL_TEMP_INSERTER_STRING = "THERMAL_TEMP_INSERTER";
const char *NO_OBJECT_STRING = "NO_OBJECT";
@@ -370,6 +376,8 @@ const char *translateObject(object_id_t object) {
return PUS_SERVICE_9_TIME_MGMT_STRING;
case 0x53000011:
return PUS_SERVICE_11_TC_SCHEDULER_STRING;
+ case 0x53000015:
+ return PUS_SERVICE_15_TM_STORAGE_STRING;
case 0x53000017:
return PUS_SERVICE_17_TEST_STRING;
case 0x53000020:
@@ -462,6 +470,16 @@ const char *translateObject(object_id_t object) {
return TCS_SUBSYSTEM_STRING;
case 0x73010004:
return COM_SUBSYSTEM_STRING;
+ case 0x73020001:
+ return MISC_TM_STORE_STRING;
+ case 0x73020002:
+ return OK_TM_STORE_STRING;
+ case 0x73020003:
+ return NOT_OK_TM_STORE_STRING;
+ case 0x73020004:
+ return HK_TM_STORE_STRING;
+ case 0x73030000:
+ return CFDP_TM_STORE_STRING;
case 0x73500000:
return CCSDS_IP_CORE_BRIDGE_STRING;
case 0x90000003:
diff --git a/mission/controller/AcsController.cpp b/mission/controller/AcsController.cpp
index 6b821a08..f3269285 100644
--- a/mission/controller/AcsController.cpp
+++ b/mission/controller/AcsController.cpp
@@ -1,9 +1,8 @@
#include "AcsController.h"
#include
-
-#include "mission/acsDefs.h"
-#include "mission/config/torquer.h"
+#include
+#include
AcsController::AcsController(object_id_t objectId)
: ExtendedControllerBase(objectId),
@@ -46,6 +45,26 @@ ReturnValue_t AcsController::handleCommandMessage(CommandMessage *message) {
return result;
}
+ReturnValue_t AcsController::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
+ const uint8_t *data, size_t size) {
+ switch (actionId) {
+ case SOLAR_ARRAY_DEPLOYMENT_SUCCESSFUL: {
+ ReturnValue_t result = guidance.solarArrayDeploymentComplete();
+ if (result == returnvalue::FAILED) {
+ return FILE_DELETION_FAILED;
+ }
+ return HasActionsIF::EXECUTION_FINISHED;
+ }
+ case RESET_MEKF: {
+ navigation.resetMekf(&mekfData);
+ return HasActionsIF::EXECUTION_FINISHED;
+ }
+ default: {
+ return HasActionsIF::INVALID_ACTION_ID;
+ }
+ }
+}
+
MessageQueueId_t AcsController::getCommandQueue() const { return commandQueue->getId(); }
ReturnValue_t AcsController::getParameter(uint8_t domainId, uint8_t parameterId,
@@ -60,6 +79,25 @@ void AcsController::performControlOperation() {
#if OBSW_THREAD_TRACING == 1
trace::threadTrace(opCounter, "ACS & TCS PST");
#endif
+ {
+ PoolReadGuard pg(&mgmDataRaw);
+ if (pg.getReadResult() == returnvalue::OK) {
+ copyMgmData();
+ }
+ }
+ {
+ PoolReadGuard pg(&susDataRaw);
+ if (pg.getReadResult() == returnvalue::OK) {
+ copySusData();
+ }
+ }
+ {
+ PoolReadGuard pg(&gyrDataRaw);
+ if (pg.getReadResult() == returnvalue::OK) {
+ copyGyrData();
+ }
+ }
+
switch (internalState) {
case InternalState::STARTUP: {
initialCountdown.resetTimer();
@@ -95,25 +133,6 @@ void AcsController::performControlOperation() {
default:
break;
}
-
- {
- PoolReadGuard pg(&mgmDataRaw);
- if (pg.getReadResult() == returnvalue::OK) {
- copyMgmData();
- }
- }
- {
- PoolReadGuard pg(&susDataRaw);
- if (pg.getReadResult() == returnvalue::OK) {
- copySusData();
- }
- }
- {
- PoolReadGuard pg(&gyrDataRaw);
- if (pg.getReadResult() == returnvalue::OK) {
- copyGyrData();
- }
- }
}
void AcsController::performSafe() {
@@ -124,8 +143,8 @@ void AcsController::performSafe() {
&gyrDataProcessed, &gpsDataProcessed, &acsParameters);
ReturnValue_t result = navigation.useMekf(&sensorValues, &gyrDataProcessed, &mgmDataProcessed,
&susDataProcessed, &mekfData);
- if (result != MultiplicativeKalmanFilter::KALMAN_RUNNING &&
- result != MultiplicativeKalmanFilter::KALMAN_INITIALIZED) {
+ if (result != MultiplicativeKalmanFilter::MEKF_RUNNING &&
+ result != MultiplicativeKalmanFilter::MEKF_INITIALIZED) {
if (not mekfInvalidFlag) {
triggerEvent(acs::MEKF_INVALID_INFO);
mekfInvalidFlag = true;
@@ -139,7 +158,7 @@ void AcsController::performSafe() {
// if MEKF is working
double magMomMtq[3] = {0, 0, 0}, errAng = 0.0;
bool magMomMtqValid = false;
- if (result == MultiplicativeKalmanFilter::KALMAN_RUNNING) {
+ if (result == MultiplicativeKalmanFilter::MEKF_RUNNING) {
safeCtrl.safeMekf(now, mekfData.quatMekf.value, mekfData.quatMekf.isValid(),
mgmDataProcessed.magIgrfModel.value, mgmDataProcessed.magIgrfModel.isValid(),
susDataProcessed.sunIjkModel.value, susDataProcessed.isValid(),
@@ -189,8 +208,8 @@ void AcsController::performDetumble() {
&gyrDataProcessed, &gpsDataProcessed, &acsParameters);
ReturnValue_t result = navigation.useMekf(&sensorValues, &gyrDataProcessed, &mgmDataProcessed,
&susDataProcessed, &mekfData);
- if (result != MultiplicativeKalmanFilter::KALMAN_RUNNING &&
- result != MultiplicativeKalmanFilter::KALMAN_INITIALIZED) {
+ if (result != MultiplicativeKalmanFilter::MEKF_RUNNING &&
+ result != MultiplicativeKalmanFilter::MEKF_INITIALIZED) {
if (not mekfInvalidFlag) {
triggerEvent(acs::MEKF_INVALID_INFO);
mekfInvalidFlag = true;
@@ -236,8 +255,8 @@ void AcsController::performPointingCtrl() {
&gyrDataProcessed, &gpsDataProcessed, &acsParameters);
ReturnValue_t result = navigation.useMekf(&sensorValues, &gyrDataProcessed, &mgmDataProcessed,
&susDataProcessed, &mekfData);
- if (result != MultiplicativeKalmanFilter::KALMAN_RUNNING &&
- result != MultiplicativeKalmanFilter::KALMAN_INITIALIZED) {
+ if (result != MultiplicativeKalmanFilter::MEKF_RUNNING &&
+ result != MultiplicativeKalmanFilter::MEKF_INITIALIZED) {
if (not mekfInvalidFlag) {
triggerEvent(acs::MEKF_INVALID_INFO);
mekfInvalidFlag = true;
@@ -246,9 +265,10 @@ void AcsController::performPointingCtrl() {
triggerEvent(acs::MEKF_INVALID_MODE_VIOLATION);
}
mekfInvalidCounter++;
- commandActuators(0, 0, 0, acsParameters.magnetorquesParameter.torqueDuration, cmdSpeedRws[0],
- cmdSpeedRws[1], cmdSpeedRws[2], cmdSpeedRws[3],
- acsParameters.rwHandlingParameters.rampTime);
+ // commandActuators(0, 0, 0, acsParameters.magnetorquesParameter.torqueDuration,
+ // cmdSpeedRws[0],
+ // cmdSpeedRws[1], cmdSpeedRws[2], cmdSpeedRws[3],
+ // acsParameters.rwHandlingParameters.rampTime);
return;
} else {
mekfInvalidFlag = false;
@@ -395,7 +415,7 @@ void AcsController::performPointingCtrl() {
sensorValues.rw4Set.currSpeed.value, torqueRwsScaled, cmdSpeedRws);
actuatorCmd.cmdDipolMtq(mgtDpDes, cmdDipolMtqs);
- updateCtrlValData(targetQuat, errorQuat, errorAngle);
+ updateCtrlValData(targetQuat, errorQuat, errorAngle, targetSatRotRate);
updateActuatorCmdData(rwTrqNs, cmdSpeedRws, cmdDipolMtqs);
// commandActuators(cmdDipolMtqs[0], cmdDipolMtqs[1], cmdDipolMtqs[2],
// acsParameters.magnetorquesParameter.torqueDuration, cmdSpeedRws[0],
@@ -457,16 +477,20 @@ void AcsController::updateCtrlValData(double errAng) {
ctrlValData.errQuat.setValid(false);
ctrlValData.errAng.value = errAng;
ctrlValData.errAng.setValid(true);
+ std::memcpy(ctrlValData.tgtRotRate.value, ZERO_VEC, 3 * sizeof(double));
+ ctrlValData.tgtRotRate.setValid(false);
ctrlValData.setValidity(true, false);
}
}
-void AcsController::updateCtrlValData(const double *tgtQuat, const double *errQuat, double errAng) {
+void AcsController::updateCtrlValData(const double *tgtQuat, const double *errQuat, double errAng,
+ const double *tgtRotRate) {
PoolReadGuard pg(&ctrlValData);
if (pg.getReadResult() == returnvalue::OK) {
std::memcpy(ctrlValData.tgtQuat.value, tgtQuat, 4 * sizeof(double));
std::memcpy(ctrlValData.errQuat.value, errQuat, 4 * sizeof(double));
ctrlValData.errAng.value = errAng;
+ std::memcpy(ctrlValData.tgtRotRate.value, tgtRotRate, 3 * sizeof(double));
ctrlValData.setValidity(true, true);
}
}
@@ -477,6 +501,7 @@ void AcsController::disableCtrlValData() {
std::memcpy(ctrlValData.tgtQuat.value, UNIT_QUAT, 4 * sizeof(double));
std::memcpy(ctrlValData.errQuat.value, UNIT_QUAT, 4 * sizeof(double));
ctrlValData.errAng.value = 0;
+ std::memcpy(ctrlValData.tgtRotRate.value, ZERO_VEC, 3 * sizeof(double));
ctrlValData.setValidity(false, true);
}
}
diff --git a/mission/controller/AcsController.h b/mission/controller/AcsController.h
index 1b57a32a..6d31ae49 100644
--- a/mission/controller/AcsController.h
+++ b/mission/controller/AcsController.h
@@ -1,12 +1,17 @@
#ifndef MISSION_CONTROLLER_ACSCONTROLLER_H_
#define MISSION_CONTROLLER_ACSCONTROLLER_H_
+#include
#include
#include
#include
#include
+#include
+#include
+#include
#include
#include
+#include
#include "acs/ActuatorCmd.h"
#include "acs/Guidance.h"
@@ -17,11 +22,6 @@
#include "acs/control/PtgCtrl.h"
#include "acs/control/SafeCtrl.h"
#include "controllerdefinitions/AcsCtrlDefinitions.h"
-#include "eive/objects.h"
-#include "fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h"
-#include "fsfw_hal/devicehandlers/MgmRM3100Handler.h"
-#include "mission/devices/devicedefinitions/SusDefinitions.h"
-#include "mission/trace.h"
class AcsController : public ExtendedControllerBase, public ReceivesParameterMessagesIF {
public:
@@ -41,6 +41,7 @@ class AcsController : public ExtendedControllerBase, public ReceivesParameterMes
private:
static constexpr double UNIT_QUAT[4] = {0, 0, 0, 1};
+ static constexpr double ZERO_VEC[3] = {0, 0, 0};
static constexpr double RW_OFF_TORQUE[4] = {0.0, 0.0, 0.0, 0.0};
static constexpr int32_t RW_OFF_SPEED[4] = {0, 0, 0, 0};
@@ -58,7 +59,7 @@ class AcsController : public ExtendedControllerBase, public ReceivesParameterMes
uint8_t detumbleCounter = 0;
uint8_t multipleRwUnavailableCounter = 0;
- bool mekfInvalidFlag = true;
+ bool mekfInvalidFlag = false;
uint8_t mekfInvalidCounter = 0;
int32_t cmdSpeedRws[4] = {0, 0, 0, 0};
int16_t cmdDipolMtqs[3] = {0, 0, 0};
@@ -68,13 +69,23 @@ class AcsController : public ExtendedControllerBase, public ReceivesParameterMes
#endif
enum class InternalState { STARTUP, INITIAL_DELAY, READY };
-
InternalState internalState = InternalState::STARTUP;
+ /** Device command IDs */
+ static const DeviceCommandId_t SOLAR_ARRAY_DEPLOYMENT_SUCCESSFUL = 0x0;
+ static const DeviceCommandId_t RESET_MEKF = 0x1;
+
+ static const uint8_t INTERFACE_ID = CLASS_ID::ACS_CTRL;
+ static constexpr ReturnValue_t FILE_DELETION_FAILED = MAKE_RETURN_CODE(0);
+
ReturnValue_t initialize() override;
ReturnValue_t handleCommandMessage(CommandMessage* message) override;
void performControlOperation() override;
+ /* HasActionsIF overrides */
+ ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
+ const uint8_t* data, size_t size) override;
+
ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override;
LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;
@@ -92,7 +103,8 @@ class AcsController : public ExtendedControllerBase, public ReceivesParameterMes
void updateActuatorCmdData(const double* rwTargetTorque, const int32_t* rwTargetSpeed,
const int16_t* mtqTargetDipole);
void updateCtrlValData(double errAng);
- void updateCtrlValData(const double* tgtQuat, const double* errQuat, double errAng);
+ void updateCtrlValData(const double* tgtQuat, const double* errQuat, double errAng,
+ const double* tgtRotRate);
void disableCtrlValData();
/* ACS Sensor Values */
diff --git a/mission/controller/acs/AcsParameters.h b/mission/controller/acs/AcsParameters.h
index f1b538c8..11de10a3 100644
--- a/mission/controller/acs/AcsParameters.h
+++ b/mission/controller/acs/AcsParameters.h
@@ -1,8 +1,3 @@
-/*******************************
- * EIVE Flight Software Framework (FSFW)
- * (c) 2022 IRS, Uni Stuttgart
- *******************************/
-
#ifndef ACSPARAMETERS_H_
#define ACSPARAMETERS_H_
diff --git a/mission/controller/acs/Guidance.cpp b/mission/controller/acs/Guidance.cpp
index 031cd384..09f0be20 100644
--- a/mission/controller/acs/Guidance.cpp
+++ b/mission/controller/acs/Guidance.cpp
@@ -551,3 +551,19 @@ void Guidance::getTargetParamsSafe(double sunTargetSafe[3], double satRateSafe[3
std::memcpy(satRateSafe, acsParameters.safeModeControllerParameters.satRateRef,
3 * sizeof(double));
}
+
+ReturnValue_t Guidance::solarArrayDeploymentComplete() {
+ if (std::filesystem::exists(SD_0_SKEWED_PTG_FILE)) {
+ std::remove(SD_0_SKEWED_PTG_FILE);
+ if (std::filesystem::exists(SD_0_SKEWED_PTG_FILE)) {
+ return returnvalue::FAILED;
+ }
+ }
+ if (std::filesystem::exists(SD_1_SKEWED_PTG_FILE)) {
+ std::remove(SD_1_SKEWED_PTG_FILE);
+ if (std::filesystem::exists(SD_1_SKEWED_PTG_FILE)) {
+ return returnvalue::FAILED;
+ }
+ }
+ return returnvalue::OK;
+}
diff --git a/mission/controller/acs/Guidance.h b/mission/controller/acs/Guidance.h
index 65c9aa12..da9d429b 100644
--- a/mission/controller/acs/Guidance.h
+++ b/mission/controller/acs/Guidance.h
@@ -13,6 +13,7 @@ class Guidance {
virtual ~Guidance();
void getTargetParamsSafe(double sunTargetSafe[3], double satRateRef[3]);
+ ReturnValue_t solarArrayDeploymentComplete();
// Function to get the target quaternion and refence rotation rate from gps position and
// position of the ground station
diff --git a/mission/controller/acs/MultiplicativeKalmanFilter.cpp b/mission/controller/acs/MultiplicativeKalmanFilter.cpp
index 5bae4624..a700c6a6 100644
--- a/mission/controller/acs/MultiplicativeKalmanFilter.cpp
+++ b/mission/controller/acs/MultiplicativeKalmanFilter.cpp
@@ -189,12 +189,12 @@ ReturnValue_t MultiplicativeKalmanFilter::init(
initialCovarianceMatrix[5][4] = initGyroCov[2][1];
initialCovarianceMatrix[5][5] = initGyroCov[2][2];
updateDataSetWithoutData(mekfData, MekfStatus::INITIALIZED);
- return KALMAN_INITIALIZED;
+ return MEKF_INITIALIZED;
} else {
// no initialisation possible, no valid measurements
validInit = false;
updateDataSetWithoutData(mekfData, MekfStatus::UNINITIALIZED);
- return KALMAN_UNINITIALIZED;
+ return MEKF_UNINITIALIZED;
}
}
@@ -211,12 +211,12 @@ ReturnValue_t MultiplicativeKalmanFilter::mekfEst(const double *quaternionSTR, c
int MDF = 0; // Matrix Dimension Factor
if (!validGYRs_) {
updateDataSetWithoutData(mekfData, MekfStatus::NO_GYR_DATA);
- return KALMAN_NO_GYR_DATA;
+ return MEKF_NO_GYR_DATA;
}
// Check for Model Calculations
else if (!validSSModel || !validMagModel) {
updateDataSetWithoutData(mekfData, MekfStatus::NO_MODEL_VECTORS);
- return KALMAN_NO_MODEL_VECTORS;
+ return MEKF_NO_MODEL_VECTORS;
}
// Check Measurements available from SS, MAG, STR
if (validSS && validMagField_ && validSTR_) {
@@ -854,7 +854,7 @@ ReturnValue_t MultiplicativeKalmanFilter::mekfEst(const double *quaternionSTR, c
int inversionFailed = MathOperations::inverseMatrix(*residualCov, *invResidualCov, MDF);
if (inversionFailed) {
updateDataSetWithoutData(mekfData, MekfStatus::COVARIANCE_INVERSION_FAILED);
- return KALMAN_COVARIANCE_INVERSION_FAILED; // RETURN VALUE ? -- Like: Kalman Inversion Failed
+ return MEKF_COVARIANCE_INVERSION_FAILED; // RETURN VALUE ? -- Like: Kalman Inversion Failed
}
// [K = P * H' / (H * P * H' + R)]
@@ -1085,16 +1085,17 @@ ReturnValue_t MultiplicativeKalmanFilter::mekfEst(const double *quaternionSTR, c
MatrixOperations::add(*cov0, *cov1, *initialCovarianceMatrix, 6, 6);
updateDataSet(mekfData, MekfStatus::RUNNING, quatBJ, rotRateEst);
- return KALMAN_RUNNING;
+ return MEKF_RUNNING;
}
-void MultiplicativeKalmanFilter::reset(acsctrl::MekfData *mekfData) {
+ReturnValue_t MultiplicativeKalmanFilter::reset(acsctrl::MekfData *mekfData) {
double resetQuaternion[4] = {0, 0, 0, 1};
double resetCovarianceMatrix[6][6] = {{0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}};
std::memcpy(initialQuaternion, resetQuaternion, 4 * sizeof(double));
std::memcpy(initialCovarianceMatrix, resetCovarianceMatrix, 6 * 6 * sizeof(double));
updateDataSetWithoutData(mekfData, MekfStatus::UNINITIALIZED);
+ return MEKF_UNINITIALIZED;
}
void MultiplicativeKalmanFilter::updateDataSetWithoutData(acsctrl::MekfData *mekfData,
diff --git a/mission/controller/acs/MultiplicativeKalmanFilter.h b/mission/controller/acs/MultiplicativeKalmanFilter.h
index dd02cf9f..47e1f807 100644
--- a/mission/controller/acs/MultiplicativeKalmanFilter.h
+++ b/mission/controller/acs/MultiplicativeKalmanFilter.h
@@ -1,17 +1,3 @@
-/*
- * MultiplicativeKalmanFilter.h
- *
- * Created on: 4 Feb 2022
- * Author: Robin Marquardt
- *
- * @brief: This class handles the calculation of an estimated quaternion and the gyro bias by
- * means of the spacecraft attitude sensors
- *
- * @note: A description of the used algorithms can be found in the bachelor thesis of Robin
- * Marquardt
- * https://eive-cloud.irs.uni-stuttgart.de/index.php/apps/files/?dir=/EIVE_Studenten/Marquardt_Robin&openfile=500811
- */
-
#ifndef MULTIPLICATIVEKALMANFILTER_H_
#define MULTIPLICATIVEKALMANFILTER_H_
@@ -22,6 +8,13 @@
#include "eive/resultClassIds.h"
class MultiplicativeKalmanFilter {
+ /* @brief: This class handles the calculation of an estimated quaternion and the gyro bias by
+ * means of the spacecraft attitude sensors
+ *
+ * @note: A description of the used algorithms can be found in the bachelor thesis of Robin
+ * Marquardt
+ * https://eive-cloud.irs.uni-stuttgart.de/index.php/apps/files/?dir=/EIVE_Studenten/Marquardt_Robin&openfile=500811
+ */
public:
/* @brief: Constructor
* @param: acsParameters_ Pointer to object which defines the ACS configuration parameters
@@ -29,7 +22,7 @@ class MultiplicativeKalmanFilter {
MultiplicativeKalmanFilter(AcsParameters *acsParameters_);
virtual ~MultiplicativeKalmanFilter();
- void reset(acsctrl::MekfData *mekfData);
+ ReturnValue_t reset(acsctrl::MekfData *mekfData);
/* @brief: init() - This function initializes the Kalman Filter and will provide the first
* quaternion through the QUEST algorithm
@@ -74,15 +67,15 @@ class MultiplicativeKalmanFilter {
};
// resetting Mekf
- static constexpr uint8_t IF_KAL_ID = CLASS_ID::ACS_KALMAN;
- static constexpr ReturnValue_t KALMAN_UNINITIALIZED = returnvalue::makeCode(IF_KAL_ID, 2);
- static constexpr ReturnValue_t KALMAN_NO_GYR_DATA = returnvalue::makeCode(IF_KAL_ID, 3);
- static constexpr ReturnValue_t KALMAN_NO_MODEL_VECTORS = returnvalue::makeCode(IF_KAL_ID, 4);
- static constexpr ReturnValue_t KALMAN_NO_SUS_MGM_STR_DATA = returnvalue::makeCode(IF_KAL_ID, 5);
- static constexpr ReturnValue_t KALMAN_COVARIANCE_INVERSION_FAILED =
- returnvalue::makeCode(IF_KAL_ID, 6);
- static constexpr ReturnValue_t KALMAN_INITIALIZED = returnvalue::makeCode(IF_KAL_ID, 7);
- static constexpr ReturnValue_t KALMAN_RUNNING = returnvalue::makeCode(IF_KAL_ID, 8);
+ static constexpr uint8_t IF_MEKF_ID = CLASS_ID::ACS_MEKF;
+ static constexpr ReturnValue_t MEKF_UNINITIALIZED = returnvalue::makeCode(IF_MEKF_ID, 2);
+ static constexpr ReturnValue_t MEKF_NO_GYR_DATA = returnvalue::makeCode(IF_MEKF_ID, 3);
+ static constexpr ReturnValue_t MEKF_NO_MODEL_VECTORS = returnvalue::makeCode(IF_MEKF_ID, 4);
+ static constexpr ReturnValue_t MEKF_NO_SUS_MGM_STR_DATA = returnvalue::makeCode(IF_MEKF_ID, 5);
+ static constexpr ReturnValue_t MEKF_COVARIANCE_INVERSION_FAILED =
+ returnvalue::makeCode(IF_MEKF_ID, 6);
+ static constexpr ReturnValue_t MEKF_INITIALIZED = returnvalue::makeCode(IF_MEKF_ID, 7);
+ static constexpr ReturnValue_t MEKF_RUNNING = returnvalue::makeCode(IF_MEKF_ID, 8);
private:
/*Parameters*/
diff --git a/mission/controller/acs/Navigation.cpp b/mission/controller/acs/Navigation.cpp
index c6310302..03446609 100644
--- a/mission/controller/acs/Navigation.cpp
+++ b/mission/controller/acs/Navigation.cpp
@@ -25,26 +25,25 @@ ReturnValue_t Navigation::useMekf(ACS::SensorValues *sensorValues,
sensorValues->strSet.caliQy.isValid() &&
sensorValues->strSet.caliQz.isValid() && sensorValues->strSet.caliQw.isValid();
- if (kalmanInit) {
- return multiplicativeKalmanFilter.mekfEst(
+ if (mekfStatus == MultiplicativeKalmanFilter::MEKF_UNINITIALIZED) {
+ mekfStatus = multiplicativeKalmanFilter.init(
+ mgmDataProcessed->mgmVecTot.value, mgmDataProcessed->mgmVecTot.isValid(),
+ susDataProcessed->susVecTot.value, susDataProcessed->susVecTot.isValid(),
+ susDataProcessed->sunIjkModel.value, susDataProcessed->sunIjkModel.isValid(),
+ mgmDataProcessed->magIgrfModel.value, mgmDataProcessed->magIgrfModel.isValid(), mekfData);
+ return mekfStatus;
+ } else {
+ mekfStatus = multiplicativeKalmanFilter.mekfEst(
quatIB, quatIBValid, gyrDataProcessed->gyrVecTot.value,
gyrDataProcessed->gyrVecTot.isValid(), mgmDataProcessed->mgmVecTot.value,
mgmDataProcessed->mgmVecTot.isValid(), susDataProcessed->susVecTot.value,
susDataProcessed->susVecTot.isValid(), susDataProcessed->sunIjkModel.value,
susDataProcessed->sunIjkModel.isValid(), mgmDataProcessed->magIgrfModel.value,
mgmDataProcessed->magIgrfModel.isValid(), acsParameters.onBoardParams.sampleTime, mekfData);
- } else {
- ReturnValue_t result;
- result = multiplicativeKalmanFilter.init(
- mgmDataProcessed->mgmVecTot.value, mgmDataProcessed->mgmVecTot.isValid(),
- susDataProcessed->susVecTot.value, susDataProcessed->susVecTot.isValid(),
- susDataProcessed->sunIjkModel.value, susDataProcessed->sunIjkModel.isValid(),
- mgmDataProcessed->magIgrfModel.value, mgmDataProcessed->magIgrfModel.isValid(), mekfData);
- kalmanInit = true;
- return result;
+ return mekfStatus;
}
}
void Navigation::resetMekf(acsctrl::MekfData *mekfData) {
- multiplicativeKalmanFilter.reset(mekfData);
+ mekfStatus = multiplicativeKalmanFilter.reset(mekfData);
}
diff --git a/mission/controller/acs/Navigation.h b/mission/controller/acs/Navigation.h
index e054bfbf..cf9e81e3 100644
--- a/mission/controller/acs/Navigation.h
+++ b/mission/controller/acs/Navigation.h
@@ -22,7 +22,7 @@ class Navigation {
private:
MultiplicativeKalmanFilter multiplicativeKalmanFilter;
AcsParameters acsParameters;
- bool kalmanInit = false;
+ ReturnValue_t mekfStatus = MultiplicativeKalmanFilter::MEKF_UNINITIALIZED;
};
#endif /* ACS_NAVIGATION_H_ */
diff --git a/mission/controller/acs/SensorProcessing.h b/mission/controller/acs/SensorProcessing.h
index 6fa1ab8c..cdd29d8b 100644
--- a/mission/controller/acs/SensorProcessing.h
+++ b/mission/controller/acs/SensorProcessing.h
@@ -1,7 +1,3 @@
-/*******************************
- * EIVE Flight Software
- * (c) 2022 IRS, Uni Stuttgart
- *******************************/
#ifndef SENSORPROCESSING_H_
#define SENSORPROCESSING_H_
diff --git a/mission/controller/acs/SensorValues.cpp b/mission/controller/acs/SensorValues.cpp
index e4026300..85815ae5 100644
--- a/mission/controller/acs/SensorValues.cpp
+++ b/mission/controller/acs/SensorValues.cpp
@@ -1,9 +1,3 @@
-/*
- * SensorValues.cpp
- *
- * Created on: 30 Mar 2022
- * Author: rooob
- */
#include "SensorValues.h"
#include
diff --git a/mission/controller/acs/SusConverter.cpp b/mission/controller/acs/SusConverter.cpp
index f56ad32e..1a645270 100644
--- a/mission/controller/acs/SusConverter.cpp
+++ b/mission/controller/acs/SusConverter.cpp
@@ -1,16 +1,9 @@
-/*
- * SusConverter.cpp
- *
- * Created on: 17.01.2022
- * Author: Timon Schwarz
- */
-
#include "SusConverter.h"
#include
#include
#include
-#include //for atan2
+#include
#include
diff --git a/mission/controller/acs/SusConverter.h b/mission/controller/acs/SusConverter.h
index b3829827..046b0ca8 100644
--- a/mission/controller/acs/SusConverter.h
+++ b/mission/controller/acs/SusConverter.h
@@ -1,10 +1,3 @@
-/*
- * SusConverter.h
- *
- * Created on: Sep 22, 2022
- * Author: marius
- */
-
#ifndef MISSION_CONTROLLER_ACS_SUSCONVERTER_H_
#define MISSION_CONTROLLER_ACS_SUSCONVERTER_H_
@@ -28,8 +21,6 @@ class SusConverter {
private:
float alphaBetaRaw[2]; //[°]
- // float coeffAlpha[9][10];
- // float coeffBeta[9][10];
float alphaBetaCalibrated[2]; //[°]
float sunVectorSensorFrame[3]; //[-]
diff --git a/mission/controller/acs/util/MathOperations.h b/mission/controller/acs/util/MathOperations.h
index b8d1fa4d..f8537740 100644
--- a/mission/controller/acs/util/MathOperations.h
+++ b/mission/controller/acs/util/MathOperations.h
@@ -300,6 +300,7 @@ class MathOperations {
}
static float matrixDeterminant(const T1 *inputMatrix, uint8_t size) {
+ /* do not use this. takes 300ms */
float det = 0;
T1 matrix[size][size], submatrix[size - 1][size - 1];
for (uint8_t row = 0; row < size; row++) {
@@ -329,9 +330,7 @@ class MathOperations {
}
static int inverseMatrix(const T1 *inputMatrix, T1 *inverse, uint8_t size) {
- if (MathOperations::matrixDeterminant(inputMatrix, size) == 0) {
- return 1; // Matrix is singular and not invertible
- }
+ // Stopwatch stopwatch;
T1 matrix[size][size], identity[size][size];
// reformat array to matrix
for (uint8_t row = 0; row < size; row++) {
@@ -346,7 +345,6 @@ class MathOperations {
}
// gauss-jordan algo
// sort matrix such as no diag entry shall be 0
- // should not be needed as such a matrix has a det=0
for (uint8_t row = 0; row < size; row++) {
if (matrix[row][row] == 0.0) {
bool swaped = false;
diff --git a/mission/core/GenericFactory.cpp b/mission/core/GenericFactory.cpp
index b62c8af3..9e929e83 100644
--- a/mission/core/GenericFactory.cpp
+++ b/mission/core/GenericFactory.cpp
@@ -58,6 +58,7 @@
// TCP server includes
#include "fsfw/osal/common/TcpTmTcBridge.h"
#include "fsfw/osal/common/TcpTmTcServer.h"
+#include "mission/tmtc/Service15TmStorage.h"
#endif
#endif
@@ -83,7 +84,7 @@ EiveFaultHandler EIVE_FAULT_HANDLER;
} // namespace cfdp
void ObjectFactory::produceGenericObjects(HealthTableIF** healthTable_, PusTmFunnel** pusFunnel,
- CfdpTmFunnel** cfdpFunnel) {
+ CfdpTmFunnel** cfdpFunnel, SdCardMountedIF& sdcMan) {
// Framework objects
new EventManager(objects::EVENT_MANAGER);
auto healthTable = new HealthTable(objects::HEALTH_TABLE);
@@ -95,6 +96,7 @@ void ObjectFactory::produceGenericObjects(HealthTableIF** healthTable_, PusTmFun
auto* timeStamper = new CdsShortTimeStamper(objects::TIME_STAMPER);
StorageManagerIF* tcStore;
StorageManagerIF* tmStore;
+ StorageManagerIF* ipcStore;
{
PoolManager::LocalPoolConfig poolCfg = {{250, 16}, {250, 32}, {250, 64},
{150, 128}, {120, 1024}, {120, 2048}};
@@ -109,8 +111,8 @@ void ObjectFactory::produceGenericObjects(HealthTableIF** healthTable_, PusTmFun
{
PoolManager::LocalPoolConfig poolCfg = {{300, 16}, {200, 32}, {150, 64}, {150, 128},
- {100, 256}, {50, 512}, {50, 1024}, {50, 2048}};
- new PoolManager(objects::IPC_STORE, poolCfg);
+ {100, 256}, {50, 512}, {50, 1024}, {10, 2048}};
+ ipcStore = new PoolManager(objects::IPC_STORE, poolCfg);
}
#if OBSW_ADD_TCPIP_SERVERS == 1
@@ -137,9 +139,11 @@ void ObjectFactory::produceGenericObjects(HealthTableIF** healthTable_, PusTmFun
new CcsdsDistributor(config::EIVE_PUS_APID, objects::CCSDS_PACKET_DISTRIBUTOR);
new PusDistributor(config::EIVE_PUS_APID, objects::PUS_PACKET_DISTRIBUTOR, ccsdsDistrib);
- *cfdpFunnel = new CfdpTmFunnel(objects::CFDP_TM_FUNNEL, config::EIVE_CFDP_APID, *tmStore, 50);
- *pusFunnel = new PusTmFunnel(objects::PUS_TM_FUNNEL, *timeStamper, *tmStore,
- config::MAX_PUS_FUNNEL_QUEUE_DEPTH);
+ PusTmFunnel::FunnelCfg cfdpFunnelCfg(objects::CFDP_TM_FUNNEL, *tmStore, *ipcStore, 50);
+ *cfdpFunnel = new CfdpTmFunnel(cfdpFunnelCfg, config::EIVE_CFDP_APID);
+ PusTmFunnel::FunnelCfg pusFunnelCfg(objects::PUS_TM_FUNNEL, *tmStore, *ipcStore,
+ config::MAX_PUS_FUNNEL_QUEUE_DEPTH);
+ *pusFunnel = new PusTmFunnel(pusFunnelCfg, *timeStamper, sdcMan);
#if OBSW_ADD_TCPIP_SERVERS == 1
#if OBSW_ADD_TMTC_UDP_SERVER == 1
(*cfdpFunnel)->addDestination("UDP Server", *udpBridge, 0);
@@ -171,6 +175,7 @@ void ObjectFactory::produceGenericObjects(HealthTableIF** healthTable_, PusTmFun
new Service11TelecommandScheduling(
PsbParams(objects::PUS_SERVICE_11_TC_SCHEDULER, config::EIVE_PUS_APID, pus::PUS_SERVICE_11),
ccsdsDistrib);
+ new Service15TmStorage(objects::PUS_SERVICE_15_TM_STORAGE, config::EIVE_PUS_APID, 10);
new Service17Test(
PsbParams(objects::PUS_SERVICE_17_TEST, config::EIVE_PUS_APID, pus::PUS_SERVICE_17));
new Service20ParameterManagement(objects::PUS_SERVICE_20_PARAMETERS, config::EIVE_PUS_APID,
@@ -232,7 +237,7 @@ void ObjectFactory::createRwAssy(PowerSwitchIF& pwrSwitcher, power::Switch_t the
std::array rwIds) {
RwHelper rwHelper(rwIds);
auto* rwAss = new RwAssembly(objects::RW_ASS, &pwrSwitcher, theSwitch, rwHelper);
- for (uint8_t idx = 0; idx < rwIds.size(); idx++) {
+ for (size_t idx = 0; idx < rwIds.size(); idx++) {
ReturnValue_t result = rws[idx]->connectModeTreeParent(*rwAss);
if (result != returnvalue::OK) {
sif::error << "Connecting RW " << static_cast(idx) << " to RW assembly failed"
@@ -251,7 +256,7 @@ void ObjectFactory::createSusAssy(PowerSwitchIF& pwrSwitcher,
objects::SUS_6_R_LOC_XFYBZM_PT_XF, objects::SUS_7_R_LOC_XBYBZM_PT_XB,
objects::SUS_8_R_LOC_XBYBZB_PT_YB, objects::SUS_9_R_LOC_XBYBZB_PT_YF,
objects::SUS_10_N_LOC_XMYBZF_PT_ZF, objects::SUS_11_R_LOC_XBYMZB_PT_ZB};
- SusAssHelper susAssHelper = SusAssHelper(susIds);
+ auto susAssHelper = SusAssHelper(susIds);
auto susAss = new SusAssembly(objects::SUS_BOARD_ASS, &pwrSwitcher, susAssHelper);
for (auto& sus : suses) {
if (sus != nullptr) {
@@ -287,8 +292,8 @@ void ObjectFactory::createAcsBoardAssy(PowerSwitchIF& pwrSwitcher,
TcsBoardAssembly* ObjectFactory::createTcsBoardAssy(PowerSwitchIF& pwrSwitcher) {
TcsBoardHelper helper(RTD_INFOS);
- TcsBoardAssembly* tcsBoardAss = new TcsBoardAssembly(
- objects::TCS_BOARD_ASS, &pwrSwitcher, pcdu::Switches::PDU1_CH0_TCS_BOARD_3V3, helper);
+ auto* tcsBoardAss = new TcsBoardAssembly(objects::TCS_BOARD_ASS, &pwrSwitcher,
+ pcdu::Switches::PDU1_CH0_TCS_BOARD_3V3, helper);
tcsBoardAss->connectModeTreeParent(satsystem::tcs::SUBSYSTEM);
return tcsBoardAss;
}
diff --git a/mission/core/GenericFactory.h b/mission/core/GenericFactory.h
index 30f2d6bb..5902ff7b 100644
--- a/mission/core/GenericFactory.h
+++ b/mission/core/GenericFactory.h
@@ -2,6 +2,7 @@
#define MISSION_CORE_GENERICFACTORY_H_
#include
+#include
#include "fsfw/objectmanager/SystemObjectIF.h"
#include "fsfw/power/PowerSwitchIF.h"
@@ -37,7 +38,7 @@ const std::array, EiveMax31855::NUM_RTDS> RT
namespace ObjectFactory {
void produceGenericObjects(HealthTableIF** healthTable, PusTmFunnel** pusFunnel,
- CfdpTmFunnel** cfdpFunnel);
+ CfdpTmFunnel** cfdpFunnel, SdCardMountedIF& sdcMan);
void createGenericHeaterComponents(GpioIF& gpioIF, PowerSwitchIF& pwrSwitcher,
HeaterHandler*& heaterHandler);
diff --git a/mission/devices/PayloadPcduHandler.cpp b/mission/devices/PayloadPcduHandler.cpp
index 44dd667c..48880c6e 100644
--- a/mission/devices/PayloadPcduHandler.cpp
+++ b/mission/devices/PayloadPcduHandler.cpp
@@ -517,6 +517,9 @@ void PayloadPcduHandler::checkJsonFileInit() {
if (not jsonFileInitComplete) {
auto activeSd = sdcMan->getActiveSdCard();
if (activeSd and sdcMan->isSdCardUsable(activeSd.value())) {
+ if (sdcMan->getCurrentMountPrefix() == nullptr) {
+ return;
+ }
params.initialize(sdcMan->getCurrentMountPrefix());
jsonFileInitComplete = true;
}
diff --git a/mission/devices/ScexDeviceHandler.cpp b/mission/devices/ScexDeviceHandler.cpp
index 8da6d229..e2061a6b 100644
--- a/mission/devices/ScexDeviceHandler.cpp
+++ b/mission/devices/ScexDeviceHandler.cpp
@@ -214,6 +214,9 @@ ReturnValue_t ScexDeviceHandler::interpretDeviceReply(DeviceCommandId_t id, cons
fileId = date_time_string();
std::ostringstream oss;
auto prefix = sdcMan.getCurrentMountPrefix();
+ if (prefix == nullptr) {
+ return returnvalue::FAILED;
+ }
oss << prefix << "/scex/scex-" << cmdName << fileId << ".bin";
fileName = oss.str();
ofstream out(fileName, ofstream::binary);
@@ -234,6 +237,9 @@ ReturnValue_t ScexDeviceHandler::interpretDeviceReply(DeviceCommandId_t id, cons
fileId = date_time_string();
std::ostringstream oss;
auto prefix = sdcMan.getCurrentMountPrefix();
+ if (prefix == nullptr) {
+ return returnvalue::FAILED;
+ }
oss << prefix << "/scex/scex-" << cmdName << fileId << ".bin";
fileName = oss.str();
fileNameSet = true;
@@ -310,6 +316,16 @@ ReturnValue_t ScexDeviceHandler::interpretDeviceReply(DeviceCommandId_t id, cons
}
void ScexDeviceHandler::performOperationHook() {
+ auto mntPrefix = sdcMan.getCurrentMountPrefix();
+ if (mntPrefix != nullptr) {
+ std::filesystem::path fullFilePath = mntPrefix;
+ fullFilePath /= "scex";
+ bool fileExists = std::filesystem::exists(fullFilePath);
+
+ if (not fileExists) {
+ std::filesystem::create_directory(fullFilePath);
+ }
+ }
uint32_t remainingMillis = finishCountdown.getRemainingMillis();
if (commandActive and finishCountdown.hasTimedOut()) {
triggerEvent(scex::EXPERIMENT_TIMEDOUT, currCmd, 0);
@@ -373,13 +389,5 @@ void ScexDeviceHandler::setPowerSwitcher(PowerSwitchIF& powerSwitcher, power::Sw
}
ReturnValue_t ScexDeviceHandler::initializeAfterTaskCreation() {
- auto mntPrefix = sdcMan.getCurrentMountPrefix();
- std::filesystem::path fullFilePath = mntPrefix;
- fullFilePath /= "scex";
- bool fileExists = std::filesystem::exists(fullFilePath);
-
- if (not fileExists) {
- std::filesystem::create_directory(fullFilePath);
- }
return DeviceHandlerBase::initializeAfterTaskCreation();
}
diff --git a/mission/devices/devicedefinitions/GPSDefinitions.h b/mission/devices/devicedefinitions/GPSDefinitions.h
index 8acb77e9..80e2861a 100644
--- a/mission/devices/devicedefinitions/GPSDefinitions.h
+++ b/mission/devices/devicedefinitions/GPSDefinitions.h
@@ -67,6 +67,7 @@ class GpsPrimaryDataset : public StaticLocalDataSet<18> {
private:
friend class GpsHyperionLinuxController;
+ friend class GpsCtrlDummy;
GpsPrimaryDataset(HasLocalDataPoolIF* hkOwner)
: StaticLocalDataSet(hkOwner, GpsHyperion::DATASET_ID) {}
};
diff --git a/mission/memory/SdCardMountedIF.h b/mission/memory/SdCardMountedIF.h
index ac705e8d..1e76b9b7 100644
--- a/mission/memory/SdCardMountedIF.h
+++ b/mission/memory/SdCardMountedIF.h
@@ -9,7 +9,7 @@
class SdCardMountedIF {
public:
virtual ~SdCardMountedIF(){};
- virtual const std::string& getCurrentMountPrefix() const = 0;
+ virtual const char* getCurrentMountPrefix() const = 0;
virtual bool isSdCardUsable(std::optional sdCard) = 0;
virtual std::optional getPreferredSdCard() const = 0;
virtual void setActiveSdCard(sd::SdCard sdCard) = 0;
diff --git a/mission/tmtc/CMakeLists.txt b/mission/tmtc/CMakeLists.txt
index bb92a84e..c4c93ab6 100644
--- a/mission/tmtc/CMakeLists.txt
+++ b/mission/tmtc/CMakeLists.txt
@@ -1,4 +1,10 @@
target_sources(
${LIB_EIVE_MISSION}
- PRIVATE CcsdsIpCoreHandler.cpp VirtualChannel.cpp TmFunnelHandler.cpp
- TmFunnelBase.cpp CfdpTmFunnel.cpp PusTmFunnel.cpp)
+ PRIVATE CcsdsIpCoreHandler.cpp
+ VirtualChannel.cpp
+ TmFunnelHandler.cpp
+ TmFunnelBase.cpp
+ CfdpTmFunnel.cpp
+ Service15TmStorage.cpp
+ PersistentTmStore.cpp
+ PusTmFunnel.cpp)
diff --git a/mission/tmtc/CfdpTmFunnel.cpp b/mission/tmtc/CfdpTmFunnel.cpp
index 32dba7fe..89d7c105 100644
--- a/mission/tmtc/CfdpTmFunnel.cpp
+++ b/mission/tmtc/CfdpTmFunnel.cpp
@@ -4,9 +4,8 @@
#include "fsfw/tmtcpacket/ccsds/SpacePacketCreator.h"
#include "fsfw/tmtcservices/TmTcMessage.h"
-CfdpTmFunnel::CfdpTmFunnel(object_id_t objectId, uint16_t cfdpInCcsdsApid,
- StorageManagerIF& tmStore, uint32_t messageDepth)
- : TmFunnelBase(objectId, tmStore, messageDepth), cfdpInCcsdsApid(cfdpInCcsdsApid) {}
+CfdpTmFunnel::CfdpTmFunnel(TmFunnelBase::FunnelCfg cfg, uint16_t cfdpInCcsdsApid)
+ : TmFunnelBase(cfg), cfdpInCcsdsApid(cfdpInCcsdsApid) {}
const char* CfdpTmFunnel::getName() const { return "CFDP TM Funnel"; }
diff --git a/mission/tmtc/CfdpTmFunnel.h b/mission/tmtc/CfdpTmFunnel.h
index e294956a..717573a0 100644
--- a/mission/tmtc/CfdpTmFunnel.h
+++ b/mission/tmtc/CfdpTmFunnel.h
@@ -12,8 +12,7 @@
class CfdpTmFunnel : public TmFunnelBase {
public:
- CfdpTmFunnel(object_id_t objectId, uint16_t cfdpInCcsdsApid, StorageManagerIF& tmStore,
- uint32_t messageDepth);
+ CfdpTmFunnel(TmFunnelBase::FunnelCfg cfg, uint16_t cfdpInCcsdsApid);
[[nodiscard]] const char* getName() const override;
ReturnValue_t performOperation(uint8_t opCode);
ReturnValue_t initialize() override;
diff --git a/mission/tmtc/PersistentTmStore.cpp b/mission/tmtc/PersistentTmStore.cpp
new file mode 100644
index 00000000..6ceed609
--- /dev/null
+++ b/mission/tmtc/PersistentTmStore.cpp
@@ -0,0 +1,362 @@
+#include "PersistentTmStore.h"
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include "fsfw/ipc/CommandMessage.h"
+#include "fsfw/ipc/QueueFactory.h"
+#include "fsfw/tmstorage/TmStoreMessage.h"
+
+using namespace returnvalue;
+
+PersistentTmStore::PersistentTmStore(object_id_t objectId, const char* baseDir,
+ std::string baseName, RolloverInterval intervalUnit,
+ uint32_t intervalCount, StorageManagerIF& tmStore,
+ SdCardMountedIF& sdcMan)
+ : SystemObject(objectId),
+ baseDir(baseDir),
+ baseName(std::move(baseName)),
+ sdcMan(sdcMan),
+ tmStore(tmStore) {
+ tcQueue = QueueFactory::instance()->createMessageQueue();
+ calcDiffSeconds(intervalUnit, intervalCount);
+}
+
+ReturnValue_t PersistentTmStore::assignAndOrCreateMostRecentFile() {
+ using namespace std::filesystem;
+ for (auto const& file : directory_iterator(basePath)) {
+ if (file.is_directory()) {
+ continue;
+ }
+ auto pathStr = file.path().string();
+ if (pathStr.find(baseName) == std::string::npos) {
+ continue;
+ }
+ unsigned int underscorePos = pathStr.find_last_of('_');
+ std::string stampStr = pathStr.substr(underscorePos + 1);
+ struct tm time {};
+ if (nullptr == strptime(stampStr.c_str(), FILE_DATE_FORMAT, &time)) {
+ sif::error << "PersistentTmStore::assignOrCreateMostRecentFile: Error reading timestamp"
+ << std::endl;
+ // Delete the file and re-create it.
+ activeFile = std::nullopt;
+ std::filesystem::remove(file.path());
+ break;
+ }
+ time_t fileEpoch = timegm(&time);
+ // There is still a file within the active time window, so re-use that file for new TMs to
+ // store.
+ if (fileEpoch + static_cast(rolloverDiffSeconds) > currentTv.tv_sec) {
+ activeFileTv.tv_sec = fileEpoch;
+ activeFile = file.path();
+ break;
+ }
+ }
+ if (not activeFile.has_value()) {
+ return createMostRecentFile(std::nullopt);
+ }
+ return returnvalue::OK;
+}
+
+ReturnValue_t PersistentTmStore::handleCommandQueue(StorageManagerIF& ipcStore,
+ TmFunnelBase& tmFunnel) {
+ CommandMessage cmdMessage;
+ ReturnValue_t result = tcQueue->receiveMessage(&cmdMessage);
+ if (result == MessageQueueIF::EMPTY) {
+ return returnvalue::OK;
+ }
+ if (result != returnvalue::OK) {
+ return result;
+ }
+ if (cmdMessage.getMessageType() == messagetypes::TM_STORE) {
+ Command_t cmd = cmdMessage.getCommand();
+ if (cmd == TmStoreMessage::DELETE_STORE_CONTENT_TIME) {
+ Clock::getClock_timeval(¤tTv);
+ store_address_t storeId = TmStoreMessage::getStoreId(&cmdMessage);
+ auto accessor = ipcStore.getData(storeId);
+ uint32_t deleteUpToUnixSeconds = 0;
+ size_t size = accessor.second.size();
+ SerializeAdapter::deSerialize(&deleteUpToUnixSeconds, accessor.second.data(), &size,
+ SerializeIF::Endianness::NETWORK);
+ deleteUpTo(deleteUpToUnixSeconds);
+ } else if (cmd == TmStoreMessage::DOWNLINK_STORE_CONTENT_TIME) {
+ Clock::getClock_timeval(¤tTv);
+ store_address_t storeId = TmStoreMessage::getStoreId(&cmdMessage);
+ auto accessor = ipcStore.getData(storeId);
+ if (accessor.second.size() < 8) {
+ return returnvalue::FAILED;
+ }
+ uint32_t dumpFromUnixSeconds;
+ uint32_t dumpUntilUnixSeconds;
+ size_t size = 8;
+ SerializeAdapter::deSerialize(&dumpFromUnixSeconds, accessor.second.data(), &size,
+ SerializeIF::Endianness::NETWORK);
+ SerializeAdapter::deSerialize(&dumpUntilUnixSeconds, accessor.second.data() + 4, &size,
+ SerializeIF::Endianness::NETWORK);
+ dumpFromUpTo(dumpFromUnixSeconds, dumpUntilUnixSeconds, tmFunnel);
+ }
+ }
+ return returnvalue::OK;
+}
+
+ReturnValue_t PersistentTmStore::passPacket(PusTmReader& reader) {
+ bool inApidList = false;
+ if (filter.apid) {
+ auto& apidFilter = filter.apid.value();
+ if (std::find(apidFilter.begin(), apidFilter.end(), reader.getApid()) != apidFilter.end()) {
+ if (not filter.serviceSubservices and not filter.services) {
+ return storePacket(reader);
+ }
+ inApidList = true;
+ }
+ }
+ std::pair serviceSubservice;
+ serviceSubservice.first = reader.getService();
+ serviceSubservice.second = reader.getSubService();
+ if (filter.services) {
+ auto& serviceFilter = filter.services.value();
+ if (std::find(serviceFilter.begin(), serviceFilter.end(), serviceSubservice.first) !=
+ serviceFilter.end()) {
+ if (filter.apid and inApidList) {
+ return storePacket(reader);
+ }
+ }
+ }
+ if (filter.serviceSubservices) {
+ auto& serviceSubserviceFilter = filter.serviceSubservices.value();
+ if (std::find(serviceSubserviceFilter.begin(), serviceSubserviceFilter.end(),
+ serviceSubservice) != serviceSubserviceFilter.end()) {
+ if (filter.apid and inApidList) {
+ return storePacket(reader);
+ }
+ }
+ }
+ return returnvalue::OK;
+}
+
+void PersistentTmStore::dumpFrom(uint32_t fromUnixSeconds, TmFunnelBase& tmFunnel) {
+ return dumpFromUpTo(fromUnixSeconds, currentTv.tv_sec, tmFunnel);
+}
+
+ReturnValue_t PersistentTmStore::storePacket(PusTmReader& reader) {
+ using namespace std::filesystem;
+ if (baseDirUninitialized) {
+ updateBaseDir();
+ }
+ Clock::getClock_timeval(¤tTv);
+ // It is assumed here that the filesystem is usable.
+ if (not activeFile.has_value()) {
+ ReturnValue_t result = assignAndOrCreateMostRecentFile();
+ if (result != returnvalue::OK) {
+ return result;
+ }
+ }
+
+ bool createNewFile = false;
+ std::optional suffix = std::nullopt;
+ if (currentTv.tv_sec > activeFileTv.tv_sec + static_cast(rolloverDiffSeconds)) {
+ createNewFile = true;
+ currentSameSecNumber = 0;
+ } else if (file_size(activeFile.value()) + reader.getFullPacketLen() > fileBuf.size()) {
+ createNewFile = true;
+ if (currentSameSecNumber >= MAX_FILES_IN_ONE_SECOND) {
+ currentSameSecNumber = 0;
+ }
+ if (currentTv.tv_sec == activeFileTv.tv_sec) {
+ suffix = currentSameSecNumber++;
+ } else {
+ currentSameSecNumber = 0;
+ }
+ }
+ if (createNewFile) {
+ createMostRecentFile(suffix);
+ }
+
+ // Rollover conditions were handled, write to file now
+ std::ofstream of(activeFile.value(), std::ios::app | std::ios::binary);
+ of.write(reinterpret_cast(reader.getFullData()),
+ static_cast(reader.getFullPacketLen()));
+ return returnvalue::OK;
+}
+
+MessageQueueId_t PersistentTmStore::getCommandQueue() const { return tcQueue->getId(); }
+
+void PersistentTmStore::calcDiffSeconds(RolloverInterval intervalUnit, uint32_t intervalCount) {
+ if (intervalUnit == RolloverInterval::MINUTELY) {
+ rolloverDiffSeconds = 60 * intervalCount;
+ } else if (intervalUnit == RolloverInterval::HOURLY) {
+ rolloverDiffSeconds = 60 * 60 * intervalCount;
+ } else if (intervalUnit == RolloverInterval::DAILY) {
+ rolloverDiffSeconds = 60 * 60 * 24 * intervalCount;
+ }
+}
+
+bool PersistentTmStore::updateBaseDir() {
+ using namespace std::filesystem;
+ const char* currentPrefix = sdcMan.getCurrentMountPrefix();
+ if (currentPrefix == nullptr) {
+ return false;
+ }
+ basePath = path(currentPrefix) / baseDir / baseName;
+ if (not exists(basePath)) {
+ create_directories(basePath);
+ }
+ baseDirUninitialized = false;
+ return true;
+}
+
+void PersistentTmStore::addApid(uint16_t apid) {
+ if (not filter.apid) {
+ filter.apid = std::vector({apid});
+ return;
+ }
+ filter.apid.value().push_back(apid);
+}
+
+void PersistentTmStore::addService(uint8_t service) {
+ if (not filter.services) {
+ filter.services = std::vector({service});
+ return;
+ }
+ filter.services.value().push_back(service);
+}
+
+void PersistentTmStore::addServiceSubservice(uint8_t service, uint8_t subservice) {
+ if (not filter.serviceSubservices) {
+ filter.serviceSubservices =
+ std::vector>({std::pair(service, subservice)});
+ return;
+ }
+ filter.serviceSubservices.value().emplace_back(service, subservice);
+}
+
+void PersistentTmStore::deleteUpTo(uint32_t unixSeconds) {
+ using namespace std::filesystem;
+ for (auto const& file : directory_iterator(basePath)) {
+ if (file.is_directory() or (activeFile.has_value() and (activeFile.value() == file.path()))) {
+ continue;
+ }
+ // Convert file time to the UNIX epoch
+ struct tm fileTime {};
+ if (pathToTm(file.path(), fileTime) != returnvalue::OK) {
+ sif::error << "Time extraction for " << file << "failed" << std::endl;
+ continue;
+ }
+ time_t fileEpoch = timegm(&fileTime);
+ if (fileEpoch + rolloverDiffSeconds < unixSeconds) {
+ std::filesystem::remove(file.path());
+ }
+ }
+}
+
+void PersistentTmStore::dumpFromUpTo(uint32_t fromUnixSeconds, uint32_t upToUnixSeconds,
+ TmFunnelBase& funnel) {
+ using namespace std::filesystem;
+ for (auto const& file : directory_iterator(basePath)) {
+ if (file.is_directory()) {
+ continue;
+ }
+ struct tm fileTime {};
+ if (pathToTm(file.path(), fileTime) != returnvalue::OK) {
+ sif::error << "Time extraction for file " << file << "failed" << std::endl;
+ continue;
+ }
+ auto fileEpoch = static_cast(timegm(&fileTime));
+ if ((fileEpoch > fromUnixSeconds) and (fileEpoch + rolloverDiffSeconds <= upToUnixSeconds)) {
+ fileToPackets(file, fileEpoch, funnel);
+ }
+ }
+}
+
+ReturnValue_t PersistentTmStore::pathToTm(const std::filesystem::path& path, struct tm& time) {
+ auto pathStr = path.string();
+ size_t splitChar = pathStr.find('_');
+ auto timeOnlyStr = pathStr.substr(splitChar + 1);
+ if (nullptr == strptime(timeOnlyStr.c_str(), FILE_DATE_FORMAT, &time)) {
+ return returnvalue::FAILED;
+ }
+ return returnvalue::OK;
+}
+
+void PersistentTmStore::fileToPackets(const std::filesystem::path& path, uint32_t unixStamp,
+ TmFunnelBase& funnel) {
+ store_address_t storeId;
+ TmTcMessage message;
+ size_t size = std::filesystem::file_size(path);
+ if (size < 6) {
+ // Can't even read the CCSDS header
+ return;
+ }
+ std::ifstream ifile(path, std::ios::binary);
+ ifile.read(reinterpret_cast(fileBuf.data()), static_cast(size));
+ size_t currentIdx = 0;
+ while (currentIdx < size) {
+ PusTmReader reader(&timeReader, fileBuf.data(), fileBuf.size());
+ // CRC check to fully ensure this is a valid TM
+ ReturnValue_t result = reader.parseDataWithCrcCheck();
+ if (result == returnvalue::OK) {
+ result = tmStore.addData(&storeId, fileBuf.data() + currentIdx, reader.getFullPacketLen());
+ if (result != returnvalue::OK) {
+ continue;
+ }
+ funnel.sendPacketToDestinations(storeId, message, fileBuf.data() + currentIdx,
+ reader.getFullPacketLen());
+ currentIdx += reader.getFullPacketLen();
+ } else {
+ sif::error << "Parsing of PUS TM failed with code " << result << std::endl;
+ triggerEvent(POSSIBLE_FILE_CORRUPTION, result, unixStamp);
+ // Stop for now, do not really know where to continue and we do not trust the file anymore.
+ break;
+ }
+ }
+}
+
+ReturnValue_t PersistentTmStore::createMostRecentFile(std::optional suffix) {
+ using namespace std::filesystem;
+ unsigned currentIdx = 0;
+ path pathStart = basePath / baseName;
+ memcpy(fileBuf.data() + currentIdx, pathStart.c_str(), pathStart.string().length());
+ currentIdx += pathStart.string().length();
+ fileBuf[currentIdx] = '_';
+ currentIdx += 1;
+ time_t epoch = currentTv.tv_sec;
+ struct tm* time = gmtime(&epoch);
+ size_t writtenBytes = strftime(reinterpret_cast(fileBuf.data() + currentIdx),
+ fileBuf.size(), FILE_DATE_FORMAT, time);
+ if (writtenBytes == 0) {
+ sif::error << "PersistentTmStore::createMostRecentFile: Could not create file timestamp"
+ << std::endl;
+ return returnvalue::FAILED;
+ }
+ currentIdx += writtenBytes;
+ char* res = strcpy(reinterpret_cast(fileBuf.data() + currentIdx), ".bin");
+ if (res == nullptr) {
+ return returnvalue::FAILED;
+ }
+ currentIdx += 4;
+ if (suffix.has_value()) {
+ std::string fullSuffix = "." + std::to_string(suffix.value());
+ res = strcpy(reinterpret_cast(fileBuf.data() + currentIdx), fullSuffix.c_str());
+ if (res == nullptr) {
+ return returnvalue::FAILED;
+ }
+ currentIdx += fullSuffix.size();
+ }
+
+ path newPath(std::string(reinterpret_cast(fileBuf.data()), currentIdx));
+ std::ofstream of(newPath, std::ios::binary);
+ activeFile = newPath;
+ activeFileTv = currentTv;
+ return returnvalue::OK;
+}
+
+ReturnValue_t PersistentTmStore::initializeTmStore() {
+ Clock::getClock_timeval(¤tTv);
+ updateBaseDir();
+ return assignAndOrCreateMostRecentFile();
+}
diff --git a/mission/tmtc/PersistentTmStore.h b/mission/tmtc/PersistentTmStore.h
new file mode 100644
index 00000000..d8bc9acf
--- /dev/null
+++ b/mission/tmtc/PersistentTmStore.h
@@ -0,0 +1,87 @@
+#ifndef MISSION_TMTC_TMSTOREBACKEND_H_
+#define MISSION_TMTC_TMSTOREBACKEND_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "TmFunnelBase.h"
+#include "eive/eventSubsystemIds.h"
+
+struct PacketFilter {
+ std::optional> apid;
+ std::optional> services;
+ std::optional>> serviceSubservices;
+};
+
+enum class RolloverInterval { MINUTELY, HOURLY, DAILY };
+
+class PersistentTmStore : public TmStoreFrontendSimpleIF, public SystemObject {
+ public:
+ static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PERSISTENT_TM_STORE;
+
+ //! [EXPORT] : [COMMENT]
+ //! P1: Result code of TM packet parser.
+ //! P2: Timestamp of possibly corrupt file as a unix timestamp.
+ static constexpr Event POSSIBLE_FILE_CORRUPTION =
+ event::makeEvent(SUBSYSTEM_ID, 0, severity::LOW);
+ PersistentTmStore(object_id_t objectId, const char* baseDir, std::string baseName,
+ RolloverInterval intervalUnit, uint32_t intervalCount,
+ StorageManagerIF& tmStore, SdCardMountedIF& sdcMan);
+
+ ReturnValue_t initializeTmStore();
+ ReturnValue_t handleCommandQueue(StorageManagerIF& ipcStore, TmFunnelBase& tmFunnel);
+
+ void addApid(uint16_t apid);
+ void addService(uint8_t service);
+ void addServiceSubservice(uint8_t service, uint8_t subservice);
+
+ void deleteUpTo(uint32_t unixSeconds);
+ void dumpFrom(uint32_t fromUnixSeconds, TmFunnelBase& tmFunnel);
+ void dumpFromUpTo(uint32_t fromUnixSeconds, uint32_t upToUnixSeconds, TmFunnelBase& tmFunnel);
+
+ ReturnValue_t passPacket(PusTmReader& reader);
+
+ private:
+ static constexpr uint8_t MAX_FILES_IN_ONE_SECOND = 10;
+ static constexpr size_t MAX_FILESIZE = 8192;
+ // ISO8601 timestamp.
+ static constexpr char FILE_DATE_FORMAT[] = "%FT%H%M%SZ";
+
+ MessageQueueIF* tcQueue;
+ PacketFilter filter;
+ CdsShortTimeStamper timeReader;
+ bool baseDirUninitialized = true;
+ const char* baseDir;
+ std::string baseName;
+ uint8_t currentSameSecNumber = 0;
+ std::filesystem::path basePath;
+ uint32_t rolloverDiffSeconds = 0;
+ std::array fileBuf{};
+ timeval currentTv;
+ timeval activeFileTv{};
+ std::optional activeFile;
+ SdCardMountedIF& sdcMan;
+ StorageManagerIF& tmStore;
+
+ /**
+ * To get the queue where commands shall be sent.
+ * @return Id of command queue.
+ */
+ [[nodiscard]] MessageQueueId_t getCommandQueue() const override;
+
+ void calcDiffSeconds(RolloverInterval intervalUnit, uint32_t intervalCount);
+ ReturnValue_t createMostRecentFile(std::optional suffix);
+ static ReturnValue_t pathToTm(const std::filesystem::path& path, struct tm& time);
+ void fileToPackets(const std::filesystem::path& path, uint32_t unixStamp, TmFunnelBase& funnel);
+ bool updateBaseDir();
+ ReturnValue_t assignAndOrCreateMostRecentFile();
+ ReturnValue_t storePacket(PusTmReader& reader);
+};
+
+#endif /* MISSION_TMTC_TMSTOREBACKEND_H_ */
diff --git a/mission/tmtc/PusTmFunnel.cpp b/mission/tmtc/PusTmFunnel.cpp
index 974cdca0..08a047a0 100644
--- a/mission/tmtc/PusTmFunnel.cpp
+++ b/mission/tmtc/PusTmFunnel.cpp
@@ -1,22 +1,87 @@
#include "PusTmFunnel.h"
+#include "eive/definitions.h"
+#include "eive/objects.h"
+#include "fsfw/ipc/CommandMessage.h"
#include "fsfw/ipc/QueueFactory.h"
#include "fsfw/objectmanager.h"
+#include "fsfw/pus/Service5EventReporting.h"
+#include "fsfw/tmstorage/TmStoreMessage.h"
#include "fsfw/tmtcpacket/pus/tm/PusTmZcWriter.h"
+#include "tmtc/pusIds.h"
-PusTmFunnel::PusTmFunnel(object_id_t objectId, TimeReaderIF &timeReader, StorageManagerIF &tmStore,
- uint32_t messageDepth)
- : TmFunnelBase(objectId, tmStore, messageDepth), timeReader(timeReader) {}
+PusTmFunnel::PusTmFunnel(TmFunnelBase::FunnelCfg cfg, TimeReaderIF &timeReader,
+ SdCardMountedIF &sdcMan)
+ : TmFunnelBase(cfg),
+ timeReader(timeReader),
+ miscStore(objects::MISC_TM_STORE, "tm", "misc", RolloverInterval::HOURLY, 2, tmStore, sdcMan),
+ okStore(objects::OK_TM_STORE, "tm", "ok", RolloverInterval::MINUTELY, 30, tmStore, sdcMan),
+ notOkStore(objects::NOT_OK_TM_STORE, "tm", "nok", RolloverInterval::MINUTELY, 30, tmStore,
+ sdcMan),
+ hkStore(objects::HK_TM_STORE, "tm", "hk", RolloverInterval::MINUTELY, 15, tmStore, sdcMan),
+ sdcMan(sdcMan) {
+ Clock::getClock_timeval(¤tTv);
+ Clock::getUptime(&lastTvUpdate);
+ hkStore.addApid(config::EIVE_PUS_APID);
+ hkStore.addService(pus::PUS_SERVICE_3);
+ miscStore.addApid(config::EIVE_PUS_APID);
+ miscStore.addService(pus::PUS_SERVICE_17);
+ miscStore.addService(pus::PUS_SERVICE_2);
+ miscStore.addService(pus::PUS_SERVICE_200);
+ miscStore.addService(pus::PUS_SERVICE_201);
+ miscStore.addService(pus::PUS_SERVICE_9);
+ miscStore.addService(pus::PUS_SERVICE_20);
+ okStore.addApid(config::EIVE_PUS_APID);
+ okStore.addServiceSubservice(pus::PUS_SERVICE_5,
+ Service5EventReporting::Subservice::NORMAL_REPORT);
+ okStore.addService(pus::PUS_SERVICE_8);
+ okStore.addServiceSubservice(pus::PUS_SERVICE_1, 1);
+ okStore.addServiceSubservice(pus::PUS_SERVICE_1, 3);
+ okStore.addServiceSubservice(pus::PUS_SERVICE_1, 5);
+ okStore.addServiceSubservice(pus::PUS_SERVICE_1, 7);
+ notOkStore.addApid(config::EIVE_PUS_APID);
+ notOkStore.addServiceSubservice(pus::PUS_SERVICE_5, 2);
+ notOkStore.addServiceSubservice(pus::PUS_SERVICE_5, 3);
+ notOkStore.addServiceSubservice(pus::PUS_SERVICE_5, 4);
+ notOkStore.addServiceSubservice(pus::PUS_SERVICE_1, 2);
+ notOkStore.addServiceSubservice(pus::PUS_SERVICE_1, 4);
+ notOkStore.addServiceSubservice(pus::PUS_SERVICE_1, 6);
+ notOkStore.addServiceSubservice(pus::PUS_SERVICE_1, 8);
+}
PusTmFunnel::~PusTmFunnel() = default;
ReturnValue_t PusTmFunnel::performOperation(uint8_t) {
+ CommandMessage cmdMessage;
+ ReturnValue_t result;
+ try {
+ result = okStore.handleCommandQueue(ipcStore, *this);
+ if (result != returnvalue::OK) {
+ sif::error << "PusTmFunnel::performOperation: Issue handling OK store command" << std::endl;
+ }
+ result = notOkStore.handleCommandQueue(ipcStore, *this);
+ if (result != returnvalue::OK) {
+ sif::error << "PusTmFunnel::performOperation: Issue handling NOT OK store command"
+ << std::endl;
+ }
+ result = hkStore.handleCommandQueue(ipcStore, *this);
+ if (result != returnvalue::OK) {
+ sif::error << "PusTmFunnel::performOperation: Issue handling HK store command" << std::endl;
+ }
+ result = miscStore.handleCommandQueue(ipcStore, *this);
+ if (result != returnvalue::OK) {
+ sif::error << "PusTmFunnel::performOperation: Issue handling MISC store command" << std::endl;
+ }
+ } catch (const std::bad_optional_access &e) {
+ sif::error << e.what() << "when handling TM store command" << std::endl;
+ }
+
TmTcMessage currentMessage;
unsigned int count = 0;
- ReturnValue_t status = tmQueue->receiveMessage(¤tMessage);
- while (status == returnvalue::OK) {
- status = handlePacket(currentMessage);
- if (status != returnvalue::OK) {
+ result = tmQueue->receiveMessage(¤tMessage);
+ while (result == returnvalue::OK) {
+ result = handleTmPacket(currentMessage);
+ if (result != returnvalue::OK) {
sif::warning << "TmFunnel packet handling failed" << std::endl;
break;
}
@@ -25,16 +90,16 @@ ReturnValue_t PusTmFunnel::performOperation(uint8_t) {
sif::error << "PusTmFunnel: Possible message storm detected" << std::endl;
break;
}
- status = tmQueue->receiveMessage(¤tMessage);
+ result = tmQueue->receiveMessage(¤tMessage);
}
- if (status == MessageQueueIF::EMPTY) {
+ if (result == MessageQueueIF::EMPTY) {
return returnvalue::OK;
}
- return status;
+ return result;
}
-ReturnValue_t PusTmFunnel::handlePacket(TmTcMessage &message) {
+ReturnValue_t PusTmFunnel::handleTmPacket(TmTcMessage &message) {
uint8_t *packetData = nullptr;
size_t size = 0;
store_address_t origStoreId = message.getStorageId();
@@ -54,36 +119,38 @@ ReturnValue_t PusTmFunnel::handlePacket(TmTcMessage &message) {
sourceSequenceCount = sourceSequenceCount % ccsds::LIMIT_SEQUENCE_COUNT;
packet.updateErrorControl();
- for (unsigned int idx = 0; idx < destinations.size(); idx++) {
- const auto &dest = destinations[idx];
- if (destinations.size() > 1) {
- if (idx < destinations.size() - 1) {
- // Create copy of data to ensure each TM recipient has its own copy. That way, we don't need
- // to bother with send order and where the data is deleted.
- store_address_t storeId;
- result = tmStore.addData(&storeId, packetData, size);
- if (result == returnvalue::OK) {
- message.setStorageId(storeId);
- } else {
-#if FSFW_CPP_OSTREAM_ENABLED == 1
- sif::error << "PusTmFunnel::handlePacket: Store too full to create data copy"
- << std::endl;
-#endif
- }
- } else {
- message.setStorageId(origStoreId);
- }
- }
- result = tmQueue->sendMessage(dest.queueId, &message);
- if (result != returnvalue::OK) {
-#if FSFW_CPP_OSTREAM_ENABLED == 1
- sif::error << "PusTmFunnel::handlePacket: Error sending TM to downlink handler " << dest.name
- << " failed" << std::endl;
-#endif
- tmStore.deleteData(message.getStorageId());
- }
+ timeval currentUptime{};
+ Clock::getUptime(¤tUptime);
+ if (currentUptime.tv_sec - lastTvUpdate.tv_sec >
+ static_cast(TV_UPDATE_INTERVAL_SECS)) {
+ Clock::getClock_timeval(¤tTv);
+ lastTvUpdate = currentUptime;
}
- return result;
+
+ bool sdcUsable = sdcMan.isSdCardUsable(std::nullopt);
+ initStoresIfPossible(sdcUsable);
+ if (sdcUsable) {
+ miscStore.passPacket(packet);
+ okStore.passPacket(packet);
+ notOkStore.passPacket(packet);
+ hkStore.passPacket(packet);
+ }
+ return sendPacketToDestinations(origStoreId, message, packetData, size);
}
const char *PusTmFunnel::getName() const { return "PUS TM Funnel"; }
+
+void PusTmFunnel::initStoresIfPossible(bool sdCardUsable) {
+ if (not storesInitialized and sdCardUsable and sdcMan.getCurrentMountPrefix() != nullptr) {
+ miscStore.initializeTmStore();
+ okStore.initializeTmStore();
+ hkStore.initializeTmStore();
+ notOkStore.initializeTmStore();
+ storesInitialized = true;
+ }
+}
+
+ReturnValue_t PusTmFunnel::initialize() {
+ initStoresIfPossible(sdcMan.isSdCardUsable(std::nullopt));
+ return returnvalue::OK;
+}
diff --git a/mission/tmtc/PusTmFunnel.h b/mission/tmtc/PusTmFunnel.h
index ca9a6016..ab6a9480 100644
--- a/mission/tmtc/PusTmFunnel.h
+++ b/mission/tmtc/PusTmFunnel.h
@@ -10,33 +10,43 @@
#include
+#include "PersistentTmStore.h"
+#include "fsfw/ipc/CommandMessage.h"
#include "fsfw/timemanager/TimeReaderIF.h"
/**
* @brief TM Recipient.
* @details
- * TODO: Add support for TM storage by using the (or a) LIVE flag provided by the CCSDS or Syrlinks
- * handler. If we are in LIVE TM mode, forward TM to downlink destination directly. Otherwise,
- * forward to TM storage backend which stores TMs into files.
- * Main telemetry receiver. All generated telemetry is funneled into
- * this object.
+ * Main telemetry receiver. All generated telemetry is funneled into this object.
* @ingroup utility
* @author J. Meier, R. Mueller
*/
class PusTmFunnel : public TmFunnelBase {
public:
- explicit PusTmFunnel(object_id_t objectId, TimeReaderIF &timeReader, StorageManagerIF &tmStore,
- uint32_t messageDepth = 10);
+ PusTmFunnel(TmFunnelBase::FunnelCfg cfg, TimeReaderIF &timeReader, SdCardMountedIF &sdcMan);
[[nodiscard]] const char *getName() const override;
~PusTmFunnel() override;
ReturnValue_t performOperation(uint8_t operationCode);
private:
+ // Update TV stamp every 5 minutes
+ static constexpr dur_millis_t TV_UPDATE_INTERVAL_SECS = 60 * 5;
+
uint16_t sourceSequenceCount = 0;
TimeReaderIF &timeReader;
+ bool storesInitialized = false;
+ timeval currentTv{};
+ timeval lastTvUpdate{};
+ PersistentTmStore miscStore;
+ PersistentTmStore okStore;
+ PersistentTmStore notOkStore;
+ PersistentTmStore hkStore;
+ SdCardMountedIF &sdcMan;
- ReturnValue_t handlePacket(TmTcMessage &message);
+ ReturnValue_t handleTmPacket(TmTcMessage &message);
+ void initStoresIfPossible(bool sdCardUsable);
+ ReturnValue_t initialize() override;
};
#endif // FSFW_EXAMPLE_COMMON_PUSTMFUNNEL_H
diff --git a/mission/tmtc/Service15TmStorage.cpp b/mission/tmtc/Service15TmStorage.cpp
new file mode 100644
index 00000000..1c9b8611
--- /dev/null
+++ b/mission/tmtc/Service15TmStorage.cpp
@@ -0,0 +1,85 @@
+#include "Service15TmStorage.h"
+
+#include
+#include
+
+#include "eive/objects.h"
+#include "fsfw/tmstorage/TmStoreMessage.h"
+
+using namespace returnvalue;
+
+Service15TmStorage::Service15TmStorage(object_id_t objectId, uint16_t apid,
+ uint8_t numParallelCommands, uint16_t commandTimeoutSecs,
+ size_t queueDepth)
+ : CommandingServiceBase(objectId, apid, "PUS Service 15", 15, numParallelCommands,
+ commandTimeoutSecs, queueDepth) {}
+
+ReturnValue_t Service15TmStorage::isValidSubservice(uint8_t subservice) {
+ switch (subservice) {
+ case (Subservices::DELETE_UP_TO):
+ case (Subservices::START_BY_TIME_RANGE_RETRIEVAL): {
+ return OK;
+ }
+ default: {
+ return FAILED;
+ }
+ }
+}
+
+ReturnValue_t Service15TmStorage::getMessageQueueAndObject(uint8_t subservice,
+ const uint8_t *tcData, size_t tcDataLen,
+ MessageQueueId_t *id,
+ object_id_t *objectId) {
+ if (tcDataLen < 4) {
+ return CommandingServiceBase::INVALID_TC;
+ }
+ SerializeAdapter::deSerialize(objectId, &tcData, &tcDataLen, SerializeIF::Endianness::NETWORK);
+ auto *frontendIF = ObjectManager::instance()->get(*objectId);
+ if (frontendIF == nullptr) {
+ return CommandingServiceBase::INVALID_OBJECT;
+ }
+ *id = frontendIF->getCommandQueue();
+ return OK;
+}
+
+ReturnValue_t Service15TmStorage::prepareCommand(CommandMessage *message, uint8_t subservice,
+ const uint8_t *tcData, size_t tcDataLen,
+ uint32_t *state, object_id_t objectId) {
+ if (subservice == Subservices::START_BY_TIME_RANGE_RETRIEVAL) {
+ // TODO: Hardcoded to UNIX timestamps.. Should allow arbitrary timestamp and let receiver
+ // to time reading and reply handling
+ if (tcDataLen != 12) {
+ return INVALID_TC;
+ }
+ store_address_t storeId;
+ ReturnValue_t result = ipcStore->addData(&storeId, tcData + 4, tcDataLen - 4);
+ if (result != OK) {
+ return result;
+ }
+ // Store timestamps
+ TmStoreMessage::setDownlinkContentTimeMessage(message, storeId);
+ return CommandingServiceBase::EXECUTION_COMPLETE;
+ } else if (subservice == Subservices::DELETE_UP_TO) {
+ // TODO: Hardcoded to UNIX timestamps.. Should allow arbitrary timestamp and let receiver
+ // to time reading and reply handling
+ if (tcDataLen != 8) {
+ return INVALID_TC;
+ }
+ store_address_t storeId;
+ ReturnValue_t result = ipcStore->addData(&storeId, tcData + 4, tcDataLen - 4);
+ if (result != OK) {
+ return result;
+ }
+ // Store timestamps
+ TmStoreMessage::setDeleteContentTimeMessage(message, storeId);
+ return CommandingServiceBase::EXECUTION_COMPLETE;
+ }
+ return OK;
+}
+
+ReturnValue_t Service15TmStorage::handleReply(const CommandMessage *reply,
+ Command_t previousCommand, uint32_t *state,
+ CommandMessage *optionalNextCommand,
+ object_id_t objectId, bool *isStep) {
+ return OK;
+}
diff --git a/mission/tmtc/Service15TmStorage.h b/mission/tmtc/Service15TmStorage.h
new file mode 100644
index 00000000..33be0634
--- /dev/null
+++ b/mission/tmtc/Service15TmStorage.h
@@ -0,0 +1,24 @@
+#ifndef MISSION_TMTC_SERVICE15TMSTORAGE_H_
+#define MISSION_TMTC_SERVICE15TMSTORAGE_H_
+
+#include
+
+class Service15TmStorage : public CommandingServiceBase {
+ public:
+ enum Subservices : uint8_t { START_BY_TIME_RANGE_RETRIEVAL = 9, DELETE_UP_TO = 11 };
+ explicit Service15TmStorage(object_id_t objectId, uint16_t apid, uint8_t numParallelCommands,
+ uint16_t commandTimeoutSecs = 60, size_t queueDepth = 10);
+
+ private:
+ ReturnValue_t isValidSubservice(uint8_t subservice) override;
+ ReturnValue_t getMessageQueueAndObject(uint8_t subservice, const uint8_t* tcData,
+ size_t tcDataLen, MessageQueueId_t* id,
+ object_id_t* objectId) override;
+ ReturnValue_t prepareCommand(CommandMessage* message, uint8_t subservice, const uint8_t* tcData,
+ size_t tcDataLen, uint32_t* state, object_id_t objectId) override;
+ ReturnValue_t handleReply(const CommandMessage* reply, Command_t previousCommand, uint32_t* state,
+ CommandMessage* optionalNextCommand, object_id_t objectId,
+ bool* isStep) override;
+};
+
+#endif /* MISSION_TMTC_SERVICE15TMSTORAGE_H_ */
diff --git a/mission/tmtc/TmFunnelBase.cpp b/mission/tmtc/TmFunnelBase.cpp
index 51bf93a1..bbb5bcc3 100644
--- a/mission/tmtc/TmFunnelBase.cpp
+++ b/mission/tmtc/TmFunnelBase.cpp
@@ -1,10 +1,12 @@
#include "TmFunnelBase.h"
+#include
+
#include "fsfw/ipc/QueueFactory.h"
-TmFunnelBase::TmFunnelBase(object_id_t objectId, StorageManagerIF &tmStore, uint32_t tmMsgDepth)
- : SystemObject(objectId), tmStore(tmStore) {
- tmQueue = QueueFactory::instance()->createMessageQueue(tmMsgDepth);
+TmFunnelBase::TmFunnelBase(FunnelCfg cfg)
+ : SystemObject(cfg.objectId), tmStore(cfg.tmStore), ipcStore(cfg.ipcStore) {
+ tmQueue = QueueFactory::instance()->createMessageQueue(cfg.tmMsgDepth);
}
TmFunnelBase::~TmFunnelBase() { QueueFactory::instance()->deleteMessageQueue(tmQueue); }
@@ -18,3 +20,38 @@ void TmFunnelBase::addDestination(const char *name, const AcceptsTelemetryIF &do
auto queueId = downlinkDestination.getReportReceptionQueue(vcid);
destinations.emplace_back(name, queueId, vcid);
}
+
+ReturnValue_t TmFunnelBase::sendPacketToDestinations(store_address_t origStoreId,
+ TmTcMessage &message,
+ const uint8_t *packetData, size_t size) {
+ ReturnValue_t result;
+ for (unsigned int idx = 0; idx < destinations.size(); idx++) {
+ const auto &dest = destinations[idx];
+ if (destinations.size() > 1) {
+ if (idx < destinations.size() - 1) {
+ // Create copy of data to ensure each TM recipient has its own copy. That way, we don't need
+ // to bother with send order and where the data is deleted.
+ store_address_t storeId;
+ result = tmStore.addData(&storeId, packetData, size);
+ if (result == returnvalue::OK) {
+ message.setStorageId(storeId);
+ } else {
+#if FSFW_CPP_OSTREAM_ENABLED == 1
+ sif::error << "PusTmFunnel::handlePacket: Store too full to create data copy"
+ << std::endl;
+#endif
+ }
+ } else {
+ message.setStorageId(origStoreId);
+ }
+ }
+ result = tmQueue->sendMessage(dest.queueId, &message);
+ if (result != returnvalue::OK) {
+#if FSFW_CPP_OSTREAM_ENABLED == 1
+ sif::error << "PusTmFunnel::handlePacket: Error sending TM to downlink handler" << std::endl;
+#endif
+ tmStore.deleteData(message.getStorageId());
+ }
+ }
+ return result;
+}
diff --git a/mission/tmtc/TmFunnelBase.h b/mission/tmtc/TmFunnelBase.h
index 408244dd..af65771f 100644
--- a/mission/tmtc/TmFunnelBase.h
+++ b/mission/tmtc/TmFunnelBase.h
@@ -3,21 +3,36 @@
#include
#include
+#include
#include
+#include
#include
class TmFunnelBase : public AcceptsTelemetryIF, public SystemObject {
public:
- TmFunnelBase(object_id_t objectId, StorageManagerIF& tmStore, uint32_t tmMsgDepth);
+ struct FunnelCfg {
+ FunnelCfg(object_id_t objId, StorageManagerIF& tmStore, StorageManagerIF& ipcStore,
+ uint32_t tmMsgDepth)
+ : objectId(objId), tmStore(tmStore), ipcStore(ipcStore), tmMsgDepth(tmMsgDepth) {}
+ object_id_t objectId;
+ StorageManagerIF& tmStore;
+ StorageManagerIF& ipcStore;
+ uint32_t tmMsgDepth;
+ };
+ explicit TmFunnelBase(FunnelCfg cfg);
void addDestination(const char* name, const AcceptsTelemetryIF& downlinkDestination,
uint8_t vcid = 0);
+ ReturnValue_t sendPacketToDestinations(store_address_t origStoreId, TmTcMessage& message,
+ const uint8_t* packetData, size_t size);
[[nodiscard]] MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel) const override;
- virtual ~TmFunnelBase();
+ ~TmFunnelBase() override;
protected:
StorageManagerIF& tmStore;
+ StorageManagerIF& ipcStore;
+
struct Destination {
Destination(const char* name, MessageQueueId_t queueId, uint8_t virtualChannel)
: name(name), queueId(queueId), virtualChannel(virtualChannel) {}
diff --git a/mission/utility/CMakeLists.txt b/mission/utility/CMakeLists.txt
index e2459ed1..dadce33f 100644
--- a/mission/utility/CMakeLists.txt
+++ b/mission/utility/CMakeLists.txt
@@ -1,3 +1,3 @@
target_sources(
${LIB_EIVE_MISSION} PRIVATE Timestamp.cpp ProgressPrinter.cpp Filenaming.cpp
- GlobalConfigHandler.cpp)
+ GlobalConfigHandler.cpp DummySdCardManager.cpp)
diff --git a/mission/utility/DummySdCardManager.cpp b/mission/utility/DummySdCardManager.cpp
new file mode 100644
index 00000000..17d7ba2b
--- /dev/null
+++ b/mission/utility/DummySdCardManager.cpp
@@ -0,0 +1,13 @@
+#include "DummySdCardManager.h"
+
+DummySdCardManager::DummySdCardManager(std::string prefix) : prefix(std::move(prefix)) {}
+
+const char* DummySdCardManager::getCurrentMountPrefix() const { return prefix.c_str(); }
+
+bool DummySdCardManager::isSdCardUsable(std::optional sdCard) { return true; }
+
+std::optional DummySdCardManager::getPreferredSdCard() const { return std::nullopt; }
+
+void DummySdCardManager::setActiveSdCard(sd::SdCard sdCard) {}
+
+std::optional DummySdCardManager::getActiveSdCard() const { return std::nullopt; }
diff --git a/bsp_linux_board/RPiSdCardManager.h b/mission/utility/DummySdCardManager.h
similarity index 65%
rename from bsp_linux_board/RPiSdCardManager.h
rename to mission/utility/DummySdCardManager.h
index 068471c1..4c985056 100644
--- a/bsp_linux_board/RPiSdCardManager.h
+++ b/mission/utility/DummySdCardManager.h
@@ -2,11 +2,11 @@
#define BSP_LINUX_BOARD_RPISDCARDMANAGER_H_
#include
-class RPiSdCardManager : public SdCardMountedIF {
+class DummySdCardManager : public SdCardMountedIF {
public:
- RPiSdCardManager(std::string prefix);
- const std::string& getCurrentMountPrefix() const override;
- bool isSdCardUsable(sd::SdCard sdCard) override;
+ DummySdCardManager(std::string prefix);
+ const char* getCurrentMountPrefix() const override;
+ bool isSdCardUsable(std::optional sdCard) override;
std::optional getPreferredSdCard() const override;
void setActiveSdCard(sd::SdCard sdCard) override;
std::optional getActiveSdCard() const override;
diff --git a/release_checklist.md b/release_checklist.md
index b4f08165..2e0247c7 100644
--- a/release_checklist.md
+++ b/release_checklist.md
@@ -4,8 +4,10 @@ OBSW Release Checklist
# Pre-Release
1. Update version in `CMakeLists.txt`
-2. Verify that the Q7S, Q7S EM and Host build are working
-3. Wait for CI/CD results
+2. Re-run the auto-formatters with the `scripts/auto-formatter.sh` script
+3. Re-run the generators with `generators/gen.py all`
+4. Verify that the Q7S, Q7S EM and Host build are working
+5. Wait for CI/CD results
# Post-Release
diff --git a/tmtc b/tmtc
index 24f0d8e1..13014eb2 160000
--- a/tmtc
+++ b/tmtc
@@ -1 +1 @@
-Subproject commit 24f0d8e1a6a8ea1323623932e699326214c78159
+Subproject commit 13014eb25053368f4fb9a445788aba71ff98de19
diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt
index 2ff542fd..20b98979 100644
--- a/unittest/CMakeLists.txt
+++ b/unittest/CMakeLists.txt
@@ -4,6 +4,7 @@ add_subdirectory(mocks)
target_sources(${UNITTEST_NAME} PRIVATE
main.cpp
testEnvironment.cpp
+ testStampInFilename.cpp
hdlcEncodingRw.cpp
printChar.cpp
)
\ No newline at end of file
diff --git a/unittest/testStampInFilename.cpp b/unittest/testStampInFilename.cpp
new file mode 100644
index 00000000..c66bdce6
--- /dev/null
+++ b/unittest/testStampInFilename.cpp
@@ -0,0 +1,21 @@
+
+#include
+#include
+
+#include "fsfw/timemanager/Clock.h"
+
+TEST_CASE("Stamp in Filename", "[Stamp In Filename]") {
+ Clock::TimeOfDay_t tod;
+ std::string baseName = "verif";
+ std::string pathStr = "verif_2022-05-25T16:55:23Z.bin";
+ unsigned int underscorePos = pathStr.find_last_of('_');
+ std::string stampStr = pathStr.substr(underscorePos + 1);
+ float seconds = 0.0;
+ char* prefix = nullptr;
+ int count =
+ sscanf(stampStr.c_str(),
+ "%4" SCNu32 "-%2" SCNu32 "-%2" SCNu32 "T%2" SCNu32 ":%2" SCNu32 ":%2" SCNu32 "Z",
+ &tod.year, &tod.month, &tod.day, &tod.hour, &tod.minute, &tod.second);
+ static_cast(count);
+ CHECK(count == 6);
+}