PDEC Config Persistent #398
7
.gitignore
vendored
7
.gitignore
vendored
@ -12,8 +12,13 @@
|
||||
#vscode
|
||||
/.vscode
|
||||
|
||||
# IntelliJ
|
||||
/.idea/*
|
||||
|
||||
# Python
|
||||
__pycache__
|
||||
.idea
|
||||
|
||||
# CLion
|
||||
!/.idea/cmake.xml
|
||||
|
||||
generators/*.db
|
||||
|
10
.run/Q7S FM.run.xml
Normal file
10
.run/Q7S FM.run.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Q7S FM" type="com.jetbrains.cidr.remote.gdbserver.type" factoryName="com.jetbrains.cidr.remote.gdbserver.factory" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="eive-obsw" TARGET_NAME="eive-obsw" CONFIG_NAME="Debug" version="1" RUN_TARGET_PROJECT_NAME="eive-obsw" RUN_TARGET_NAME="eive-obsw">
|
||||
<custom-gdb-server version="1" gdb-connect="localhost:1234" executable="" warmup-ms="0" download-type="NONE" sshConfigName="Q7S FM" uploadFile="/tmp/eive-obsw" defaultGdbServerArgs=":1234 /tmp/eive-obsw">
|
||||
<debugger kind="GDB" isBundled="true" />
|
||||
</custom-gdb-server>
|
||||
<method v="2">
|
||||
<option name="CLION.COMPOUND.BUILD" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
42
CHANGELOG.md
42
CHANGELOG.md
@ -18,7 +18,49 @@ will consitute of a breaking change warranting a new major release:
|
||||
|
||||
## Fixed
|
||||
|
||||
- Linux GPS handler now checks the individual `*_SET` flags when analysing the `gpsd` struct.
|
||||
PR: https://egit.irs.uni-stuttgart.de/eive/eive-obsw/pulls/400
|
||||
|
||||
# [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]
|
||||
|
||||
|
@ -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.
|
||||
|
17
README.md
17
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=..
|
||||
```
|
||||
|
||||
# <a id="CLion"></a> 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`
|
||||
|
||||
# <a id="eclipse"></a> Eclipse
|
||||
|
||||
When using Eclipse, there are two special build variables in the project properties
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <mission/tmtc/TmFunnelHandler.h>
|
||||
#include <objects/systemObjectList.h>
|
||||
|
||||
#include "../mission/utility/DummySdCardManager.h"
|
||||
#include "OBSWConfig.h"
|
||||
#include "fsfw/platform.h"
|
||||
#include "fsfw_tests/integration/task/TestTask.h"
|
||||
@ -57,7 +58,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);
|
||||
|
@ -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";
|
||||
|
@ -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:
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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<sd::SdCard> RPiSdCardManager::getPreferredSdCard() const { return std::nullopt; }
|
||||
|
||||
void RPiSdCardManager::setActiveSdCard(sd::SdCard sdCard) {}
|
||||
|
||||
std::optional<sd::SdCard> RPiSdCardManager::getActiveSdCard() const { return std::nullopt; }
|
@ -49,6 +49,8 @@ CoreController::CoreController(object_id_t objectId)
|
||||
}
|
||||
|
||||
getCurrentBootCopy(CURRENT_CHIP, CURRENT_COPY);
|
||||
|
||||
initClockFromTimeFile();
|
||||
} catch (const std::filesystem::filesystem_error &e) {
|
||||
sif::error << "CoreController::CoreController: Failed with exception " << e.what() << std::endl;
|
||||
}
|
||||
@ -159,6 +161,9 @@ ReturnValue_t CoreController::initializeAfterTaskCreation() {
|
||||
}
|
||||
sdcMan->setActiveSdCard(sdInfo.active);
|
||||
currMntPrefix = sdcMan->getCurrentMountPrefix();
|
||||
if (currMntPrefix == "") {
|
||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||
}
|
||||
if (BLOCKING_SD_INIT) {
|
||||
result = initSdCardBlocking();
|
||||
if (result != returnvalue::OK and result != SdCardManager::ALREADY_MOUNTED) {
|
||||
@ -1266,10 +1271,12 @@ void CoreController::performMountedSdCardOperations() {
|
||||
if (result != returnvalue::OK) {
|
||||
sif::warning << "CoreController::CoreController: Boot copy init" << std::endl;
|
||||
}
|
||||
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)) {
|
||||
@ -1783,7 +1790,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()) {
|
||||
@ -1793,14 +1800,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;
|
||||
}
|
||||
@ -1808,8 +1815,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);
|
||||
@ -1837,6 +1844,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;
|
||||
|
@ -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;
|
||||
// Designated value for rechecking FIFO open
|
||||
@ -221,6 +223,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
|
||||
@ -258,7 +261,7 @@ class CoreController : public ExtendedControllerBase {
|
||||
|
||||
ReturnValue_t initClockFromTimeFile();
|
||||
ReturnValue_t performSdCardCheck();
|
||||
ReturnValue_t timeFileHandler();
|
||||
ReturnValue_t backupTimeFileHandler();
|
||||
ReturnValue_t initBootCopyFile();
|
||||
ReturnValue_t initWatchdogFifo();
|
||||
ReturnValue_t initSdCardBlocking();
|
||||
|
@ -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();
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <fsfw/power/DummyPowerSwitcher.h>
|
||||
#include <mission/devices/devicedefinitions/GomspaceDefinitions.h>
|
||||
#include <mission/system/tree/system.h>
|
||||
#include <mission/utility/DummySdCardManager.h>
|
||||
|
||||
#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;
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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<std::string> currentPrefix;
|
||||
|
||||
static SdCardManager* INSTANCE;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -38,6 +38,7 @@ enum : uint8_t {
|
||||
CORE = 140,
|
||||
TCS_CONTROLLER = 141,
|
||||
COM_SUBSYSTEM = 142,
|
||||
PERSISTENT_TM_STORE = 143,
|
||||
COMMON_SUBSYSTEM_ID_END
|
||||
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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_ */
|
||||
|
@ -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,
|
||||
|
@ -20,6 +20,7 @@ target_sources(
|
||||
GyroL3GD20Dummy.cpp
|
||||
MgmLIS3MDLDummy.cpp
|
||||
PlPcduDummy.cpp
|
||||
ExecutableComIfDummy.cpp
|
||||
ScexDummy.cpp
|
||||
CoreControllerDummy.cpp
|
||||
PlocMpsocDummy.cpp
|
||||
|
27
dummies/ExecutableComIfDummy.cpp
Normal file
27
dummies/ExecutableComIfDummy.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include <dummies/ExecutableComIfDummy.h>
|
||||
|
||||
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;
|
||||
}
|
21
dummies/ExecutableComIfDummy.h
Normal file
21
dummies/ExecutableComIfDummy.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef DUMMIES_EXECUTABLECOMIFDUMMY_H_
|
||||
#define DUMMIES_EXECUTABLECOMIFDUMMY_H_
|
||||
|
||||
#include <fsfw/devicehandlers/DeviceCommunicationIF.h>
|
||||
#include <fsfw/objectmanager/SystemObject.h>
|
||||
#include <fsfw/tasks/ExecutableObjectIF.h>
|
||||
|
||||
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_ */
|
@ -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<double>({537222.3469}, true));
|
||||
localDataPoolMap.emplace(GpsHyperion::LONGITUDE, new PoolEntry<double>({-8.8579}, true));
|
||||
localDataPoolMap.emplace(GpsHyperion::LATITUDE, new PoolEntry<double>({49.5952}, true));
|
||||
localDataPoolMap.emplace(GpsHyperion::SPEED, new PoolEntry<double>({0}));
|
||||
localDataPoolMap.emplace(GpsHyperion::YEAR, new PoolEntry<uint16_t>({2023}, true));
|
||||
localDataPoolMap.emplace(GpsHyperion::MONTH, new PoolEntry<uint8_t>({5}, true));
|
||||
localDataPoolMap.emplace(GpsHyperion::DAY, new PoolEntry<uint8_t>({16}, true));
|
||||
localDataPoolMap.emplace(GpsHyperion::HOURS, new PoolEntry<uint8_t>({1}, true));
|
||||
localDataPoolMap.emplace(GpsHyperion::MINUTES, new PoolEntry<uint8_t>({0}, true));
|
||||
localDataPoolMap.emplace(GpsHyperion::SECONDS, new PoolEntry<uint8_t>({0}, true));
|
||||
localDataPoolMap.emplace(GpsHyperion::UNIX_SECONDS, new PoolEntry<uint32_t>({1684191600}, true));
|
||||
localDataPoolMap.emplace(GpsHyperion::SATS_IN_USE, new PoolEntry<uint8_t>());
|
||||
localDataPoolMap.emplace(GpsHyperion::SATS_IN_VIEW, new PoolEntry<uint8_t>());
|
||||
localDataPoolMap.emplace(GpsHyperion::FIX_MODE, new PoolEntry<uint8_t>());
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
LocalPoolDataSetBase* GpsCtrlDummy::getDataSetHandle(sid_t sid) { return nullptr; }
|
||||
|
@ -2,12 +2,15 @@
|
||||
#define DUMMIES_GPSCTRLDUMMY_H_
|
||||
|
||||
#include <fsfw/controller/ExtendedControllerBase.h>
|
||||
#include <mission/devices/devicedefinitions/GPSDefinitions.h>
|
||||
|
||||
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,
|
||||
|
@ -3,7 +3,8 @@
|
||||
#include <mission/devices/devicedefinitions/GomspaceDefinitions.h>
|
||||
|
||||
PduDummy::PduDummy(object_id_t objectId, object_id_t comif, CookieIF *comCookie)
|
||||
: DeviceHandlerBase(objectId, comif, comCookie) {}
|
||||
: DeviceHandlerBase(objectId, comif, comCookie),
|
||||
coreHk(this, static_cast<uint32_t>(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<float>({0}));
|
||||
localDataPoolMap.emplace(PDU::pool::PDU_VOLTAGES, &pduVoltages);
|
||||
localDataPoolMap.emplace(PDU::pool::PDU_CURRENTS, &pduCurrents);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#include <fsfw/devicehandlers/DeviceHandlerBase.h>
|
||||
|
||||
#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<int16_t> pduVoltages = PoolEntry<int16_t>(9);
|
||||
PoolEntry<int16_t> pduCurrents = PoolEntry<int16_t>(9);
|
||||
|
||||
void doStartUp() override;
|
||||
void doShutDown() override;
|
||||
ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t *id) override;
|
||||
|
@ -41,7 +41,7 @@ ReturnValue_t RwDummy::initializeLocalDataPool(localpool::DataPool &localDataPoo
|
||||
|
||||
localDataPoolMap.emplace(rws::CURR_SPEED, new PoolEntry<int32_t>({0}));
|
||||
localDataPoolMap.emplace(rws::REFERENCE_SPEED, new PoolEntry<int32_t>({0}));
|
||||
localDataPoolMap.emplace(rws::STATE, new PoolEntry<uint8_t>({0}));
|
||||
localDataPoolMap.emplace(rws::STATE, new PoolEntry<uint8_t>({1}, true));
|
||||
localDataPoolMap.emplace(rws::CLC_MODE, new PoolEntry<uint8_t>({0}));
|
||||
|
||||
localDataPoolMap.emplace(rws::LAST_RESET_STATUS, new PoolEntry<uint8_t>({0}));
|
||||
|
@ -37,7 +37,7 @@ ReturnValue_t SusDummy::initializeLocalDataPool(localpool::DataPool &localDataPo
|
||||
LocalDataPoolManager &poolManager) {
|
||||
localDataPoolMap.emplace(SUS::SusPoolIds::TEMPERATURE_C, new PoolEntry<float>({0}, 1, true));
|
||||
localDataPoolMap.emplace(SUS::SusPoolIds::CHANNEL_VEC,
|
||||
new PoolEntry<uint16_t>({0, 0, 0, 0, 0, 0}, true));
|
||||
new PoolEntry<uint16_t>({2603, 781, 2760, 2048, 4056, 0}, true));
|
||||
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <dummies/ComCookieDummy.h>
|
||||
#include <dummies/ComIFDummy.h>
|
||||
#include <dummies/CoreControllerDummy.h>
|
||||
#include <dummies/ExecutableComIfDummy.h>
|
||||
#include <dummies/GpsCtrlDummy.h>
|
||||
#include <dummies/GpsDhbDummy.h>
|
||||
#include <dummies/GyroAdisDummy.h>
|
||||
@ -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<object_id_t, 4> rwIds = {objects::RW1, objects::RW2, objects::RW3, objects::RW4};
|
||||
std::array<DeviceHandlerBase*, 4> rws;
|
||||
|
2
fsfw
2
fsfw
@ -1 +1 @@
|
||||
Subproject commit bd208038dd85a94dce8c763397ad5ac7eae76402
|
||||
Subproject commit bdfe31dba48039b60fe700e7d03bfb95e9549688
|
2
generators/.gitignore
vendored
2
generators/.gitignore
vendored
@ -1,2 +1,4 @@
|
||||
.~lock*
|
||||
/venv
|
||||
/.idea/*
|
||||
!/.idea/runConfigurations
|
||||
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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";
|
||||
|
@ -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:
|
||||
|
@ -172,20 +172,10 @@ bool GpsHyperionLinuxController::readGpsDataFromGpsd() {
|
||||
return false;
|
||||
}
|
||||
oneShotSwitches.gpsReadFailedSwitch = true;
|
||||
// did not event get mode, nothing to see.
|
||||
if (MODE_SET != (MODE_SET & gps.set)) {
|
||||
if (mode != MODE_OFF) {
|
||||
if (maxTimeToReachFix.hasTimedOut() and oneShotSwitches.cantGetFixSwitch) {
|
||||
sif::warning
|
||||
<< "GPSHyperionHandler::readGpsDataFromGpsd: No mode could be set in allowed "
|
||||
<< maxTimeToReachFix.timeout / 1000 << " seconds" << std::endl;
|
||||
triggerEvent(GpsHyperion::CANT_GET_FIX, maxTimeToReachFix.timeout);
|
||||
oneShotSwitches.cantGetFixSwitch = false;
|
||||
}
|
||||
// Mode is on, so do next read immediately
|
||||
ReturnValue_t result = handleGpsReadData();
|
||||
if (result == returnvalue::OK) {
|
||||
return true;
|
||||
}
|
||||
// GPS device is off anyway, so do other handling
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
noModeSetCntr = 0;
|
||||
@ -197,11 +187,26 @@ bool GpsHyperionLinuxController::readGpsDataFromGpsd() {
|
||||
"SHM read not implemented"
|
||||
<< std::endl;
|
||||
}
|
||||
handleGpsReadData();
|
||||
return true;
|
||||
}
|
||||
|
||||
ReturnValue_t GpsHyperionLinuxController::handleGpsReadData() {
|
||||
bool modeIsSet = true;
|
||||
if (MODE_SET != (MODE_SET & gps.set)) {
|
||||
if (mode != MODE_OFF) {
|
||||
if (maxTimeToReachFix.hasTimedOut() and oneShotSwitches.cantGetFixSwitch) {
|
||||
sif::warning << "GpsHyperionLinuxController: No mode could be set in allowed "
|
||||
<< maxTimeToReachFix.timeout / 1000 << " seconds" << std::endl;
|
||||
triggerEvent(GpsHyperion::CANT_GET_FIX, maxTimeToReachFix.timeout);
|
||||
oneShotSwitches.cantGetFixSwitch = false;
|
||||
}
|
||||
modeIsSet = false;
|
||||
} else {
|
||||
// GPS device is off anyway, so do other handling
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
PoolReadGuard pg(&gpsSet);
|
||||
if (pg.getReadResult() != returnvalue::OK) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
@ -211,6 +216,7 @@ ReturnValue_t GpsHyperionLinuxController::handleGpsReadData() {
|
||||
}
|
||||
|
||||
bool validFix = false;
|
||||
if (modeIsSet) {
|
||||
// 0: Not seen, 1: No fix, 2: 2D-Fix, 3: 3D-Fix
|
||||
if (gps.fix.mode == 2 or gps.fix.mode == 3) {
|
||||
validFix = true;
|
||||
@ -227,50 +233,76 @@ ReturnValue_t GpsHyperionLinuxController::handleGpsReadData() {
|
||||
}
|
||||
modeCommanded = false;
|
||||
}
|
||||
gpsSet.setValidity(false, true);
|
||||
} else if (gps.satellites_used > 0 && validFix && mode != MODE_OFF) {
|
||||
gpsSet.setValidity(true, true);
|
||||
}
|
||||
}
|
||||
gpsSet.fixMode.setValid(modeIsSet);
|
||||
|
||||
// Only set on specific messages, so only set a valid flag to invalid
|
||||
// if not set for more than a full message set (10 messages here)
|
||||
if (SATELLITE_SET == (SATELLITE_SET & gps.set)) {
|
||||
gpsSet.satInUse.value = gps.satellites_used;
|
||||
gpsSet.satInView.value = gps.satellites_visible;
|
||||
if (not gpsSet.satInUse.isValid()) {
|
||||
gpsSet.satInUse.setValid(true);
|
||||
gpsSet.satInView.setValid(true);
|
||||
}
|
||||
satNotSetCounter = 0;
|
||||
} else {
|
||||
satNotSetCounter++;
|
||||
if (gpsSet.satInUse.isValid() and satNotSetCounter >= 10) {
|
||||
gpsSet.satInUse.setValid(false);
|
||||
gpsSet.satInView.setValid(false);
|
||||
}
|
||||
}
|
||||
|
||||
// LATLON is set for every message, no need for a counter
|
||||
bool latValid = false;
|
||||
bool longValid = false;
|
||||
if (LATLON_SET == (LATLON_SET & gps.set)) {
|
||||
if (std::isfinite(gps.fix.latitude)) {
|
||||
// Negative latitude -> South direction
|
||||
gpsSet.latitude.value = gps.fix.latitude;
|
||||
// As specified in gps.h: Only valid if mode >= 2
|
||||
if (gps.fix.mode >= 2) {
|
||||
latValid = true;
|
||||
}
|
||||
}
|
||||
gpsSet.latitude.setValid(latValid);
|
||||
|
||||
bool longValid = false;
|
||||
if (std::isfinite(gps.fix.longitude)) {
|
||||
// Negative longitude -> West direction
|
||||
gpsSet.longitude.value = gps.fix.longitude;
|
||||
// As specified in gps.h: Only valid if mode >= 2
|
||||
if (gps.fix.mode >= 2) {
|
||||
longValid = true;
|
||||
}
|
||||
}
|
||||
gpsSet.latitude.setValid(longValid);
|
||||
}
|
||||
gpsSet.latitude.setValid(latValid);
|
||||
gpsSet.longitude.setValid(longValid);
|
||||
|
||||
// ALTITUDE is set for every message, no need for a counter
|
||||
bool altitudeValid = false;
|
||||
if (std::isfinite(gps.fix.altitude)) {
|
||||
if (ALTITUDE_SET == (ALTITUDE_SET & gps.set) && std::isfinite(gps.fix.altitude)) {
|
||||
gpsSet.altitude.value = gps.fix.altitude;
|
||||
// As specified in gps.h: Only valid if mode == 3
|
||||
if (gps.fix.mode == 3) {
|
||||
altitudeValid = true;
|
||||
}
|
||||
}
|
||||
gpsSet.altitude.setValid(altitudeValid);
|
||||
|
||||
if (std::isfinite(gps.fix.speed)) {
|
||||
// SPEED is set for every message, no need for a counter
|
||||
bool speedValid = false;
|
||||
if (SPEED_SET == (SPEED_SET & gps.set) && std::isfinite(gps.fix.speed)) {
|
||||
gpsSet.speed.value = gps.fix.speed;
|
||||
} else {
|
||||
gpsSet.speed.setValid(false);
|
||||
speedValid = true;
|
||||
}
|
||||
gpsSet.speed.setValid(speedValid);
|
||||
|
||||
// TIME is set for every message, no need for a counter
|
||||
bool timeValid = false;
|
||||
if (TIME_SET == (TIME_SET & gps.set)) {
|
||||
timeValid = true;
|
||||
timeval time = {};
|
||||
#if LIBGPS_VERSION_MINOR <= 17
|
||||
gpsSet.unixSeconds.value = std::floor(gps.fix.time);
|
||||
@ -294,15 +326,14 @@ ReturnValue_t GpsHyperionLinuxController::handleGpsReadData() {
|
||||
gpsSet.hours = timeOfDay.hour;
|
||||
gpsSet.minutes = timeOfDay.minute;
|
||||
gpsSet.seconds = timeOfDay.second;
|
||||
} else {
|
||||
gpsSet.unixSeconds.setValid(false);
|
||||
gpsSet.year.setValid(false);
|
||||
gpsSet.month.setValid(false);
|
||||
gpsSet.day.setValid(false);
|
||||
gpsSet.hours.setValid(false);
|
||||
gpsSet.minutes.setValid(false);
|
||||
gpsSet.seconds.setValid(false);
|
||||
}
|
||||
gpsSet.unixSeconds.setValid(timeValid);
|
||||
gpsSet.year.setValid(timeValid);
|
||||
gpsSet.month.setValid(timeValid);
|
||||
gpsSet.day.setValid(timeValid);
|
||||
gpsSet.hours.setValid(timeValid);
|
||||
gpsSet.minutes.setValid(timeValid);
|
||||
gpsSet.seconds.setValid(timeValid);
|
||||
|
||||
if (debugHyperionGps) {
|
||||
sif::info << "-- Hyperion GPS Data --" << std::endl;
|
||||
|
@ -61,6 +61,8 @@ class GpsHyperionLinuxController : public ExtendedControllerBase {
|
||||
Countdown maxTimeToReachFix = Countdown(MAX_SECONDS_TO_REACH_FIX * 1000);
|
||||
bool modeCommanded = false;
|
||||
bool timeInit = false;
|
||||
uint8_t satNotSetCounter = 0;
|
||||
|
||||
#if OBSW_THREAD_TRACING == 1
|
||||
uint32_t opCounter = 0;
|
||||
#endif
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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";
|
||||
|
@ -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:
|
||||
|
@ -1,9 +1,8 @@
|
||||
#include "AcsController.h"
|
||||
|
||||
#include <fsfw/datapool/PoolReadGuard.h>
|
||||
|
||||
#include "mission/acsDefs.h"
|
||||
#include "mission/config/torquer.h"
|
||||
#include <mission/acsDefs.h>
|
||||
#include <mission/config/torquer.h>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,17 @@
|
||||
#ifndef MISSION_CONTROLLER_ACSCONTROLLER_H_
|
||||
#define MISSION_CONTROLLER_ACSCONTROLLER_H_
|
||||
|
||||
#include <eive/objects.h>
|
||||
#include <fsfw/controller/ExtendedControllerBase.h>
|
||||
#include <fsfw/globalfunctions/math/VectorOperations.h>
|
||||
#include <fsfw/parameters/ParameterHelper.h>
|
||||
#include <fsfw/parameters/ReceivesParameterMessagesIF.h>
|
||||
#include <fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h>
|
||||
#include <fsfw_hal/devicehandlers/MgmRM3100Handler.h>
|
||||
#include <mission/devices/devicedefinitions/SusDefinitions.h>
|
||||
#include <mission/devices/devicedefinitions/imtqHelpers.h>
|
||||
#include <mission/devices/devicedefinitions/rwHelpers.h>
|
||||
#include <mission/trace.h>
|
||||
|
||||
#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 */
|
||||
|
@ -1,8 +1,3 @@
|
||||
/*******************************
|
||||
* EIVE Flight Software Framework (FSFW)
|
||||
* (c) 2022 IRS, Uni Stuttgart
|
||||
*******************************/
|
||||
|
||||
#ifndef ACSPARAMETERS_H_
|
||||
#define ACSPARAMETERS_H_
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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<double>::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<double>::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,
|
||||
|
@ -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*/
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ class Navigation {
|
||||
private:
|
||||
MultiplicativeKalmanFilter multiplicativeKalmanFilter;
|
||||
AcsParameters acsParameters;
|
||||
bool kalmanInit = false;
|
||||
ReturnValue_t mekfStatus = MultiplicativeKalmanFilter::MEKF_UNINITIALIZED;
|
||||
};
|
||||
|
||||
#endif /* ACS_NAVIGATION_H_ */
|
||||
|
@ -1,7 +1,3 @@
|
||||
/*******************************
|
||||
* EIVE Flight Software
|
||||
* (c) 2022 IRS, Uni Stuttgart
|
||||
*******************************/
|
||||
#ifndef SENSORPROCESSING_H_
|
||||
#define SENSORPROCESSING_H_
|
||||
|
||||
|
@ -1,9 +1,3 @@
|
||||
/*
|
||||
* SensorValues.cpp
|
||||
*
|
||||
* Created on: 30 Mar 2022
|
||||
* Author: rooob
|
||||
*/
|
||||
#include "SensorValues.h"
|
||||
|
||||
#include <fsfw/datapool/PoolReadGuard.h>
|
||||
|
@ -1,16 +1,9 @@
|
||||
/*
|
||||
* SusConverter.cpp
|
||||
*
|
||||
* Created on: 17.01.2022
|
||||
* Author: Timon Schwarz
|
||||
*/
|
||||
|
||||
#include "SusConverter.h"
|
||||
|
||||
#include <fsfw/datapoollocal/LocalPoolVariable.h>
|
||||
#include <fsfw/datapoollocal/LocalPoolVector.h>
|
||||
#include <fsfw/globalfunctions/math/VectorOperations.h>
|
||||
#include <math.h> //for atan2
|
||||
#include <math.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
@ -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]; //[-]
|
||||
|
||||
|
@ -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<T1>::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;
|
||||
|
@ -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,
|
||||
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<common::OBSW_MAX_SCHEDULED_TCS>(
|
||||
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<object_id_t, 4> 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<int>(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;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define MISSION_CORE_GENERICFACTORY_H_
|
||||
|
||||
#include <fsfw/devicehandlers/DeviceHandlerBase.h>
|
||||
#include <mission/memory/SdCardMountedIF.h>
|
||||
|
||||
#include "fsfw/objectmanager/SystemObjectIF.h"
|
||||
#include "fsfw/power/PowerSwitchIF.h"
|
||||
@ -37,7 +38,7 @@ const std::array<std::pair<object_id_t, std::string>, 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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -67,6 +67,7 @@ class GpsPrimaryDataset : public StaticLocalDataSet<18> {
|
||||
|
||||
private:
|
||||
friend class GpsHyperionLinuxController;
|
||||
friend class GpsCtrlDummy;
|
||||
GpsPrimaryDataset(HasLocalDataPoolIF* hkOwner)
|
||||
: StaticLocalDataSet(hkOwner, GpsHyperion::DATASET_ID) {}
|
||||
};
|
||||
|
@ -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<sd::SdCard> sdCard) = 0;
|
||||
virtual std::optional<sd::SdCard> getPreferredSdCard() const = 0;
|
||||
virtual void setActiveSdCard(sd::SdCard sdCard) = 0;
|
||||
|
@ -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)
|
||||
|
@ -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"; }
|
||||
|
||||
|
@ -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;
|
||||
|
362
mission/tmtc/PersistentTmStore.cpp
Normal file
362
mission/tmtc/PersistentTmStore.cpp
Normal file
@ -0,0 +1,362 @@
|
||||
#include "PersistentTmStore.h"
|
||||
|
||||
#include <mission/memory/SdCardMountedIF.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cinttypes>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <utility>
|
||||
|
||||
#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<time_t>(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<uint8_t, uint8_t> 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<uint8_t> suffix = std::nullopt;
|
||||
if (currentTv.tv_sec > activeFileTv.tv_sec + static_cast<int>(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<const char*>(reader.getFullData()),
|
||||
static_cast<std::streamsize>(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<uint16_t>({apid});
|
||||
return;
|
||||
}
|
||||
filter.apid.value().push_back(apid);
|
||||
}
|
||||
|
||||
void PersistentTmStore::addService(uint8_t service) {
|
||||
if (not filter.services) {
|
||||
filter.services = std::vector<uint8_t>({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<uint8_t, uint8_t>>({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<uint32_t>(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<char*>(fileBuf.data()), static_cast<std::streamsize>(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<uint8_t> 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<char*>(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<char*>(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<char*>(fileBuf.data() + currentIdx), fullSuffix.c_str());
|
||||
if (res == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
currentIdx += fullSuffix.size();
|
||||
}
|
||||
|
||||
path newPath(std::string(reinterpret_cast<const char*>(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();
|
||||
}
|
87
mission/tmtc/PersistentTmStore.h
Normal file
87
mission/tmtc/PersistentTmStore.h
Normal file
@ -0,0 +1,87 @@
|
||||
#ifndef MISSION_TMTC_TMSTOREBACKEND_H_
|
||||
#define MISSION_TMTC_TMSTOREBACKEND_H_
|
||||
|
||||
#include <fsfw/objectmanager/SystemObject.h>
|
||||
#include <fsfw/timemanager/CdsShortTimeStamper.h>
|
||||
#include <fsfw/tmstorage/TmStoreFrontendSimpleIF.h>
|
||||
#include <fsfw/tmtcpacket/pus/tm/PusTmReader.h>
|
||||
#include <fsfw/tmtcservices/AcceptsTelemetryIF.h>
|
||||
#include <mission/memory/SdCardMountedIF.h>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include "TmFunnelBase.h"
|
||||
#include "eive/eventSubsystemIds.h"
|
||||
|
||||
struct PacketFilter {
|
||||
std::optional<std::vector<uint16_t>> apid;
|
||||
std::optional<std::vector<uint8_t>> services;
|
||||
std::optional<std::vector<std::pair<uint8_t, uint8_t>>> 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<uint8_t, MAX_FILESIZE> fileBuf{};
|
||||
timeval currentTv;
|
||||
timeval activeFileTv{};
|
||||
std::optional<std::filesystem::path> 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<uint8_t> 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_ */
|
@ -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
|
||||
timeval currentUptime{};
|
||||
Clock::getUptime(¤tUptime);
|
||||
if (currentUptime.tv_sec - lastTvUpdate.tv_sec >
|
||||
static_cast<signed int>(TV_UPDATE_INTERVAL_SECS)) {
|
||||
Clock::getClock_timeval(¤tTv);
|
||||
lastTvUpdate = currentUptime;
|
||||
}
|
||||
} else {
|
||||
message.setStorageId(origStoreId);
|
||||
|
||||
bool sdcUsable = sdcMan.isSdCardUsable(std::nullopt);
|
||||
initStoresIfPossible(sdcUsable);
|
||||
if (sdcUsable) {
|
||||
miscStore.passPacket(packet);
|
||||
okStore.passPacket(packet);
|
||||
notOkStore.passPacket(packet);
|
||||
hkStore.passPacket(packet);
|
||||
}
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
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;
|
||||
}
|
||||
|
@ -10,33 +10,43 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#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
|
||||
|
85
mission/tmtc/Service15TmStorage.cpp
Normal file
85
mission/tmtc/Service15TmStorage.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
#include "Service15TmStorage.h"
|
||||
|
||||
#include <fsfw/objectmanager/ObjectManager.h>
|
||||
#include <fsfw/tmstorage/TmStoreFrontendSimpleIF.h>
|
||||
|
||||
#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<TmStoreFrontendSimpleIF>(*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;
|
||||
}
|
24
mission/tmtc/Service15TmStorage.h
Normal file
24
mission/tmtc/Service15TmStorage.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef MISSION_TMTC_SERVICE15TMSTORAGE_H_
|
||||
#define MISSION_TMTC_SERVICE15TMSTORAGE_H_
|
||||
|
||||
#include <fsfw/tmtcservices/CommandingServiceBase.h>
|
||||
|
||||
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_ */
|
@ -1,10 +1,12 @@
|
||||
#include "TmFunnelBase.h"
|
||||
|
||||
#include <fsfw/tmtcservices/TmTcMessage.h>
|
||||
|
||||
#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 = returnvalue::OK;
|
||||
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;
|
||||
}
|
||||
|
@ -3,21 +3,36 @@
|
||||
|
||||
#include <fsfw/objectmanager/SystemObject.h>
|
||||
#include <fsfw/storagemanager/StorageManagerIF.h>
|
||||
#include <fsfw/tmstorage/TmStoreFrontendSimpleIF.h>
|
||||
#include <fsfw/tmtcservices/AcceptsTelemetryIF.h>
|
||||
#include <fsfw/tmtcservices/TmTcMessage.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
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) {}
|
||||
|
@ -1,3 +1,3 @@
|
||||
target_sources(
|
||||
${LIB_EIVE_MISSION} PRIVATE Timestamp.cpp ProgressPrinter.cpp Filenaming.cpp
|
||||
GlobalConfigHandler.cpp)
|
||||
GlobalConfigHandler.cpp DummySdCardManager.cpp)
|
||||
|
13
mission/utility/DummySdCardManager.cpp
Normal file
13
mission/utility/DummySdCardManager.cpp
Normal file
@ -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<sd::SdCard> sdCard) { return true; }
|
||||
|
||||
std::optional<sd::SdCard> DummySdCardManager::getPreferredSdCard() const { return std::nullopt; }
|
||||
|
||||
void DummySdCardManager::setActiveSdCard(sd::SdCard sdCard) {}
|
||||
|
||||
std::optional<sd::SdCard> DummySdCardManager::getActiveSdCard() const { return std::nullopt; }
|
@ -2,11 +2,11 @@
|
||||
#define BSP_LINUX_BOARD_RPISDCARDMANAGER_H_
|
||||
#include <mission/memory/SdCardMountedIF.h>
|
||||
|
||||
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<sd::SdCard> sdCard) override;
|
||||
std::optional<sd::SdCard> getPreferredSdCard() const override;
|
||||
void setActiveSdCard(sd::SdCard sdCard) override;
|
||||
std::optional<sd::SdCard> getActiveSdCard() const override;
|
@ -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
|
||||
|
||||
|
2
tmtc
2
tmtc
@ -1 +1 @@
|
||||
Subproject commit 24f0d8e1a6a8ea1323623932e699326214c78159
|
||||
Subproject commit 9720fcddecb04b228dc5eb0d064f15a12ef8daca
|
@ -4,6 +4,7 @@ add_subdirectory(mocks)
|
||||
target_sources(${UNITTEST_NAME} PRIVATE
|
||||
main.cpp
|
||||
testEnvironment.cpp
|
||||
testStampInFilename.cpp
|
||||
hdlcEncodingRw.cpp
|
||||
printChar.cpp
|
||||
)
|
21
unittest/testStampInFilename.cpp
Normal file
21
unittest/testStampInFilename.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <cinttypes>
|
||||
|
||||
#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<void>(count);
|
||||
CHECK(count == 6);
|
||||
}
|
Loading…
Reference in New Issue
Block a user