diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f151a03..67af0720 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,56 @@ will consitute of a breaking change warranting a new major release: - Relaxed SUS FDIR. The devices have shown to be glitchy in orbit, but still seem to deliver sensible raw values most of the time. Some further testing is necessary, but some changes in the code should cause the SUS devices to remain healthy for now. +- The primary and the secondary temperature sensors for the PLOC mission boards are exchanged. +- ACS parameters for the SUSMGM (FLP) safe mode have been adjusted. This safe mode is now the + default one. + +# [v6.4.1] 2023-08-21 + +## Fixed + +- `PDEC_CONFIG_CORRUPTED` event now actually contains the readback instead of the expected + config +- Magnetic field vector was not calculated if only MGM4 was available, but still written to + the dataset. This would result in a NaN vector. Allowance for usage of MGM4 is now checked + before entering calculation. + +# [v6.4.0] 2023-08-16 + +- `eive-tmtc`: v5.4.3 + +## Fixed + +- The handling function of the GPS data is only called once per GPS read. This should remove + the fake fix-has-changed events. +- Fix for PLOC SUPV HK set parsing. +- The timestamp for the `POSSIBLE_FILE_CORRUPTION` event will be generated properly now. + +## Changed + +- PDEC FDIR rework: A full PDEC reboot will now only be performed after a regular PDEC reset has + failed 10 times. The mechanism will reset after no PDEC reset has happended for 2 minutes. + The PDEC reset will be performed when counting 4 dirty frame events 10 seconds after the count + was incremented initially. +- GPS Fix has changed event is no longer triggered for the EM +- MGM and SUS rates now will only be calculated, if 2 valid consecutive datapoints are available. + The stored value of the last timestep will now be reset, if no actual value is available. + +## Added + +- The PLOC SUPV HK set is requested and downlinked periodically if the SUPV is on now. +- SGP4 Propagator is now used for propagating the position of EIVE. It will only work once + a TLE has been uploaded with the newly added action command for the ACS Controller. In + return the actual GPS data will be ignored once SPG4 is running. However, by setting the + according parameter, the ACS Controller can be directed to ignore the SGP4 solution. +- Skyview dataset for more GPS TM has been added +- `PDEC_CONFIG_CORRUPTED` event which is triggered when the PDEC configuration does not match the + expected configuration. P1 will contain the readback of the first word and P2 will contain the + readback of the second word. +- The MGM and SUS vectors being too close together does not prevent the usage of the safe + mode controller anymore. +- Parameter to disable usage of MGM4, which is part of the MTQ and therefore cannot be + disabled without disabling the MTQ itself. # [v6.3.0] 2023-08-03 diff --git a/CMakeLists.txt b/CMakeLists.txt index 908c89ac..ff115a2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,8 +10,8 @@ cmake_minimum_required(VERSION 3.13) set(OBSW_VERSION_MAJOR 6) -set(OBSW_VERSION_MINOR 3) -set(OBSW_VERSION_REVISION 0) +set(OBSW_VERSION_MINOR 4) +set(OBSW_VERSION_REVISION 1) # set(CMAKE_VERBOSE TRUE) @@ -240,6 +240,9 @@ set(FSFW_WARNING_SHADOW_LOCAL_GCC OFF) set(EIVE_ADD_LINUX_FILES OFF) set(FSFW_ADD_TMSTORAGE ON) +set(FSFW_ADD_COORDINATES ON) +set(FSFW_ADD_SGP4_PROPAGATOR ON) + # Analyse different OS and architecture/target options, determine BSP_PATH, # display information about compiler etc. pre_source_hw_os_config() diff --git a/bsp_hosted/fsfwconfig/events/translateEvents.cpp b/bsp_hosted/fsfwconfig/events/translateEvents.cpp index 98c5035f..2f249d3b 100644 --- a/bsp_hosted/fsfwconfig/events/translateEvents.cpp +++ b/bsp_hosted/fsfwconfig/events/translateEvents.cpp @@ -1,7 +1,7 @@ /** - * @brief Auto-generated event translation file. Contains 303 translations. + * @brief Auto-generated event translation file. Contains 305 translations. * @details - * Generated on: 2023-08-03 13:36:37 + * Generated on: 2023-09-07 15:38:20 */ #include "translateEvents.h" @@ -100,6 +100,7 @@ const char *MEKF_RECOVERY_STRING = "MEKF_RECOVERY"; const char *MEKF_AUTOMATIC_RESET_STRING = "MEKF_AUTOMATIC_RESET"; const char *MEKF_INVALID_MODE_VIOLATION_STRING = "MEKF_INVALID_MODE_VIOLATION"; const char *SAFE_MODE_CONTROLLER_FAILURE_STRING = "SAFE_MODE_CONTROLLER_FAILURE"; +const char *TLE_TOO_OLD_STRING = "TLE_TOO_OLD"; const char *SWITCH_CMD_SENT_STRING = "SWITCH_CMD_SENT"; const char *SWITCH_HAS_CHANGED_STRING = "SWITCH_HAS_CHANGED"; const char *SWITCHING_Q7S_DENIED_STRING = "SWITCHING_Q7S_DENIED"; @@ -167,6 +168,7 @@ const char *PDEC_TRYING_RESET_NO_INIT_STRING = "PDEC_TRYING_RESET_NO_INIT"; const char *PDEC_RESET_FAILED_STRING = "PDEC_RESET_FAILED"; const char *OPEN_IRQ_FILE_FAILED_STRING = "OPEN_IRQ_FILE_FAILED"; const char *PDEC_INIT_FAILED_STRING = "PDEC_INIT_FAILED"; +const char *PDEC_CONFIG_CORRUPTED_STRING = "PDEC_CONFIG_CORRUPTED"; const char *IMAGE_UPLOAD_FAILED_STRING = "IMAGE_UPLOAD_FAILED"; const char *IMAGE_DOWNLOAD_FAILED_STRING = "IMAGE_DOWNLOAD_FAILED"; const char *IMAGE_UPLOAD_SUCCESSFUL_STRING = "IMAGE_UPLOAD_SUCCESSFUL"; @@ -501,6 +503,8 @@ const char *translateEvents(Event event) { return MEKF_INVALID_MODE_VIOLATION_STRING; case (11207): return SAFE_MODE_CONTROLLER_FAILURE_STRING; + case (11208): + return TLE_TOO_OLD_STRING; case (11300): return SWITCH_CMD_SENT_STRING; case (11301): @@ -635,6 +639,8 @@ const char *translateEvents(Event event) { return OPEN_IRQ_FILE_FAILED_STRING; case (12414): return PDEC_INIT_FAILED_STRING; + case (12415): + return PDEC_CONFIG_CORRUPTED_STRING; case (12500): return IMAGE_UPLOAD_FAILED_STRING; case (12501): diff --git a/bsp_hosted/fsfwconfig/objects/translateObjects.cpp b/bsp_hosted/fsfwconfig/objects/translateObjects.cpp index bd5ef90f..41f9789a 100644 --- a/bsp_hosted/fsfwconfig/objects/translateObjects.cpp +++ b/bsp_hosted/fsfwconfig/objects/translateObjects.cpp @@ -2,7 +2,7 @@ * @brief Auto-generated object translation file. * @details * Contains 171 translations. - * Generated on: 2023-08-03 13:36:37 + * Generated on: 2023-09-07 15:38:20 */ #include "translateObjects.h" diff --git a/bsp_q7s/em/emObjectFactory.cpp b/bsp_q7s/em/emObjectFactory.cpp index 3c3ba290..976602d4 100644 --- a/bsp_q7s/em/emObjectFactory.cpp +++ b/bsp_q7s/em/emObjectFactory.cpp @@ -111,6 +111,7 @@ void ObjectFactory::produce(void* args) { new CoreController(objects::CORE_CONTROLLER, enableHkSets); auto* stackHandler = new Stack5VHandler(*pwrSwitcher); + static_cast(stackHandler); // Initialize chip select to avoid SPI bus issues. createRadSensorChipSelect(gpioComIF); diff --git a/fsfw b/fsfw index d575da85..d246ce34 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit d575da85407e029dabecaffa5368f0c9f1034941 +Subproject commit d246ce34d05ecc5c722fd127e61556374961c899 diff --git a/generators/bsp_hosted_events.csv b/generators/bsp_hosted_events.csv index 99ea0670..d1dc39ea 100644 --- a/generators/bsp_hosted_events.csv +++ b/generators/bsp_hosted_events.csv @@ -94,6 +94,7 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path 11205;0x2bc5;MEKF_AUTOMATIC_RESET;INFO;MEKF performed an automatic reset after detection of nonfinite values.;mission/acs/defs.h 11206;0x2bc6;MEKF_INVALID_MODE_VIOLATION;HIGH;MEKF was not able to compute a solution during any pointing ACS mode for a prolonged time.;mission/acs/defs.h 11207;0x2bc7;SAFE_MODE_CONTROLLER_FAILURE;HIGH;The ACS safe mode controller was not able to compute a solution and has failed. P1: Missing information about magnetic field, P2: Missing information about rotational rate;mission/acs/defs.h +11208;0x2bc8;TLE_TOO_OLD;INFO;The TLE for the SGP4 Propagator has become too old.;mission/acs/defs.h 11300;0x2c24;SWITCH_CMD_SENT;INFO;Indicates that a FSFW object requested setting a switch P1: 1 if on was requested, 0 for off | P2: Switch Index;mission/power/defs.h 11301;0x2c25;SWITCH_HAS_CHANGED;INFO;Indicated that a switch state has changed P1: New switch state, 1 for on, 0 for off | P2: Switch Index;mission/power/defs.h 11302;0x2c26;SWITCHING_Q7S_DENIED;MEDIUM;No description;mission/power/defs.h @@ -161,6 +162,7 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path 12412;0x307c;PDEC_RESET_FAILED;HIGH;Failed to pull PDEC reset to low;linux/ipcore/pdec.h 12413;0x307d;OPEN_IRQ_FILE_FAILED;HIGH;Failed to open the IRQ uio file;linux/ipcore/pdec.h 12414;0x307e;PDEC_INIT_FAILED;HIGH;PDEC initialization failed. This might also be due to the persistent confiuration never becoming available, for example due to SD card issues.;linux/ipcore/pdec.h +12415;0x307f;PDEC_CONFIG_CORRUPTED;HIGH;The PDEC configuration area has been corrupted P1: The first configuration word P2: The second configuration word;linux/ipcore/pdec.h 12500;0x30d4;IMAGE_UPLOAD_FAILED;LOW;Image upload failed;linux/acs/StrComHandler.h 12501;0x30d5;IMAGE_DOWNLOAD_FAILED;LOW;Image download failed;linux/acs/StrComHandler.h 12502;0x30d6;IMAGE_UPLOAD_SUCCESSFUL;LOW;Uploading image to star tracker was successfulop;linux/acs/StrComHandler.h diff --git a/generators/bsp_q7s_events.csv b/generators/bsp_q7s_events.csv index 99ea0670..d1dc39ea 100644 --- a/generators/bsp_q7s_events.csv +++ b/generators/bsp_q7s_events.csv @@ -94,6 +94,7 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path 11205;0x2bc5;MEKF_AUTOMATIC_RESET;INFO;MEKF performed an automatic reset after detection of nonfinite values.;mission/acs/defs.h 11206;0x2bc6;MEKF_INVALID_MODE_VIOLATION;HIGH;MEKF was not able to compute a solution during any pointing ACS mode for a prolonged time.;mission/acs/defs.h 11207;0x2bc7;SAFE_MODE_CONTROLLER_FAILURE;HIGH;The ACS safe mode controller was not able to compute a solution and has failed. P1: Missing information about magnetic field, P2: Missing information about rotational rate;mission/acs/defs.h +11208;0x2bc8;TLE_TOO_OLD;INFO;The TLE for the SGP4 Propagator has become too old.;mission/acs/defs.h 11300;0x2c24;SWITCH_CMD_SENT;INFO;Indicates that a FSFW object requested setting a switch P1: 1 if on was requested, 0 for off | P2: Switch Index;mission/power/defs.h 11301;0x2c25;SWITCH_HAS_CHANGED;INFO;Indicated that a switch state has changed P1: New switch state, 1 for on, 0 for off | P2: Switch Index;mission/power/defs.h 11302;0x2c26;SWITCHING_Q7S_DENIED;MEDIUM;No description;mission/power/defs.h @@ -161,6 +162,7 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path 12412;0x307c;PDEC_RESET_FAILED;HIGH;Failed to pull PDEC reset to low;linux/ipcore/pdec.h 12413;0x307d;OPEN_IRQ_FILE_FAILED;HIGH;Failed to open the IRQ uio file;linux/ipcore/pdec.h 12414;0x307e;PDEC_INIT_FAILED;HIGH;PDEC initialization failed. This might also be due to the persistent confiuration never becoming available, for example due to SD card issues.;linux/ipcore/pdec.h +12415;0x307f;PDEC_CONFIG_CORRUPTED;HIGH;The PDEC configuration area has been corrupted P1: The first configuration word P2: The second configuration word;linux/ipcore/pdec.h 12500;0x30d4;IMAGE_UPLOAD_FAILED;LOW;Image upload failed;linux/acs/StrComHandler.h 12501;0x30d5;IMAGE_DOWNLOAD_FAILED;LOW;Image download failed;linux/acs/StrComHandler.h 12502;0x30d6;IMAGE_UPLOAD_SUCCESSFUL;LOW;Uploading image to star tracker was successfulop;linux/acs/StrComHandler.h diff --git a/generators/events/translateEvents.cpp b/generators/events/translateEvents.cpp index 98c5035f..2f249d3b 100644 --- a/generators/events/translateEvents.cpp +++ b/generators/events/translateEvents.cpp @@ -1,7 +1,7 @@ /** - * @brief Auto-generated event translation file. Contains 303 translations. + * @brief Auto-generated event translation file. Contains 305 translations. * @details - * Generated on: 2023-08-03 13:36:37 + * Generated on: 2023-09-07 15:38:20 */ #include "translateEvents.h" @@ -100,6 +100,7 @@ const char *MEKF_RECOVERY_STRING = "MEKF_RECOVERY"; const char *MEKF_AUTOMATIC_RESET_STRING = "MEKF_AUTOMATIC_RESET"; const char *MEKF_INVALID_MODE_VIOLATION_STRING = "MEKF_INVALID_MODE_VIOLATION"; const char *SAFE_MODE_CONTROLLER_FAILURE_STRING = "SAFE_MODE_CONTROLLER_FAILURE"; +const char *TLE_TOO_OLD_STRING = "TLE_TOO_OLD"; const char *SWITCH_CMD_SENT_STRING = "SWITCH_CMD_SENT"; const char *SWITCH_HAS_CHANGED_STRING = "SWITCH_HAS_CHANGED"; const char *SWITCHING_Q7S_DENIED_STRING = "SWITCHING_Q7S_DENIED"; @@ -167,6 +168,7 @@ const char *PDEC_TRYING_RESET_NO_INIT_STRING = "PDEC_TRYING_RESET_NO_INIT"; const char *PDEC_RESET_FAILED_STRING = "PDEC_RESET_FAILED"; const char *OPEN_IRQ_FILE_FAILED_STRING = "OPEN_IRQ_FILE_FAILED"; const char *PDEC_INIT_FAILED_STRING = "PDEC_INIT_FAILED"; +const char *PDEC_CONFIG_CORRUPTED_STRING = "PDEC_CONFIG_CORRUPTED"; const char *IMAGE_UPLOAD_FAILED_STRING = "IMAGE_UPLOAD_FAILED"; const char *IMAGE_DOWNLOAD_FAILED_STRING = "IMAGE_DOWNLOAD_FAILED"; const char *IMAGE_UPLOAD_SUCCESSFUL_STRING = "IMAGE_UPLOAD_SUCCESSFUL"; @@ -501,6 +503,8 @@ const char *translateEvents(Event event) { return MEKF_INVALID_MODE_VIOLATION_STRING; case (11207): return SAFE_MODE_CONTROLLER_FAILURE_STRING; + case (11208): + return TLE_TOO_OLD_STRING; case (11300): return SWITCH_CMD_SENT_STRING; case (11301): @@ -635,6 +639,8 @@ const char *translateEvents(Event event) { return OPEN_IRQ_FILE_FAILED_STRING; case (12414): return PDEC_INIT_FAILED_STRING; + case (12415): + return PDEC_CONFIG_CORRUPTED_STRING; case (12500): return IMAGE_UPLOAD_FAILED_STRING; case (12501): diff --git a/generators/objects/translateObjects.cpp b/generators/objects/translateObjects.cpp index ce21a66f..32f68bfc 100644 --- a/generators/objects/translateObjects.cpp +++ b/generators/objects/translateObjects.cpp @@ -2,7 +2,7 @@ * @brief Auto-generated object translation file. * @details * Contains 175 translations. - * Generated on: 2023-08-03 13:36:37 + * Generated on: 2023-09-07 15:38:20 */ #include "translateObjects.h" diff --git a/linux/acs/GpsHyperionLinuxController.cpp b/linux/acs/GpsHyperionLinuxController.cpp index 900de0aa..a2dbd81b 100644 --- a/linux/acs/GpsHyperionLinuxController.cpp +++ b/linux/acs/GpsHyperionLinuxController.cpp @@ -21,6 +21,7 @@ GpsHyperionLinuxController::GpsHyperionLinuxController(object_id_t objectId, obj bool enableHkSets, bool debugHyperionGps) : ExtendedControllerBase(objectId), gpsSet(this), + skyviewSet(this), enableHkSets(enableHkSets), debugHyperionGps(debugHyperionGps) {} @@ -29,7 +30,17 @@ GpsHyperionLinuxController::~GpsHyperionLinuxController() { gps_close(&gps); } -LocalPoolDataSetBase *GpsHyperionLinuxController::getDataSetHandle(sid_t sid) { return &gpsSet; } +LocalPoolDataSetBase *GpsHyperionLinuxController::getDataSetHandle(sid_t sid) { + switch (sid.ownerSetId) { + case GpsHyperion::CORE_DATASET: + return &gpsSet; + case GpsHyperion::SKYVIEW_DATASET: + return &skyviewSet; + default: + return nullptr; + } + return nullptr; +} ReturnValue_t GpsHyperionLinuxController::checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode) { @@ -90,6 +101,13 @@ ReturnValue_t GpsHyperionLinuxController::initializeLocalDataPool( localDataPoolMap.emplace(GpsHyperion::SATS_IN_VIEW, new PoolEntry()); localDataPoolMap.emplace(GpsHyperion::FIX_MODE, new PoolEntry()); poolManager.subscribeForRegularPeriodicPacket({gpsSet.getSid(), enableHkSets, 30.0}); + localDataPoolMap.emplace(GpsHyperion::SKYVIEW_UNIX_SECONDS, new PoolEntry()); + localDataPoolMap.emplace(GpsHyperion::PRN_ID, new PoolEntry()); + localDataPoolMap.emplace(GpsHyperion::AZIMUTH, new PoolEntry()); + localDataPoolMap.emplace(GpsHyperion::ELEVATION, new PoolEntry()); + localDataPoolMap.emplace(GpsHyperion::SIGNAL2NOISE, new PoolEntry()); + localDataPoolMap.emplace(GpsHyperion::USED, new PoolEntry()); + poolManager.subscribeForRegularPeriodicPacket({skyviewSet.getSid(), false, 120.0}); return returnvalue::OK; } @@ -166,30 +184,32 @@ bool GpsHyperionLinuxController::readGpsDataFromGpsd() { if (mode == MODE_OFF) { return false; } + unsigned int readIdx = 0; if (readMode == ReadModes::SOCKET) { // Poll the GPS. - if (gps_waiting(&gps, 0)) { - if (-1 == gps_read(&gps)) { + while (gps_waiting(&gps, 0)) { + int retval = gps_read(&gps); + if (retval < 0) { readError(); return false; } - oneShotSwitches.gpsReadFailedSwitch = true; - ReturnValue_t result = handleGpsReadData(); - if (result == returnvalue::OK) { - return true; - } else { - return false; + readIdx++; + if (readIdx >= 40) { + sif::warning << "GpsHyperionLinuxController: Received " << readIdx + << " GPSD message consecutively" << std::endl; + break; } - noModeSetCntr = 0; - } else { - return false; + } + if (readIdx > 0) { + oneShotSwitches.gpsReadFailedSwitch = true; + handleGpsReadData(); } } else if (readMode == ReadModes::SHM) { sif::error << "GpsHyperionLinuxController::readGpsDataFromGpsdPermanentLoop: " "SHM read not implemented" << std::endl; } - return true; + return false; } ReturnValue_t GpsHyperionLinuxController::handleGpsReadData() { @@ -208,7 +228,15 @@ ReturnValue_t GpsHyperionLinuxController::handleGpsReadData() { return returnvalue::FAILED; } } + ReturnValue_t result = handleCoreTelemetry(modeIsSet); + if (result != returnvalue::OK) { + return result; + } + result = handleSkyviewTelemetry(); + return result; +} +ReturnValue_t GpsHyperionLinuxController::handleCoreTelemetry(bool modeIsSet) { PoolReadGuard pg(&gpsSet); if (pg.getReadResult() != returnvalue::OK) { #if FSFW_VERBOSE_LEVEL >= 1 @@ -236,7 +264,9 @@ ReturnValue_t GpsHyperionLinuxController::handleGpsReadData() { } } if (gpsSet.fixMode.value != newFix) { +#if OBSW_Q7S_EM != 1 triggerEvent(GpsHyperion::GPS_FIX_CHANGE, gpsSet.fixMode.value, newFix); +#endif } gpsSet.fixMode = newFix; gpsSet.fixMode.setValid(modeIsSet); @@ -369,6 +399,22 @@ ReturnValue_t GpsHyperionLinuxController::handleGpsReadData() { return returnvalue::OK; } +ReturnValue_t GpsHyperionLinuxController::handleSkyviewTelemetry() { + PoolReadGuard pg(&skyviewSet); + if (pg.getReadResult() != returnvalue::OK) { + return returnvalue::FAILED; + } + skyviewSet.unixSeconds.value = gps.skyview_time; + for (int sat = 0; sat < GpsHyperion::MAX_SATELLITES; sat++) { + skyviewSet.prn_id.value[sat] = gps.skyview[sat].PRN; + skyviewSet.azimuth.value[sat] = gps.skyview[sat].azimuth; + skyviewSet.elevation.value[sat] = gps.skyview[sat].elevation; + skyviewSet.signal2noise.value[sat] = gps.skyview[sat].ss; + skyviewSet.used.value[sat] = gps.skyview[sat].used; + } + return returnvalue::OK; +} + void GpsHyperionLinuxController::overwriteTimeIfNotSane(timeval time, bool validFix) { if (not timeInit and validFix) { if (not utility::timeSanityCheck()) { diff --git a/linux/acs/GpsHyperionLinuxController.h b/linux/acs/GpsHyperionLinuxController.h index d5b1f637..3378ac55 100644 --- a/linux/acs/GpsHyperionLinuxController.h +++ b/linux/acs/GpsHyperionLinuxController.h @@ -54,9 +54,12 @@ class GpsHyperionLinuxController : public ExtendedControllerBase { LocalDataPoolManager& poolManager) override; ReturnValue_t handleGpsReadData(); + ReturnValue_t handleCoreTelemetry(bool modeIsSet); + ReturnValue_t handleSkyviewTelemetry(); private: GpsPrimaryDataset gpsSet; + SkyviewDataset skyviewSet; gps_data_t gps = {}; bool enableHkSets = false; const char* currentClientBuf = nullptr; @@ -81,7 +84,6 @@ class GpsHyperionLinuxController : public ExtendedControllerBase { } oneShotSwitches; bool debugHyperionGps = false; - int32_t noModeSetCntr = 0; // Returns true if the function should be called again or false if other // controller handling can be done. diff --git a/linux/boardtest/UartTestClass.h b/linux/boardtest/UartTestClass.h index f959f877..d03706ed 100644 --- a/linux/boardtest/UartTestClass.h +++ b/linux/boardtest/UartTestClass.h @@ -11,7 +11,7 @@ #include -//#include "lwgps/lwgps.h" +// #include "lwgps/lwgps.h" #include "test/TestTask.h" class ScexUartReader; diff --git a/linux/fsfwconfig/events/translateEvents.cpp b/linux/fsfwconfig/events/translateEvents.cpp index 98c5035f..2f249d3b 100644 --- a/linux/fsfwconfig/events/translateEvents.cpp +++ b/linux/fsfwconfig/events/translateEvents.cpp @@ -1,7 +1,7 @@ /** - * @brief Auto-generated event translation file. Contains 303 translations. + * @brief Auto-generated event translation file. Contains 305 translations. * @details - * Generated on: 2023-08-03 13:36:37 + * Generated on: 2023-09-07 15:38:20 */ #include "translateEvents.h" @@ -100,6 +100,7 @@ const char *MEKF_RECOVERY_STRING = "MEKF_RECOVERY"; const char *MEKF_AUTOMATIC_RESET_STRING = "MEKF_AUTOMATIC_RESET"; const char *MEKF_INVALID_MODE_VIOLATION_STRING = "MEKF_INVALID_MODE_VIOLATION"; const char *SAFE_MODE_CONTROLLER_FAILURE_STRING = "SAFE_MODE_CONTROLLER_FAILURE"; +const char *TLE_TOO_OLD_STRING = "TLE_TOO_OLD"; const char *SWITCH_CMD_SENT_STRING = "SWITCH_CMD_SENT"; const char *SWITCH_HAS_CHANGED_STRING = "SWITCH_HAS_CHANGED"; const char *SWITCHING_Q7S_DENIED_STRING = "SWITCHING_Q7S_DENIED"; @@ -167,6 +168,7 @@ const char *PDEC_TRYING_RESET_NO_INIT_STRING = "PDEC_TRYING_RESET_NO_INIT"; const char *PDEC_RESET_FAILED_STRING = "PDEC_RESET_FAILED"; const char *OPEN_IRQ_FILE_FAILED_STRING = "OPEN_IRQ_FILE_FAILED"; const char *PDEC_INIT_FAILED_STRING = "PDEC_INIT_FAILED"; +const char *PDEC_CONFIG_CORRUPTED_STRING = "PDEC_CONFIG_CORRUPTED"; const char *IMAGE_UPLOAD_FAILED_STRING = "IMAGE_UPLOAD_FAILED"; const char *IMAGE_DOWNLOAD_FAILED_STRING = "IMAGE_DOWNLOAD_FAILED"; const char *IMAGE_UPLOAD_SUCCESSFUL_STRING = "IMAGE_UPLOAD_SUCCESSFUL"; @@ -501,6 +503,8 @@ const char *translateEvents(Event event) { return MEKF_INVALID_MODE_VIOLATION_STRING; case (11207): return SAFE_MODE_CONTROLLER_FAILURE_STRING; + case (11208): + return TLE_TOO_OLD_STRING; case (11300): return SWITCH_CMD_SENT_STRING; case (11301): @@ -635,6 +639,8 @@ const char *translateEvents(Event event) { return OPEN_IRQ_FILE_FAILED_STRING; case (12414): return PDEC_INIT_FAILED_STRING; + case (12415): + return PDEC_CONFIG_CORRUPTED_STRING; case (12500): return IMAGE_UPLOAD_FAILED_STRING; case (12501): diff --git a/linux/fsfwconfig/objects/translateObjects.cpp b/linux/fsfwconfig/objects/translateObjects.cpp index ce21a66f..32f68bfc 100644 --- a/linux/fsfwconfig/objects/translateObjects.cpp +++ b/linux/fsfwconfig/objects/translateObjects.cpp @@ -2,7 +2,7 @@ * @brief Auto-generated object translation file. * @details * Contains 175 translations. - * Generated on: 2023-08-03 13:36:37 + * Generated on: 2023-09-07 15:38:20 */ #include "translateObjects.h" diff --git a/linux/ipcore/PdecConfig.cpp b/linux/ipcore/PdecConfig.cpp index a41c5ba6..19423862 100644 --- a/linux/ipcore/PdecConfig.cpp +++ b/linux/ipcore/PdecConfig.cpp @@ -22,11 +22,11 @@ ReturnValue_t PdecConfig::write() { if (result != returnvalue::OK) { return result; } - result = writeFrameHeaderFirstOctet(); + result = writeFrameHeaderFirstWord(); if (result != returnvalue::OK) { return result; } - result = writeFrameHeaderSecondOctet(); + result = writeFrameHeaderSecondWord(); if (result != returnvalue::OK) { return result; } @@ -77,7 +77,7 @@ ReturnValue_t PdecConfig::setPositiveWindow(uint8_t pw) { return result; } // Rewrite second config word which contains the positive window parameter - writeFrameHeaderSecondOctet(); + writeFrameHeaderSecondWord(); return returnvalue::OK; } @@ -92,7 +92,7 @@ ReturnValue_t PdecConfig::setNegativeWindow(uint8_t nw) { return result; } // Rewrite second config word which contains the negative window parameter - writeFrameHeaderSecondOctet(); + writeFrameHeaderSecondWord(); return returnvalue::OK; } @@ -114,43 +114,23 @@ ReturnValue_t PdecConfig::getNegativeWindow(uint8_t& negativeWindow) { return returnvalue::OK; } -ReturnValue_t PdecConfig::writeFrameHeaderFirstOctet() { +ReturnValue_t PdecConfig::writeFrameHeaderFirstWord() { uint32_t word = 0; - word |= (VERSION_ID << 30); - - // Setting the bypass flag and the control command flag should not have any - // implication on the operation of the PDEC IP Core - word |= (BYPASS_FLAG << 29); - word |= (CONTROL_COMMAND_FLAG << 28); - - word |= (RESERVED_FIELD_A << 26); - word |= (SPACECRAFT_ID << 16); - word |= (VIRTUAL_CHANNEL << 10); - word |= (DUMMY_BITS << 8); - uint8_t positiveWindow = 0; - ReturnValue_t result = - localParameterHandler.getValue(pdecconfigdefs::paramkeys::POSITIVE_WINDOW, positiveWindow); + ReturnValue_t result = createFirstWord(&word); if (result != returnvalue::OK) { return result; } - word |= static_cast(positiveWindow); - *(memoryBaseAddress + FRAME_HEADER_OFFSET) = word; + *(memoryBaseAddress + FRAME_HEADER_OFFSET + OFFSET_FIRST_CONFIG_WORD) = word; return returnvalue::OK; } -ReturnValue_t PdecConfig::writeFrameHeaderSecondOctet() { - uint8_t negativeWindow = 0; - ReturnValue_t result = - localParameterHandler.getValue(pdecconfigdefs::paramkeys::NEGATIVE_WINDOW, negativeWindow); +ReturnValue_t PdecConfig::writeFrameHeaderSecondWord() { + uint32_t word = 0; + ReturnValue_t result = createSecondWord(&word); if (result != returnvalue::OK) { return result; } - uint32_t word = 0; - word = 0; - word |= (static_cast(negativeWindow) << 24); - word |= (HIGH_AU_MAP_ID << 16); - word |= (ENABLE_DERANDOMIZER << 8); - *(memoryBaseAddress + FRAME_HEADER_OFFSET + 1) = word; + *(memoryBaseAddress + FRAME_HEADER_OFFSET + OFFSET_SECOND_CONFIG_WORD) = word; return returnvalue::OK; } @@ -189,3 +169,49 @@ uint8_t PdecConfig::getOddParity(uint8_t number) { parityBit = ~(countBits & 0x1) & 0x1; return parityBit; } + +ReturnValue_t PdecConfig::createFirstWord(uint32_t* word) { + *word = 0; + *word |= (VERSION_ID << 30); + + // Setting the bypass flag and the control command flag should not have any + // implication on the operation of the PDEC IP Core + *word |= (BYPASS_FLAG << 29); + *word |= (CONTROL_COMMAND_FLAG << 28); + + *word |= (RESERVED_FIELD_A << 26); + *word |= (SPACECRAFT_ID << 16); + *word |= (VIRTUAL_CHANNEL << 10); + *word |= (DUMMY_BITS << 8); + uint8_t positiveWindow = 0; + ReturnValue_t result = + localParameterHandler.getValue(pdecconfigdefs::paramkeys::POSITIVE_WINDOW, positiveWindow); + if (result != returnvalue::OK) { + return result; + } + *word |= static_cast(positiveWindow); + return returnvalue::OK; +} + +ReturnValue_t PdecConfig::createSecondWord(uint32_t* word) { + uint8_t negativeWindow = 0; + ReturnValue_t result = + localParameterHandler.getValue(pdecconfigdefs::paramkeys::NEGATIVE_WINDOW, negativeWindow); + if (result != returnvalue::OK) { + return result; + } + *word = 0; + *word = 0; + *word |= (static_cast(negativeWindow) << 24); + *word |= (HIGH_AU_MAP_ID << 16); + *word |= (ENABLE_DERANDOMIZER << 8); + return returnvalue::OK; +} + +uint32_t PdecConfig::readbackFirstWord() { + return *(memoryBaseAddress + FRAME_HEADER_OFFSET + OFFSET_FIRST_CONFIG_WORD); +} + +uint32_t PdecConfig::readbackSecondWord() { + return *(memoryBaseAddress + FRAME_HEADER_OFFSET + OFFSET_SECOND_CONFIG_WORD); +} diff --git a/linux/ipcore/PdecConfig.h b/linux/ipcore/PdecConfig.h index f7203eec..1f2ed9c8 100644 --- a/linux/ipcore/PdecConfig.h +++ b/linux/ipcore/PdecConfig.h @@ -48,6 +48,39 @@ class PdecConfig { ReturnValue_t getPositiveWindow(uint8_t& positiveWindow); ReturnValue_t getNegativeWindow(uint8_t& negativeWindow); + /** + * @brief Creates the first word of the PDEC configuration + * + * @param word The created word will be written to this pointer + * + * @return OK if successful, otherwise error return value + * + */ + ReturnValue_t createFirstWord(uint32_t* word); + + /** + * @brief Creates the second word of the PDEC configuration + * + * @param word The created word will be written to this pointer + * + * @return OK if successful, otherwise error return value + */ + ReturnValue_t createSecondWord(uint32_t* word); + + /** + * @brief Reads first config word from the config memory + * + * @return The config word + */ + uint32_t readbackFirstWord(); + + /** + * @brief Reads the second config word from the config memory + * + * @return The config word + */ + uint32_t readbackSecondWord(); + private: // TC transfer frame configuration parameters static const uint8_t VERSION_ID = 0; @@ -66,6 +99,8 @@ class PdecConfig { // 0x200 / 4 = 0x80 static const uint32_t FRAME_HEADER_OFFSET = 0x80; + static const uint32_t OFFSET_FIRST_CONFIG_WORD = 0; + static const uint32_t OFFSET_SECOND_CONFIG_WORD = 1; static const uint32_t MAP_ADDR_LUT_OFFSET = 0xA0; static const uint32_t MAP_CLK_FREQ_OFFSET = 0x90; @@ -102,8 +137,8 @@ class PdecConfig { */ ReturnValue_t createPersistentConfig(); - ReturnValue_t writeFrameHeaderFirstOctet(); - ReturnValue_t writeFrameHeaderSecondOctet(); + ReturnValue_t writeFrameHeaderFirstWord(); + ReturnValue_t writeFrameHeaderSecondWord(); void writeMapConfig(); /** diff --git a/linux/ipcore/PdecHandler.cpp b/linux/ipcore/PdecHandler.cpp index cc074ddd..c7266710 100644 --- a/linux/ipcore/PdecHandler.cpp +++ b/linux/ipcore/PdecHandler.cpp @@ -478,6 +478,7 @@ bool PdecHandler::checkFrameAna(uint32_t pdecFar) { } case (FrameAna_t::FRAME_DIRTY): { triggerEvent(INVALID_TC_FRAME, FRAME_DIRTY_RETVAL); + checkConfig(); sif::warning << "PdecHandler::checkFrameAna: Frame dirty" << std::endl; break; } @@ -577,6 +578,30 @@ void PdecHandler::handleIReason(uint32_t pdecFar, ReturnValue_t parameter1) { } } +void PdecHandler::checkConfig() { + uint32_t firstWord = 0; + ReturnValue_t result = pdecConfig.createFirstWord(&firstWord); + if (result != returnvalue::OK) { + // This should normally never happen during runtime. So here is just + // output a warning + sif::warning << "PdecHandler::checkConfig: Failed to create first word" << std::endl; + return; + } + uint32_t secondWord = 0; + result = pdecConfig.createSecondWord(&secondWord); + if (result != returnvalue::OK) { + // This should normally never happen during runtime. So here is just + // output a warning + sif::warning << "PdecHandler::checkConfig: Failed to create second word" << std::endl; + return; + } + uint32_t readbackFirstWord = pdecConfig.readbackFirstWord(); + uint32_t readbackSecondWord = pdecConfig.readbackSecondWord(); + if (firstWord != readbackFirstWord or secondWord != readbackSecondWord) { + triggerEvent(PDEC_CONFIG_CORRUPTED, readbackFirstWord, readbackSecondWord); + } +} + void PdecHandler::handleNewTc() { ReturnValue_t result = returnvalue::OK; diff --git a/linux/ipcore/PdecHandler.h b/linux/ipcore/PdecHandler.h index 882dca50..11ae4de3 100644 --- a/linux/ipcore/PdecHandler.h +++ b/linux/ipcore/PdecHandler.h @@ -282,6 +282,11 @@ class PdecHandler : public SystemObject, */ void handleIReason(uint32_t pdecFar, ReturnValue_t parameter1); + /** + * @brief Checks if PDEC configuration is still correct + */ + void checkConfig(); + /** * @brief Handles the reception of new TCs. Reads the pointer to the storage location of the * new TC segment, extracts the PUS packet and forwards the data to the object diff --git a/linux/ipcore/pdec.h b/linux/ipcore/pdec.h index 0574ee73..de703c5a 100644 --- a/linux/ipcore/pdec.h +++ b/linux/ipcore/pdec.h @@ -71,6 +71,10 @@ static constexpr Event OPEN_IRQ_FILE_FAILED = event::makeEvent(SUBSYSTEM_ID, 13, //! [EXPORT] : [COMMENT] PDEC initialization failed. This might also be due to the persistent //! confiuration never becoming available, for example due to SD card issues. static constexpr Event PDEC_INIT_FAILED = event::makeEvent(SUBSYSTEM_ID, 14, severity::HIGH); +//! [EXPORT] : [COMMENT] The PDEC configuration area has been corrupted +//! P1: The first configuration word +//! P2: The second configuration word +static constexpr Event PDEC_CONFIG_CORRUPTED = event::makeEvent(SUBSYSTEM_ID, 15, severity::HIGH); // Action IDs static constexpr ActionId_t PRINT_CLCW = 0; diff --git a/linux/payload/PlocSupervisorHandler.cpp b/linux/payload/PlocSupervisorHandler.cpp index 682b8020..d4a3a1c0 100644 --- a/linux/payload/PlocSupervisorHandler.cpp +++ b/linux/payload/PlocSupervisorHandler.cpp @@ -155,12 +155,15 @@ void PlocSupervisorHandler::doStartUp() { startupState = StartupState::ON; } if (startupState == StartupState::ON) { + hkset.setReportingEnabled(true); setMode(_MODE_TO_ON); } } void PlocSupervisorHandler::doShutDown() { setMode(_MODE_POWER_DOWN); + hkset.setReportingEnabled(false); + hkset.setValidity(false, true); shutdownCmdSent = false; packetInBuffer = false; nextReplyId = supv::NONE; @@ -170,6 +173,10 @@ void PlocSupervisorHandler::doShutDown() { } ReturnValue_t PlocSupervisorHandler::buildNormalDeviceCommand(DeviceCommandId_t* id) { + if (not commandIsExecuting(GET_HK_REPORT)) { + *id = GET_HK_REPORT; + return buildCommandFromCommand(*id, nullptr, 0); + } return NOTHING_TO_SEND; } @@ -430,7 +437,7 @@ void PlocSupervisorHandler::fillCommandAndReplyMap() { insertInReplyMap(MEMORY_CHECK, 5, nullptr, 0, false); // TM replies - insertInReplyMap(HK_REPORT, 3, &hkset, SIZE_HK_REPORT); + insertInReplyMap(HK_REPORT, 3, &hkset); insertInReplyMap(BOOT_STATUS_REPORT, 3, &bootStatusReport, SIZE_BOOT_STATUS_REPORT); insertInReplyMap(LATCHUP_REPORT, 3, &latchupStatusReport, SIZE_LATCHUP_STATUS_REPORT); insertInReplyMap(LOGGING_REPORT, 3, &loggingReport, SIZE_LOGGING_REPORT); @@ -790,6 +797,8 @@ ReturnValue_t PlocSupervisorHandler::initializeLocalDataPool(localpool::DataPool localDataPoolMap.emplace(supv::ADC_ENG_14, new PoolEntry({0})); localDataPoolMap.emplace(supv::ADC_ENG_15, new PoolEntry({0})); + poolManager.subscribeForRegularPeriodicPacket( + subdp::RegularHkPeriodicParams(hkset.getSid(), false, 10.0)); return returnvalue::OK; } @@ -918,7 +927,7 @@ ReturnValue_t PlocSupervisorHandler::handleExecutionReport(const uint8_t* data) ReturnValue_t PlocSupervisorHandler::handleHkReport(const uint8_t* data) { ReturnValue_t result = returnvalue::OK; - result = verifyPacket(data, supv::SIZE_HK_REPORT); + result = verifyPacket(data, tmReader.getFullPacketLen()); if (result == result::CRC_FAILURE) { sif::error << "PlocSupervisorHandler::handleHkReport: Hk report has invalid crc" << std::endl; @@ -2096,9 +2105,9 @@ uint32_t PlocSupervisorHandler::getTransitionDelayMs(Mode_t modeFrom, Mode_t mod // if (result != returnvalue::OK) { // return result; // } -//#if OBSW_VERBOSE_LEVEL >= 1 && OBSW_DEBUG_PLOC_SUPERVISOR == 1 +// #if OBSW_VERBOSE_LEVEL >= 1 && OBSW_DEBUG_PLOC_SUPERVISOR == 1 // loggingReport.printSet(); -//#endif +// #endif // nextReplyId = supv::EXE_REPORT; // return result; // } diff --git a/linux/payload/PlocSupvUartMan.cpp b/linux/payload/PlocSupvUartMan.cpp index e4371be5..1a129927 100644 --- a/linux/payload/PlocSupvUartMan.cpp +++ b/linux/payload/PlocSupvUartMan.cpp @@ -274,12 +274,12 @@ ReturnValue_t PlocSupvUartManager::initiateUpdateContinuation() { } // ReturnValue_t PlocSupvHelper::startEventBufferRequest(std::string path) { -//#ifdef XIPHOS_Q7S +// #ifdef XIPHOS_Q7S // ReturnValue_t result = FilesystemHelper::checkPath(path); // if (result != returnvalue::OK) { // return result; // } -//#endif +// #endif // if (not std::filesystem::exists(path)) { // return PATH_NOT_EXISTS; // } @@ -836,11 +836,11 @@ uint32_t PlocSupvUartManager::getFileSize(std::string filename) { ReturnValue_t PlocSupvUartManager::handleEventBufferReception(ploc::SpTmReader& reader) { ReturnValue_t result = returnvalue::OK; // TODO: Fix - //#ifdef XIPHOS_Q7S + // #ifdef XIPHOS_Q7S // if (not sdcMan->getActiveSdCard()) { // return HasFileSystemIF::FILESYSTEM_INACTIVE; // } - //#endif + // #endif // std::string filename = Filenaming::generateAbsoluteFilename( // eventBufferReq.path, eventBufferReq.filename, timestamping); // std::ofstream file(filename, std::ios_base::app | std::ios_base::out); diff --git a/linux/payload/plocSupvDefs.h b/linux/payload/plocSupvDefs.h index d3fda3da..907bfe0c 100644 --- a/linux/payload/plocSupvDefs.h +++ b/linux/payload/plocSupvDefs.h @@ -139,7 +139,6 @@ enum ReplyId : DeviceCommandId_t { // Size of complete space packet (6 byte header + size of data + 2 byte CRC) static const uint16_t SIZE_ACK_REPORT = 14; static const uint16_t SIZE_EXE_REPORT = 14; -static const uint16_t SIZE_HK_REPORT = 52; static const uint16_t SIZE_BOOT_STATUS_REPORT = 24; static const uint16_t SIZE_LATCHUP_STATUS_REPORT = 31; static const uint16_t SIZE_LOGGING_REPORT = 73; diff --git a/mission/acs/archive/GPSDefinitions.h b/mission/acs/archive/GPSDefinitions.h index d9f93173..67169cbc 100644 --- a/mission/acs/archive/GPSDefinitions.h +++ b/mission/acs/archive/GPSDefinitions.h @@ -20,32 +20,47 @@ static constexpr Event CANT_GET_FIX = event::makeEvent(SUBSYSTEM_ID, 1, severity static constexpr DeviceCommandId_t GPS_REPLY = 0; static constexpr DeviceCommandId_t TRIGGER_RESET_PIN_GNSS = 5; -static constexpr uint32_t DATASET_ID = 0; +enum SetIds : uint32_t { + CORE_DATASET, + SKYVIEW_DATASET, +}; enum GpsPoolIds : lp_id_t { - LATITUDE = 0, - LONGITUDE = 1, - ALTITUDE = 2, - SPEED = 3, - FIX_MODE = 4, - SATS_IN_USE = 5, - SATS_IN_VIEW = 6, - UNIX_SECONDS = 7, - YEAR = 8, - MONTH = 9, - DAY = 10, - HOURS = 11, - MINUTES = 12, - SECONDS = 13 + LATITUDE, + LONGITUDE, + ALTITUDE, + SPEED, + FIX_MODE, + SATS_IN_USE, + SATS_IN_VIEW, + UNIX_SECONDS, + YEAR, + MONTH, + DAY, + HOURS, + MINUTES, + SECONDS, + SKYVIEW_UNIX_SECONDS, + PRN_ID, + AZIMUTH, + ELEVATION, + SIGNAL2NOISE, + USED, }; +static constexpr uint8_t CORE_DATASET_ENTRIES = 14; +static constexpr uint8_t SKYVIEW_ENTRIES = 6; + +static constexpr uint8_t MAX_SATELLITES = 30; + enum GpsFixModes : uint8_t { INVALID = 0, NO_FIX = 1, FIX_2D = 2, FIX_3D = 3 }; } // namespace GpsHyperion -class GpsPrimaryDataset : public StaticLocalDataSet<18> { +class GpsPrimaryDataset : public StaticLocalDataSet { public: - GpsPrimaryDataset(object_id_t gpsId) : StaticLocalDataSet(sid_t(gpsId, GpsHyperion::DATASET_ID)) { + GpsPrimaryDataset(object_id_t gpsId) + : StaticLocalDataSet(sid_t(gpsId, GpsHyperion::CORE_DATASET)) { setAllVariablesReadOnly(); } @@ -69,7 +84,34 @@ class GpsPrimaryDataset : public StaticLocalDataSet<18> { friend class GpsHyperionLinuxController; friend class GpsCtrlDummy; GpsPrimaryDataset(HasLocalDataPoolIF* hkOwner) - : StaticLocalDataSet(hkOwner, GpsHyperion::DATASET_ID) {} + : StaticLocalDataSet(hkOwner, GpsHyperion::CORE_DATASET) {} +}; + +class SkyviewDataset : public StaticLocalDataSet { + public: + SkyviewDataset(object_id_t gpsId) + : StaticLocalDataSet(sid_t(gpsId, GpsHyperion::SKYVIEW_DATASET)) { + setAllVariablesReadOnly(); + } + + lp_var_t unixSeconds = + lp_var_t(sid.objectId, GpsHyperion::SKYVIEW_UNIX_SECONDS, this); + lp_vec_t prn_id = + lp_vec_t(sid.objectId, GpsHyperion::PRN_ID, this); + lp_vec_t azimuth = + lp_vec_t(sid.objectId, GpsHyperion::AZIMUTH, this); + lp_vec_t elevation = + lp_vec_t(sid.objectId, GpsHyperion::ELEVATION, this); + lp_vec_t signal2noise = + lp_vec_t(sid.objectId, GpsHyperion::SIGNAL2NOISE, this); + lp_vec_t used = + lp_vec_t(sid.objectId, GpsHyperion::USED, this); + + private: + friend class GpsHyperionLinuxController; + friend class GpsCtrlDummy; + SkyviewDataset(HasLocalDataPoolIF* hkOwner) + : StaticLocalDataSet(hkOwner, GpsHyperion::SKYVIEW_DATASET) {} }; #endif /* MISSION_ACS_ARCHIVE_GPSDEFINITIONS_H_ */ diff --git a/mission/acs/defs.h b/mission/acs/defs.h index 677ce37a..baed276d 100644 --- a/mission/acs/defs.h +++ b/mission/acs/defs.h @@ -42,6 +42,13 @@ enum SafeModeStrategy : uint8_t { SAFECTRL_DETUMBLE_DETERIORATED = 21, }; +enum GpsSource : uint8_t { + NONE, + GPS, + GPS_EXTRAPOLATED, + SPG4, +}; + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::ACS_SUBSYSTEM; //! [EXPORT] : [COMMENT] The limits for the rotation in safe mode were violated. static constexpr Event SAFE_RATE_VIOLATION = MAKE_EVENT(0, severity::MEDIUM); @@ -64,6 +71,8 @@ static constexpr Event MEKF_INVALID_MODE_VIOLATION = MAKE_EVENT(6, severity::HIG //! failed. //! P1: Missing information about magnetic field, P2: Missing information about rotational rate static constexpr Event SAFE_MODE_CONTROLLER_FAILURE = MAKE_EVENT(7, severity::HIGH); +//! [EXPORT] : [COMMENT] The TLE for the SGP4 Propagator has become too old. +static constexpr Event TLE_TOO_OLD = MAKE_EVENT(8, severity::INFO); extern const char* getModeStr(AcsMode mode); diff --git a/mission/controller/AcsController.cpp b/mission/controller/AcsController.cpp index 08e8760d..1350bcf0 100644 --- a/mission/controller/AcsController.cpp +++ b/mission/controller/AcsController.cpp @@ -22,7 +22,8 @@ AcsController::AcsController(object_id_t objectId, bool enableHkSets) mekfData(this), ctrlValData(this), actuatorCmdData(this), - fusedRotRateData(this) {} + fusedRotRateData(this), + tleData(this) {} ReturnValue_t AcsController::initialize() { ReturnValue_t result = parameterHelper.initialize(); @@ -62,6 +63,26 @@ ReturnValue_t AcsController::executeAction(ActionId_t actionId, MessageQueueId_t mekfLost = false; return HasActionsIF::EXECUTION_FINISHED; } + case UPDATE_TLE: { + if (size != 69 * 2) { + return INVALID_PARAMETERS; + } + ReturnValue_t result = navigation.updateTle(data, data + 69); + if (result != returnvalue::OK) { + PoolReadGuard pg(&tleData); + navigation.updateTle(tleData.line1.value, tleData.line2.value); + return result; + } + { + PoolReadGuard pg(&tleData); + if (pg.getReadResult() == returnvalue::OK) { + std::memcpy(tleData.line1.value, data, 69); + std::memcpy(tleData.line2.value, data + 69, 69); + tleData.setValidity(true, true); + } + } + return HasActionsIF::EXECUTION_FINISHED; + } default: { return HasActionsIF::INVALID_ACTION_ID; } @@ -146,12 +167,19 @@ void AcsController::performSafe() { timeval now; Clock::getClock_timeval(&now); + ReturnValue_t result = navigation.useSpg4(now, &gpsDataProcessed); + if (result == Sgp4Propagator::TLE_TOO_OLD and not tleTooOldFlag) { + triggerEvent(acs::TLE_TOO_OLD); + tleTooOldFlag = true; + } else if (result != Sgp4Propagator::TLE_TOO_OLD) { + tleTooOldFlag = false; + } sensorProcessing.process(now, &sensorValues, &mgmDataProcessed, &susDataProcessed, &gyrDataProcessed, &gpsDataProcessed, &acsParameters); fusedRotationEstimation.estimateFusedRotationRateSafe(&susDataProcessed, &mgmDataProcessed, &gyrDataProcessed, &fusedRotRateData); - ReturnValue_t result = navigation.useMekf(&sensorValues, &gyrDataProcessed, &mgmDataProcessed, - &susDataProcessed, &mekfData, &acsParameters); + result = navigation.useMekf(&sensorValues, &gyrDataProcessed, &mgmDataProcessed, + &susDataProcessed, &mekfData, &acsParameters); if (result != MultiplicativeKalmanFilter::MEKF_RUNNING && result != MultiplicativeKalmanFilter::MEKF_INITIALIZED) { if (not mekfInvalidFlag) { @@ -176,8 +204,7 @@ void AcsController::performSafe() { acs::SafeModeStrategy safeCtrlStrat = safeCtrl.safeCtrlStrategy( mgmDataProcessed.mgmVecTot.isValid(), not mekfInvalidFlag, gyrDataProcessed.gyrVecTot.isValid(), susDataProcessed.susVecTot.isValid(), - fusedRotRateData.rotRateOrthogonal.isValid(), fusedRotRateData.rotRateTotal.isValid(), - acsParameters.safeModeControllerParameters.useMekf, + fusedRotRateData.rotRateTotal.isValid(), acsParameters.safeModeControllerParameters.useMekf, acsParameters.safeModeControllerParameters.useGyr, acsParameters.safeModeControllerParameters.dampingDuringEclipse); switch (safeCtrlStrat) { @@ -195,7 +222,8 @@ void AcsController::performSafe() { safeCtrlFailureCounter = 0; break; case (acs::SafeModeStrategy::SAFECTRL_SUSMGM): - safeCtrl.safeSusMgm(mgmDataProcessed.mgmVecTot.value, fusedRotRateData.rotRateParallel.value, + safeCtrl.safeSusMgm(mgmDataProcessed.mgmVecTot.value, fusedRotRateData.rotRateTotal.value, + fusedRotRateData.rotRateParallel.value, fusedRotRateData.rotRateOrthogonal.value, susDataProcessed.susVecTot.value, sunTargetDir, magMomMtq, errAng); safeCtrlFailureFlag = false; @@ -271,12 +299,19 @@ void AcsController::performDetumble() { timeval now; Clock::getClock_timeval(&now); + ReturnValue_t result = navigation.useSpg4(now, &gpsDataProcessed); + if (result == Sgp4Propagator::TLE_TOO_OLD and not tleTooOldFlag) { + triggerEvent(acs::TLE_TOO_OLD); + tleTooOldFlag = true; + } else { + tleTooOldFlag = false; + } sensorProcessing.process(now, &sensorValues, &mgmDataProcessed, &susDataProcessed, &gyrDataProcessed, &gpsDataProcessed, &acsParameters); fusedRotationEstimation.estimateFusedRotationRateSafe(&susDataProcessed, &mgmDataProcessed, &gyrDataProcessed, &fusedRotRateData); - ReturnValue_t result = navigation.useMekf(&sensorValues, &gyrDataProcessed, &mgmDataProcessed, - &susDataProcessed, &mekfData, &acsParameters); + result = navigation.useMekf(&sensorValues, &gyrDataProcessed, &mgmDataProcessed, + &susDataProcessed, &mekfData, &acsParameters); if (result != MultiplicativeKalmanFilter::MEKF_RUNNING && result != MultiplicativeKalmanFilter::MEKF_INITIALIZED) { if (not mekfInvalidFlag) { @@ -357,10 +392,17 @@ void AcsController::performPointingCtrl() { timeval now; Clock::getClock_timeval(&now); + ReturnValue_t result = navigation.useSpg4(now, &gpsDataProcessed); + if (result == Sgp4Propagator::TLE_TOO_OLD and not tleTooOldFlag) { + triggerEvent(acs::TLE_TOO_OLD); + tleTooOldFlag = true; + } else { + tleTooOldFlag = false; + } sensorProcessing.process(now, &sensorValues, &mgmDataProcessed, &susDataProcessed, &gyrDataProcessed, &gpsDataProcessed, &acsParameters); - ReturnValue_t result = navigation.useMekf(&sensorValues, &gyrDataProcessed, &mgmDataProcessed, - &susDataProcessed, &mekfData, &acsParameters); + result = navigation.useMekf(&sensorValues, &gyrDataProcessed, &mgmDataProcessed, + &susDataProcessed, &mekfData, &acsParameters); if (result != MultiplicativeKalmanFilter::MEKF_RUNNING && result != MultiplicativeKalmanFilter::MEKF_INITIALIZED) { mekfInvalidCounter++; @@ -735,6 +777,7 @@ ReturnValue_t AcsController::initializeLocalDataPool(localpool::DataPool &localD localDataPoolMap.emplace(acsctrl::PoolIds::ALTITUDE, &altitude); localDataPoolMap.emplace(acsctrl::PoolIds::GPS_POSITION, &gpsPosition); localDataPoolMap.emplace(acsctrl::PoolIds::GPS_VELOCITY, &gpsVelocity); + localDataPoolMap.emplace(acsctrl::PoolIds::SOURCE, &gpsSource); poolManager.subscribeForRegularPeriodicPacket({gpsDataProcessed.getSid(), enableHkSets, 30.0}); // MEKF localDataPoolMap.emplace(acsctrl::PoolIds::QUAT_MEKF, &quatMekf); @@ -758,6 +801,9 @@ ReturnValue_t AcsController::initializeLocalDataPool(localpool::DataPool &localD localDataPoolMap.emplace(acsctrl::PoolIds::ROT_RATE_PARALLEL, &rotRateParallel); localDataPoolMap.emplace(acsctrl::PoolIds::ROT_RATE_TOTAL, &rotRateTotal); poolManager.subscribeForRegularPeriodicPacket({fusedRotRateData.getSid(), enableHkSets, 10.0}); + // TLE Data + localDataPoolMap.emplace(acsctrl::PoolIds::TLE_LINE_1, &line1); + localDataPoolMap.emplace(acsctrl::PoolIds::TLE_LINE_2, &line2); return returnvalue::OK; } diff --git a/mission/controller/AcsController.h b/mission/controller/AcsController.h index a7dfbf6a..e03f2a55 100644 --- a/mission/controller/AcsController.h +++ b/mission/controller/AcsController.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -61,6 +62,7 @@ class AcsController : public ExtendedControllerBase, public ReceivesParameterMes ParameterHelper parameterHelper; + bool tleTooOldFlag = false; uint8_t detumbleCounter = 0; uint8_t multipleRwUnavailableCounter = 0; bool mekfInvalidFlag = false; @@ -84,6 +86,7 @@ class AcsController : public ExtendedControllerBase, public ReceivesParameterMes static const DeviceCommandId_t SOLAR_ARRAY_DEPLOYMENT_SUCCESSFUL = 0x0; static const DeviceCommandId_t RESET_MEKF = 0x1; static const DeviceCommandId_t RESTORE_MEKF_NONFINITE_RECOVERY = 0x2; + static const DeviceCommandId_t UPDATE_TLE = 0x3; static const uint8_t INTERFACE_ID = CLASS_ID::ACS_CTRL; //! [EXPORT] : [COMMENT] File deletion failed and at least one file is still existent. @@ -207,6 +210,7 @@ class AcsController : public ExtendedControllerBase, public ReceivesParameterMes PoolEntry altitude = PoolEntry(); PoolEntry gpsPosition = PoolEntry(3); PoolEntry gpsVelocity = PoolEntry(3); + PoolEntry gpsSource = PoolEntry(); // MEKF acsctrl::MekfData mekfData; @@ -234,6 +238,11 @@ class AcsController : public ExtendedControllerBase, public ReceivesParameterMes PoolEntry rotRateParallel = PoolEntry(3); PoolEntry rotRateTotal = PoolEntry(3); + // TLE Dataset + acsctrl::TleData tleData; + PoolEntry line1 = PoolEntry(69); + PoolEntry line2 = PoolEntry(69); + // Initial delay to make sure all pool variables have been initialized their owners Countdown initialCountdown = Countdown(INIT_DELAY); }; diff --git a/mission/controller/ThermalController.cpp b/mission/controller/ThermalController.cpp index 5f2277a9..2729cec0 100644 --- a/mission/controller/ThermalController.cpp +++ b/mission/controller/ThermalController.cpp @@ -1372,12 +1372,13 @@ void ThermalController::ctrlPlPcduBoard() { tooHotHandler(objects::PLPCDU_HANDLER, tooHotFlags.eBandTooHotFlag); } +// ToDo: remove one of the following 2 void ThermalController::ctrlPlocMissionBoard() { ctrlCtx.thermalComponent = tcsCtrl::PLOCMISSION_BOARD; - sensors[0].first = sensorTemperatures.plocHeatspreader.isValid(); - sensors[0].second = sensorTemperatures.plocHeatspreader.value; - sensors[1].first = sensorTemperatures.plocMissionboard.isValid(); - sensors[1].second = sensorTemperatures.plocMissionboard.value; + sensors[0].first = sensorTemperatures.plocMissionboard.isValid(); + sensors[0].second = sensorTemperatures.plocMissionboard.value; + sensors[1].first = sensorTemperatures.plocHeatspreader.isValid(); + sensors[1].second = sensorTemperatures.plocHeatspreader.value; sensors[2].first = sensorTemperatures.dacHeatspreader.isValid(); sensors[2].second = sensorTemperatures.dacHeatspreader.value; numSensors = 3; diff --git a/mission/controller/acs/AcsParameters.cpp b/mission/controller/acs/AcsParameters.cpp index bcb1a7f4..7b867a46 100644 --- a/mission/controller/acs/AcsParameters.cpp +++ b/mission/controller/acs/AcsParameters.cpp @@ -113,6 +113,9 @@ ReturnValue_t AcsParameters::getParameter(uint8_t domainId, uint8_t parameterId, case 0x13: parameterWrapper->set(mgmHandlingParameters.mgmDerivativeFilterWeight); break; + case 0x14: + parameterWrapper->set(mgmHandlingParameters.useMgm4); + break; default: return INVALID_IDENTIFIER_ID; } @@ -665,6 +668,9 @@ ReturnValue_t AcsParameters::getParameter(uint8_t domainId, uint8_t parameterId, case 0x3: parameterWrapper->set(gpsParameters.fdirAltitude); break; + case 0x4: + parameterWrapper->set(gpsParameters.useSpg4); + break; default: return INVALID_IDENTIFIER_ID; } diff --git a/mission/controller/acs/AcsParameters.h b/mission/controller/acs/AcsParameters.h index 0f2b53c9..a9c9ab5d 100644 --- a/mission/controller/acs/AcsParameters.h +++ b/mission/controller/acs/AcsParameters.h @@ -79,7 +79,8 @@ class AcsParameters : public HasParametersIF { float mgm13variance[3] = {pow(1.5e-8, 2), pow(1.5e-8, 2), pow(1.5e-8, 2)}; float mgm4variance[3] = {pow(1.7e-6, 2), pow(1.7e-6, 2), pow(1.7e-6, 2)}; float mgmVectorFilterWeight = 0.85; - float mgmDerivativeFilterWeight = 0.85; + float mgmDerivativeFilterWeight = 0.99; + uint8_t useMgm4 = false; } mgmHandlingParameters; struct SusHandlingParameters { @@ -770,7 +771,7 @@ class AcsParameters : public HasParametersIF { -0.000889232196185857, -0.00168429567131815}}; float susBrightnessThreshold = 0.7; float susVectorFilterWeight = .85; - float susRateFilterWeight = .85; + float susRateFilterWeight = .99; } susHandlingParameters; struct GyrHandlingParameters { @@ -833,15 +834,15 @@ class AcsParameters : public HasParametersIF { double k_alignGyr = 4.0e-5; double k_parallelGyr = 3.75e-4; - double k_orthoSusMgm = 1.1e-2; - double k_alignSusMgm = 2.0e-5; - double k_parallelSusMgm = 4.4e-4; + double k_orthoSusMgm = 4.4e-3; + double k_alignSusMgm = 4.0e-5; + double k_parallelSusMgm = 3.75e-4; double sunTargetDirLeop[3] = {0, sqrt(.5), sqrt(.5)}; double sunTargetDir[3] = {0, 0, 1}; uint8_t useMekf = false; - uint8_t useGyr = true; + uint8_t useGyr = false; uint8_t dampingDuringEclipse = true; float sineLimitSunRotRate = 0.24; @@ -916,6 +917,7 @@ class AcsParameters : public HasParametersIF { double minimumFdirAltitude = 475 * 1e3; // [m] double maximumFdirAltitude = 575 * 1e3; // [m] double fdirAltitude = 525 * 1e3; // [m] + uint8_t useSpg4 = true; } gpsParameters; struct SunModelParameters { diff --git a/mission/controller/acs/Navigation.cpp b/mission/controller/acs/Navigation.cpp index 7c822409..4726586b 100644 --- a/mission/controller/acs/Navigation.cpp +++ b/mission/controller/acs/Navigation.cpp @@ -44,3 +44,40 @@ ReturnValue_t Navigation::useMekf(ACS::SensorValues *sensorValues, void Navigation::resetMekf(acsctrl::MekfData *mekfData) { mekfStatus = multiplicativeKalmanFilter.reset(mekfData); } + +ReturnValue_t Navigation::useSpg4(timeval now, acsctrl::GpsDataProcessed *gpsDataProcessed) { + double position[3] = {0, 0, 0}; + double velocity[3] = {0, 0, 0}; + ReturnValue_t result = sgp4Propagator.propagate(position, velocity, now, 0); + + if (result == returnvalue::OK) { + { + PoolReadGuard pg(gpsDataProcessed); + if (pg.getReadResult() == returnvalue::OK) { + gpsDataProcessed->source = acs::GpsSource::SPG4; + gpsDataProcessed->source.setValid(true); + std::memcpy(gpsDataProcessed->gpsPosition.value, position, 3 * sizeof(double)); + gpsDataProcessed->gpsPosition.setValid(true); + std::memcpy(gpsDataProcessed->gpsVelocity.value, velocity, 3 * sizeof(double)); + gpsDataProcessed->gpsVelocity.setValid(true); + } + } + } else { + { + PoolReadGuard pg(gpsDataProcessed); + if (pg.getReadResult() == returnvalue::OK) { + gpsDataProcessed->source = acs::GpsSource::NONE; + gpsDataProcessed->source.setValid(true); + std::memcpy(gpsDataProcessed->gpsPosition.value, position, 3 * sizeof(double)); + gpsDataProcessed->gpsPosition.setValid(false); + std::memcpy(gpsDataProcessed->gpsVelocity.value, velocity, 3 * sizeof(double)); + gpsDataProcessed->gpsVelocity.setValid(false); + } + } + } + return result; +} + +ReturnValue_t Navigation::updateTle(const uint8_t *line1, const uint8_t *line2) { + return sgp4Propagator.initialize(line1, line2); +} diff --git a/mission/controller/acs/Navigation.h b/mission/controller/acs/Navigation.h index b567fbdd..2785ff2e 100644 --- a/mission/controller/acs/Navigation.h +++ b/mission/controller/acs/Navigation.h @@ -1,11 +1,13 @@ #ifndef NAVIGATION_H_ #define NAVIGATION_H_ -#include "../controllerdefinitions/AcsCtrlDefinitions.h" -#include "AcsParameters.h" -#include "MultiplicativeKalmanFilter.h" -#include "SensorProcessing.h" -#include "SensorValues.h" +#include +#include +#include +#include +#include +#include +#include class Navigation { public: @@ -19,10 +21,14 @@ class Navigation { AcsParameters *acsParameters); void resetMekf(acsctrl::MekfData *mekfData); + ReturnValue_t useSpg4(timeval now, acsctrl::GpsDataProcessed *gpsDataProcessed); + ReturnValue_t updateTle(const uint8_t *line1, const uint8_t *line2); + protected: private: MultiplicativeKalmanFilter multiplicativeKalmanFilter; ReturnValue_t mekfStatus = MultiplicativeKalmanFilter::MEKF_UNINITIALIZED; + Sgp4Propagator sgp4Propagator; }; #endif /* ACS_NAVIGATION_H_ */ diff --git a/mission/controller/acs/SensorProcessing.cpp b/mission/controller/acs/SensorProcessing.cpp index 511cae35..4405790c 100644 --- a/mission/controller/acs/SensorProcessing.cpp +++ b/mission/controller/acs/SensorProcessing.cpp @@ -1,19 +1,5 @@ #include "SensorProcessing.h" -#include -#include -#include -#include -#include -#include -#include - -#include "../controllerdefinitions/AcsCtrlDefinitions.h" -#include "Igrf13Model.h" -#include "util/MathOperations.h" - -using namespace Math; - SensorProcessing::SensorProcessing() {} SensorProcessing::~SensorProcessing() {} @@ -24,21 +10,23 @@ void SensorProcessing::processMgm(const float *mgm0Value, bool mgm0valid, const bool mgm4valid, timeval timeOfMgmMeasurement, const AcsParameters::MgmHandlingParameters *mgmParameters, acsctrl::GpsDataProcessed *gpsDataProcessed, - const double gpsAltitude, bool gpsValid, acsctrl::MgmDataProcessed *mgmDataProcessed) { // ---------------- IGRF- 13 Implementation here // ------------------------------------------------ double magIgrfModel[3] = {0.0, 0.0, 0.0}; - if (gpsValid) { + bool gpsValid = false; + if (gpsDataProcessed->source.value != acs::GpsSource::NONE) { Igrf13Model igrf13; igrf13.schmidtNormalization(); igrf13.updateCoeffGH(timeOfMgmMeasurement); // maybe put a condition here, to only update after a full day, this // class function has around 700 steps to perform igrf13.magFieldComp(gpsDataProcessed->gdLongitude.value, gpsDataProcessed->gcLatitude.value, - gpsAltitude, timeOfMgmMeasurement, magIgrfModel); + gpsDataProcessed->altitude.value, timeOfMgmMeasurement, magIgrfModel); + gpsValid = true; } - if (!mgm0valid && !mgm1valid && !mgm2valid && !mgm3valid && !mgm4valid) { + if (not mgm0valid and not mgm1valid and not mgm2valid and not mgm3valid and + (not mgm4valid or not mgmParameters->useMgm4)) { { PoolReadGuard pg(mgmDataProcessed); if (pg.getReadResult() == returnvalue::OK) { @@ -54,6 +42,7 @@ void SensorProcessing::processMgm(const float *mgm0Value, bool mgm0valid, const mgmDataProcessed->magIgrfModel.setValid(gpsValid); } } + std::memcpy(savedMgmVecTot, ZERO_VEC_D, sizeof(savedMgmVecTot)); return; } float mgm0ValueNoBias[3] = {0, 0, 0}, mgm1ValueNoBias[3] = {0, 0, 0}, @@ -113,7 +102,7 @@ void SensorProcessing::processMgm(const float *mgm0Value, bool mgm0valid, const sensorFusionDenominator[i] += 1 / mgmParameters->mgm13variance[i]; } } - if (mgm4valid) { + if (mgm4valid and mgmParameters->useMgm4) { float mgm4ValueUT[3]; VectorOperations::mulScalar(mgm4Value, 1e-3, mgm4ValueUT, 3); // nT to uT MatrixOperations::multiply(mgmParameters->mgm4orientationMatrix[0], mgm4ValueUT, @@ -141,14 +130,14 @@ void SensorProcessing::processMgm(const float *mgm0Value, bool mgm0valid, const double mgmVecTotDerivative[3] = {0.0, 0.0, 0.0}; bool mgmVecTotDerivativeValid = false; double timeDiff = timevalOperations::toDouble(timeOfMgmMeasurement - timeOfSavedMagFieldEst); - if (timeOfSavedMagFieldEst.tv_sec != 0 and timeDiff > 0) { - for (uint8_t i = 0; i < 3; i++) { - mgmVecTotDerivative[i] = (mgmVecTot[i] - savedMgmVecTot[i]) / timeDiff; - savedMgmVecTot[i] = mgmVecTot[i]; - mgmVecTotDerivativeValid = true; - } + if (timeOfSavedMagFieldEst.tv_sec != 0 and timeDiff > 0 and + VectorOperations::norm(savedMgmVecTot, 3) != 0) { + VectorOperations::subtract(mgmVecTot, savedMgmVecTot, mgmVecTotDerivative, 3); + VectorOperations::mulScalar(mgmVecTotDerivative, 1. / timeDiff, mgmVecTotDerivative, 3); + mgmVecTotDerivativeValid = true; } timeOfSavedMagFieldEst = timeOfMgmMeasurement; + std::memcpy(savedMgmVecTot, mgmVecTot, sizeof(savedMgmVecTot)); if (VectorOperations::norm(mgmVecTotDerivative, 3) != 0 and mgmDataProcessed->mgmVecTotDerivative.isValid()) { @@ -199,8 +188,8 @@ void SensorProcessing::processSus( double JC2000 = JD2000 / 36525.; double meanLongitude = - sunModelParameters->omega_0 + (sunModelParameters->domega * JC2000) * PI / 180.; - double meanAnomaly = (sunModelParameters->m_0 + sunModelParameters->dm * JC2000) * PI / 180.; + sunModelParameters->omega_0 + (sunModelParameters->domega * JC2000) * M_PI / 180.; + double meanAnomaly = (sunModelParameters->m_0 + sunModelParameters->dm * JC2000) * M_PI / 180.; double eclipticLongitude = meanLongitude + sunModelParameters->p1 * sin(meanAnomaly) + sunModelParameters->p2 * sin(2 * meanAnomaly); @@ -277,6 +266,7 @@ void SensorProcessing::processSus( susDataProcessed->sunIjkModel.setValid(true); } } + std::memcpy(savedSusVecTot, ZERO_VEC_D, sizeof(savedSusVecTot)); return; } @@ -365,13 +355,13 @@ void SensorProcessing::processSus( double susVecTotDerivative[3] = {0.0, 0.0, 0.0}; bool susVecTotDerivativeValid = false; double timeDiff = timevalOperations::toDouble(timeOfSusMeasurement - timeOfSavedSusDirEst); - if (timeOfSavedSusDirEst.tv_sec != 0 and timeDiff > 0) { - for (uint8_t i = 0; i < 3; i++) { - susVecTotDerivative[i] = (susVecTot[i] - savedSusVecTot[i]) / timeDiff; - savedSusVecTot[i] = susVecTot[i]; - susVecTotDerivativeValid = true; - } + if (timeOfSavedSusDirEst.tv_sec != 0 and timeDiff > 0 and + VectorOperations::norm(savedSusVecTot, 3) != 0) { + VectorOperations::subtract(susVecTot, savedSusVecTot, susVecTotDerivative, 3); + VectorOperations::mulScalar(susVecTotDerivative, 1. / timeDiff, susVecTotDerivative, 3); + susVecTotDerivativeValid = true; } + std::memcpy(savedSusVecTot, susVecTot, sizeof(savedSusVecTot)); if (VectorOperations::norm(susVecTotDerivative, 3) != 0 and susDataProcessed->susVecTotDerivative.isValid()) { lowPassFilter(susVecTotDerivative, susDataProcessed->susVecTotDerivative.value, @@ -535,14 +525,31 @@ void SensorProcessing::processGps(const double gpsLatitude, const double gpsLong const bool validGps, const AcsParameters::GpsParameters *gpsParameters, acsctrl::GpsDataProcessed *gpsDataProcessed) { - double gdLongitude = 0, gcLatitude = 0, altitude = 0, posSatE[3] = {0, 0, 0}, + // init variables + double gdLongitude = 0, gdLatitude = 0, gcLatitude = 0, altitude = 0, posSatE[3] = {0, 0, 0}, gpsVelocityE[3] = {0, 0, 0}; - if (validGps) { - // Transforming from Degree to Radians and calculation geocentric lattitude from geodetic - gdLongitude = gpsLongitude * PI / 180.; - double latitudeRad = gpsLatitude * PI / 180.; - double eccentricityWgs84 = 0.0818195; - double factor = 1 - pow(eccentricityWgs84, 2); + uint8_t gpsSource = acs::GpsSource::NONE; + // We do not trust the GPS and therefore it shall die here if SPG4 is running + if (gpsDataProcessed->source.value == acs::GpsSource::SPG4 and gpsParameters->useSpg4) { + MathOperations::latLongAltFromCartesian(gpsDataProcessed->gpsPosition.value, gdLatitude, + gdLongitude, altitude); + double factor = 1 - pow(ECCENTRICITY_WGS84, 2); + gcLatitude = atan(factor * tan(gdLatitude)); + { + PoolReadGuard pg(gpsDataProcessed); + if (pg.getReadResult() == returnvalue::OK) { + gpsDataProcessed->gdLongitude.value = gdLongitude; + gpsDataProcessed->gcLatitude.value = gcLatitude; + gpsDataProcessed->altitude.value = altitude; + gpsDataProcessed->setValidity(true, true); + } + } + return; + } else if (validGps) { + // Transforming from Degree to Radians and calculation geocentric latitude from geodetic + gdLongitude = gpsLongitude * M_PI / 180.; + double latitudeRad = gpsLatitude * M_PI / 180.; + double factor = 1 - pow(ECCENTRICITY_WGS84, 2); gcLatitude = atan(factor * tan(latitudeRad)); // Altitude FDIR @@ -569,6 +576,8 @@ void SensorProcessing::processGps(const double gpsLatitude, const double gpsLong timeOfSavedPosSatE = gpsUnixSeconds; validSavedPosSatE = true; + + gpsSource = acs::GpsSource::GPS; } { PoolReadGuard pg(gpsDataProcessed); @@ -579,6 +588,8 @@ void SensorProcessing::processGps(const double gpsLatitude, const double gpsLong std::memcpy(gpsDataProcessed->gpsPosition.value, posSatE, 3 * sizeof(double)); std::memcpy(gpsDataProcessed->gpsVelocity.value, gpsVelocityE, 3 * sizeof(double)); gpsDataProcessed->setValidity(validGps, true); + gpsDataProcessed->source.value = gpsSource; + gpsDataProcessed->source.setValid(true); } } } @@ -606,11 +617,7 @@ void SensorProcessing::process(timeval now, ACS::SensorValues *sensorValues, sensorValues->mgm3Rm3100Set.fieldStrengths.value, sensorValues->mgm3Rm3100Set.fieldStrengths.isValid(), sensorValues->imtqMgmSet.mtmRawNt.value, sensorValues->imtqMgmSet.mtmRawNt.isValid(), - now, &acsParameters->mgmHandlingParameters, gpsDataProcessed, - sensorValues->gpsSet.altitude.value, - (sensorValues->gpsSet.latitude.isValid() && sensorValues->gpsSet.longitude.isValid() && - sensorValues->gpsSet.altitude.isValid()), - mgmDataProcessed); + now, &acsParameters->mgmHandlingParameters, gpsDataProcessed, mgmDataProcessed); processSus(sensorValues->susSets[0].channels.value, sensorValues->susSets[0].channels.isValid(), sensorValues->susSets[1].channels.value, sensorValues->susSets[1].channels.isValid(), diff --git a/mission/controller/acs/SensorProcessing.h b/mission/controller/acs/SensorProcessing.h index 6dbc5d58..77ff2869 100644 --- a/mission/controller/acs/SensorProcessing.h +++ b/mission/controller/acs/SensorProcessing.h @@ -1,15 +1,23 @@ #ifndef SENSORPROCESSING_H_ #define SENSORPROCESSING_H_ +#include +#include +#include +#include +#include +#include +#include #include -#include //uint8_t -#include /*purpose, timeval ?*/ +#include +#include +#include +#include +#include +#include +#include -#include "../controllerdefinitions/AcsCtrlDefinitions.h" -#include "AcsParameters.h" -#include "SensorValues.h" -#include "SusConverter.h" -#include "eive/resultClassIds.h" +#include class SensorProcessing { public: @@ -25,6 +33,7 @@ class SensorProcessing { private: static constexpr float ZERO_VEC_F[3] = {0, 0, 0}; static constexpr double ZERO_VEC_D[3] = {0, 0, 0}; + static constexpr double ECCENTRICITY_WGS84 = 0.0818195; protected: // short description needed for every function @@ -32,8 +41,8 @@ class SensorProcessing { const float *mgm2Value, bool mgm2valid, const float *mgm3Value, bool mgm3valid, const float *mgm4Value, bool mgm4valid, timeval timeOfMgmMeasurement, const AcsParameters::MgmHandlingParameters *mgmParameters, - acsctrl::GpsDataProcessed *gpsDataProcessed, const double gpsAltitude, - bool gpsValid, acsctrl::MgmDataProcessed *mgmDataProcessed); + acsctrl::GpsDataProcessed *gpsDataProcessed, + acsctrl::MgmDataProcessed *mgmDataProcessed); void processSus(const uint16_t *sus0Value, bool sus0valid, const uint16_t *sus1Value, bool sus1valid, const uint16_t *sus2Value, bool sus2valid, diff --git a/mission/controller/acs/control/SafeCtrl.cpp b/mission/controller/acs/control/SafeCtrl.cpp index 8ad8b578..de0cd197 100644 --- a/mission/controller/acs/control/SafeCtrl.cpp +++ b/mission/controller/acs/control/SafeCtrl.cpp @@ -9,10 +9,12 @@ SafeCtrl::SafeCtrl(AcsParameters *acsParameters_) { acsParameters = acsParameter SafeCtrl::~SafeCtrl() {} -acs::SafeModeStrategy SafeCtrl::safeCtrlStrategy( - const bool magFieldValid, const bool mekfValid, const bool satRotRateValid, - const bool sunDirValid, const bool fusedRateSplitValid, const bool fusedRateTotalValid, - const uint8_t mekfEnabled, const uint8_t gyrEnabled, const uint8_t dampingEnabled) { +acs::SafeModeStrategy SafeCtrl::safeCtrlStrategy(const bool magFieldValid, const bool mekfValid, + const bool satRotRateValid, const bool sunDirValid, + const bool fusedRateTotalValid, + const uint8_t mekfEnabled, + const uint8_t gyrEnabled, + const uint8_t dampingEnabled) { if (not magFieldValid) { return acs::SafeModeStrategy::SAFECTRL_NO_MAG_FIELD_FOR_CONTROL; } else if (mekfEnabled and mekfValid) { @@ -20,7 +22,7 @@ acs::SafeModeStrategy SafeCtrl::safeCtrlStrategy( } else if (sunDirValid) { if (gyrEnabled and satRotRateValid) { return acs::SafeModeStrategy::SAFECTRL_GYR; - } else if (not gyrEnabled and fusedRateSplitValid) { + } else if (not gyrEnabled and fusedRateTotalValid) { return acs::SafeModeStrategy::SAFECTRL_SUSMGM; } else { return acs::SafeModeStrategy::SAFECTRL_NO_SENSORS_FOR_CONTROL; @@ -95,9 +97,10 @@ void SafeCtrl::safeGyr(const double *magFieldB, const double *satRotRateB, const calculateMagneticMoment(magMomB); } -void SafeCtrl::safeSusMgm(const double *magFieldB, const double *rotRateParallelB, - const double *rotRateOrthogonalB, const double *sunDirB, - const double *sunDirRefB, double *magMomB, double &errorAngle) { +void SafeCtrl::safeSusMgm(const double *magFieldB, const double *rotRateTotalB, + const double *rotRateParallelB, const double *rotRateOrthogonalB, + const double *sunDirB, const double *sunDirRefB, double *magMomB, + double &errorAngle) { // convert magFieldB from uT to T VectorOperations::mulScalar(magFieldB, 1e-6, magFieldBT, 3); @@ -105,8 +108,14 @@ void SafeCtrl::safeSusMgm(const double *magFieldB, const double *rotRateParallel double dotSun = VectorOperations::dot(sunDirRefB, sunDirB); errorAngle = acos(dotSun); - std::memcpy(satRotRateParallelB, rotRateParallelB, sizeof(satRotRateParallelB)); - std::memcpy(satRotRateOrthogonalB, rotRateOrthogonalB, sizeof(satRotRateOrthogonalB)); + if (VectorOperations::norm(rotRateParallelB, 3) != 0 and + VectorOperations::norm(rotRateOrthogonalB, 3) != 0) { + std::memcpy(satRotRateParallelB, rotRateParallelB, sizeof(satRotRateParallelB)); + std::memcpy(satRotRateOrthogonalB, rotRateOrthogonalB, sizeof(satRotRateOrthogonalB)); + } else { + splitRotationalRate(rotRateTotalB, sunDirB); + } + calculateRotationalRateTorque(acsParameters->safeModeControllerParameters.k_parallelSusMgm, acsParameters->safeModeControllerParameters.k_orthoSusMgm); calculateAngleErrorTorque(sunDirB, sunDirRefB, diff --git a/mission/controller/acs/control/SafeCtrl.h b/mission/controller/acs/control/SafeCtrl.h index 55bcbf08..d35d5d04 100644 --- a/mission/controller/acs/control/SafeCtrl.h +++ b/mission/controller/acs/control/SafeCtrl.h @@ -14,7 +14,6 @@ class SafeCtrl { acs::SafeModeStrategy safeCtrlStrategy(const bool magFieldValid, const bool mekfValid, const bool satRotRateValid, const bool sunDirValid, - const bool fusedRateSplitValid, const bool fusedRateTotalValid, const uint8_t mekfEnabled, const uint8_t gyrEnabled, const uint8_t dampingEnabled); @@ -25,9 +24,10 @@ class SafeCtrl { void safeGyr(const double *magFieldB, const double *satRotRateB, const double *sunDirB, const double *sunDirRefB, double *magMomB, double &errorAngle); - void safeSusMgm(const double *magFieldB, const double *rotRateParallelB, - const double *rotRateOrthogonalB, const double *sunDirB, const double *sunDirRefB, - double *magMomB, double &errorAngle); + void safeSusMgm(const double *magFieldB, const double *rotRateTotalB, + const double *rotRateParallelB, const double *rotRateOrthogonalB, + const double *sunDirB, const double *sunDirRefB, double *magMomB, + double &errorAngle); void safeRateDampingGyr(const double *magFieldB, const double *satRotRateB, const double *sunDirRefB, double *magMomB, double &errorAngle); diff --git a/mission/controller/acs/util/MathOperations.h b/mission/controller/acs/util/MathOperations.h index b344451a..dd4c3f57 100644 --- a/mission/controller/acs/util/MathOperations.h +++ b/mission/controller/acs/util/MathOperations.h @@ -3,14 +3,15 @@ #include #include -#include +#include #include #include #include +#include #include -using namespace Math; +#include "fsfw/serviceinterface.h" template class MathOperations { @@ -114,6 +115,44 @@ class MathOperations { cartesianOutput[1] = (auxRadius + alt) * cos(lat) * sin(longi); cartesianOutput[2] = ((1 - pow(eccentricity, 2)) * auxRadius + alt) * sin(lat); } + + static void latLongAltFromCartesian(const T1 *vector, T1 &latitude, T1 &longitude, T1 &altitude) { + /* @brief: latLongAltFromCartesian() - calculates latitude, longitude and altitude from + * cartesian coordinates in ECEF + * @param: x x-value of position vector [m] + * y y-value of position vector [m] + * z z-value of position vector [m] + * latitude geodetic latitude [rad] + * longitude longitude [rad] + * altitude altitude [m] + * @source: Fundamentals of Spacecraft Attitude Determination and Control, P.35 f + * Landis Markley and John L. Crassidis*/ + // From World Geodetic System the Earth Radii + double a = 6378137.0; // semimajor axis [m] + double b = 6356752.3142; // semiminor axis [m] + + // Calculation + double e2 = 1 - pow(b, 2) / pow(a, 2); + double epsilon2 = pow(a, 2) / pow(b, 2) - 1; + double rho = sqrt(pow(vector[0], 2) + pow(vector[1], 2)); + double p = std::abs(vector[2]) / epsilon2; + double s = pow(rho, 2) / (e2 * epsilon2); + double q = pow(p, 2) - pow(b, 2) + s; + double u = p / sqrt(q); + double v = pow(b, 2) * pow(u, 2) / q; + double P = 27 * v * s / q; + double Q = pow(sqrt(P + 1) + sqrt(P), 2. / 3.); + double t = (1 + Q + 1 / Q) / 6; + double c = sqrt(pow(u, 2) - 1 + 2 * t); + double w = (c - u) / 2; + double d = + sign(vector[2]) * sqrt(q) * (w + sqrt(sqrt(pow(t, 2) + v) - u * w - t / 2 - 1. / 4.)); + double N = a * sqrt(1 + epsilon2 * pow(d, 2) / pow(b, 2)); + latitude = asin((epsilon2 + 1) * d / N); + altitude = rho * cos(latitude) + vector[2] * sin(latitude) - pow(a, 2) / N; + longitude = atan2(vector[1], vector[0]); + } + static void dcmEJ(timeval time, T1 *outputDcmEJ, T1 *outputDotDcmEJ) { /* @brief: dcmEJ() - calculates the transformation matrix between ECEF and ECI frame * @param: time Current time @@ -140,7 +179,7 @@ class MathOperations { double FloorRest = floor(rest); double secOfDay = rest - FloorRest; secOfDay *= 86400; - gmst = secOfDay / 240 * PI / 180; + gmst = secOfDay / 240 * M_PI / 180; outputDcmEJ[0] = cos(gmst); outputDcmEJ[1] = sin(gmst); @@ -191,11 +230,11 @@ class MathOperations { double theta[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; // Earth Rotation angle double era = 0; - era = 2 * PI * (0.779057273264 + 1.00273781191135448 * JD2000UTC1); + era = 2 * M_PI * (0.779057273264 + 1.00273781191135448 * JD2000UTC1); // Greenwich Mean Sidereal Time double gmst2000 = 0.014506 + 4612.15739966 * JC2000TT + 1.39667721 * pow(JC2000TT, 2) - 0.00009344 * pow(JC2000TT, 3) + 0.00001882 * pow(JC2000TT, 4); - double arcsecFactor = 1 * PI / (180 * 3600); + double arcsecFactor = 1 * M_PI / (180 * 3600); gmst2000 *= arcsecFactor; gmst2000 += era; @@ -247,7 +286,7 @@ class MathOperations { double de = 9.203 * arcsecFactor * cos(Om); // % true obliquity of the ecliptic eps p.71 (simplified) - double e = 23.43929111 * PI / 180 - 46.8150 / 3600 * JC2000TT * PI / 180; + double e = 23.43929111 * M_PI / 180 - 46.8150 / 3600 * JC2000TT * M_PI / 180; nutation[0][0] = cos(dp); nutation[1][0] = cos(e + de) * sin(dp); diff --git a/mission/controller/controllerdefinitions/AcsCtrlDefinitions.h b/mission/controller/controllerdefinitions/AcsCtrlDefinitions.h index 86866c3f..b843ca0c 100644 --- a/mission/controller/controllerdefinitions/AcsCtrlDefinitions.h +++ b/mission/controller/controllerdefinitions/AcsCtrlDefinitions.h @@ -20,6 +20,7 @@ enum SetIds : uint32_t { CTRL_VAL_DATA, ACTUATOR_CMD_DATA, FUSED_ROTATION_RATE_DATA, + TLE_SET, }; enum PoolIds : lp_id_t { @@ -85,6 +86,7 @@ enum PoolIds : lp_id_t { GYR_3_VEC, GYR_VEC_TOT, // GPS Processed + SOURCE, GC_LATITUDE, GD_LONGITUDE, ALTITUDE, @@ -108,6 +110,9 @@ enum PoolIds : lp_id_t { ROT_RATE_ORTHOGONAL, ROT_RATE_PARALLEL, ROT_RATE_TOTAL, + // TLE + TLE_LINE_1, + TLE_LINE_2, }; static constexpr uint8_t MGM_SET_RAW_ENTRIES = 6; @@ -116,11 +121,12 @@ static constexpr uint8_t SUS_SET_RAW_ENTRIES = 12; static constexpr uint8_t SUS_SET_PROCESSED_ENTRIES = 15; static constexpr uint8_t GYR_SET_RAW_ENTRIES = 4; static constexpr uint8_t GYR_SET_PROCESSED_ENTRIES = 5; -static constexpr uint8_t GPS_SET_PROCESSED_ENTRIES = 5; +static constexpr uint8_t GPS_SET_PROCESSED_ENTRIES = 6; static constexpr uint8_t MEKF_SET_ENTRIES = 3; static constexpr uint8_t CTRL_VAL_SET_ENTRIES = 5; static constexpr uint8_t ACT_CMD_SET_ENTRIES = 3; static constexpr uint8_t FUSED_ROT_RATE_SET_ENTRIES = 3; +static constexpr uint8_t TLE_SET_ENTRIES = 2; /** * @brief Raw MGM sensor data. Includes the IMTQ sensor data and actuator status. @@ -239,6 +245,7 @@ class GpsDataProcessed : public StaticLocalDataSet { lp_var_t altitude = lp_var_t(sid.objectId, ALTITUDE, this); lp_vec_t gpsPosition = lp_vec_t(sid.objectId, GPS_POSITION, this); lp_vec_t gpsVelocity = lp_vec_t(sid.objectId, GPS_VELOCITY, this); + lp_var_t source = lp_var_t(sid.objectId, SOURCE, this); private: }; @@ -292,6 +299,16 @@ class FusedRotRateData : public StaticLocalDataSet { private: }; +class TleData : public StaticLocalDataSet { + public: + TleData(HasLocalDataPoolIF* hkOwner) : StaticLocalDataSet(hkOwner, TLE_SET) {} + + lp_vec_t line1 = lp_vec_t(sid.objectId, TLE_LINE_1, this); + lp_vec_t line2 = lp_vec_t(sid.objectId, TLE_LINE_1, this); + + private: +}; + } // namespace acsctrl #endif /* MISSION_CONTROLLER_CONTROLLERDEFINITIONS_ACSCTRLDEFINITIONS_H_ */ diff --git a/mission/power/gsLibDefs.h b/mission/power/gsLibDefs.h index cc9fc121..57525a39 100644 --- a/mission/power/gsLibDefs.h +++ b/mission/power/gsLibDefs.h @@ -8,12 +8,12 @@ // I really don't want to pull in all of those GomSpace headers just for 6 constants.. // Those are the headers which contain the defines which were just hardcoded below. -//#include "p60acu_hk.h" -//#include "p60acu_param.h" -//#include "p60dock_hk.h" -//#include "p60dock_param.h" -//#include "p60pdu_hk.h" -//#include "p60pdu_param.h" +// #include "p60acu_hk.h" +// #include "p60acu_param.h" +// #include "p60dock_hk.h" +// #include "p60dock_param.h" +// #include "p60pdu_hk.h" +// #include "p60pdu_param.h" #endif diff --git a/mission/system/EiveSystem.cpp b/mission/system/EiveSystem.cpp index 41f52cde..6519806e 100644 --- a/mission/system/EiveSystem.cpp +++ b/mission/system/EiveSystem.cpp @@ -133,6 +133,10 @@ void EiveSystem::handleEventMessages() { case pdec::INVALID_TC_FRAME: { if (event.getParameter1() == pdec::FRAME_DIRTY_RETVAL) { frameDirtyErrorCounter++; + // Check whether threshold was reached after 10 seconds. + if (frameDirtyErrorCounter == 1) { + frameDirtyCheckCd.resetTimer(); + } } break; } @@ -296,42 +300,39 @@ ReturnValue_t EiveSystem::sendFullRebootCommand() { } void EiveSystem::pdecRecoveryLogic() { - if (pdecResetWasAttempted and pdecResetWasAttemptedCd.hasTimedOut()) { - pdecResetWasAttempted = false; + // PDEC reset has happened too often in the last time. Perform reboot to same image. + if (pdecResetCounter >= PDEC_RESET_MAX_COUNT_BEFORE_REBOOT) { + if (waitingForPdecReboot) { + return; + } + triggerEvent(core::PDEC_REBOOT); + // Some delay to ensure that the event is stored in the persistent TM store as well. + TaskFactory::delayTask(500); + // Send reboot command. + ReturnValue_t result = sendSelfRebootCommand(); + if (result != returnvalue::OK) { + sif::error << "Sending a reboot command has failed" << std::endl; + // If the previous operation failed, it should be re-attempted the next task cycle. + pdecResetCounterResetCd.resetTimer(); + return; + } + waitingForPdecReboot = true; + return; } - if (frameDirtyCheckCd.hasTimedOut()) { + if (pdecResetCounterResetCd.hasTimedOut()) { + pdecResetCounter = 0; + } + if (frameDirtyCheckCd.hasTimedOut() and frameDirtyErrorCounter > 0) { if (frameDirtyErrorCounter >= FRAME_DIRTY_COM_REBOOT_LIMIT) { - // If a PTME reset was already attempted and there is still an issue receiving TC frames, - // reboot the system. - if (pdecResetWasAttempted) { - if (waitingForPdecReboot) { - return; - } - triggerEvent(core::PDEC_REBOOT); - // Some delay to ensure that the event is stored in the persistent TM store as well. - TaskFactory::delayTask(500); - // Send reboot command. - ReturnValue_t result = sendSelfRebootCommand(); - if (result != returnvalue::OK) { - sif::error << "Sending a reboot command has failed" << std::endl; - // If the previous operation failed, it should be re-attempted the next task cycle. - pdecResetWasAttemptedCd.resetTimer(); - return; - } - waitingForPdecReboot = true; - return; - } else { - // Try one full PDEC reset. - CommandMessage msg; - store_address_t dummy{}; - ActionMessage::setCommand(&msg, pdec::RESET_PDEC_WITH_REINIITALIZATION, dummy); - commandQueue->sendMessage(pdecHandlerQueueId, &msg); - pdecResetWasAttemptedCd.resetTimer(); - pdecResetWasAttempted = true; - } + // Try one full PDEC reset. + CommandMessage msg; + store_address_t dummy{}; + ActionMessage::setCommand(&msg, pdec::RESET_PDEC_WITH_REINIITALIZATION, dummy); + commandQueue->sendMessage(pdecHandlerQueueId, &msg); + pdecResetCounterResetCd.resetTimer(); + pdecResetCounter++; } frameDirtyErrorCounter = 0; - frameDirtyCheckCd.resetTimer(); } } diff --git a/mission/system/EiveSystem.h b/mission/system/EiveSystem.h index c724ba34..e6ff19b9 100644 --- a/mission/system/EiveSystem.h +++ b/mission/system/EiveSystem.h @@ -10,6 +10,7 @@ class EiveSystem : public Subsystem, public HasActionsIF { public: static constexpr uint8_t FRAME_DIRTY_COM_REBOOT_LIMIT = 4; + static constexpr uint32_t PDEC_RESET_MAX_COUNT_BEFORE_REBOOT = 10; static constexpr ActionId_t EXECUTE_I2C_REBOOT = 10; @@ -39,11 +40,11 @@ class EiveSystem : public Subsystem, public HasActionsIF { Countdown frameDirtyCheckCd = Countdown(10000); // If the PDEC reset was already attempted in the last 2 minutes, there is a high chance that // only a full reboot will fix the issue. - Countdown pdecResetWasAttemptedCd = Countdown(120000); - bool pdecResetWasAttempted = false; + Countdown pdecResetCounterResetCd = Countdown(120000); bool waitingForI2cReboot = false; bool waitingForPdecReboot = false; + uint32_t pdecResetCounter = 0; ActionHelper actionHelper; PowerSwitchIF* powerSwitcher = nullptr; std::atomic_uint16_t& i2cErrors; diff --git a/mission/tmtc/PersistentTmStore.cpp b/mission/tmtc/PersistentTmStore.cpp index 2f884dac..160348cd 100644 --- a/mission/tmtc/PersistentTmStore.cpp +++ b/mission/tmtc/PersistentTmStore.cpp @@ -320,6 +320,7 @@ ReturnValue_t PersistentTmStore::loadNextDumpFile() { } // File will change, reset this field for correct state-keeping. dumpParams.currentSameFileIdx = std::nullopt; + dumpParams.currentFileUnixStamp = dumpParams.dumpIter->epoch; // Increment iterator for next cycle. dumpParams.dumpIter++; };