Merge branch 'main' into soc-calculator
All checks were successful
EIVE/eive-obsw/pipeline/pr-main This commit looks good

This commit is contained in:
Marius Eggert 2023-09-13 13:07:43 +02:00
commit 2195beb045
62 changed files with 1067 additions and 354 deletions

View File

@ -16,6 +16,102 @@ will consitute of a breaking change warranting a new major release:
# [unreleased]
# [v6.5.1] 2023-09-12
- Bumped `eive-tmtc` to v5.5.0.
# [v6.5.0] 2023-09-12
## Changed
- 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.
- MGM3100 Startup Configuration: Ignore bit 1 of the CMM reply, which is sometimes set to
1 in the reply for some reason.
# [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
## Fixed
- Small SCEX fix: The temperatur check option was not passed
on for commands with a user data size larger than 1.
- SCEX: Properly check whether filesystem is usable for filesystem checks.
- ACS Controller strategy is now actually written to the dataset for detumbling.
- During detumble the fused rotation rate is now calculated.
- Detumbling is now exited when its exit value is undercut and not its entry value.
- Rotation rate of last cycle is now stored in all cases for the fused rotational rate
calculation.
- Fused rotation rate estimation during eclipse can be disabled. This will also prevent
detumbling during eclipse, as no relevant rotational rate is available for now.
- `EiveSystem`: Add a small delay between triggering an event for FDIR reboots and sending the
command to the core controller.
- PL PDU: Fixed bounds checking logic. Bound checks will only be performed for modules which are
enabled.
## Changed
- SCEX: Only perform filesystem checks when not in OFF mode.
- The `EiveSystem` now only sends reboot commands targetting the same image.
- Added 200 ms delay between switching HPA/MPA/TX/X8 and DRO GPIO pin OFF.
- PL PCDU ADC set is now automatically enabled for `NORMAL` mode transitions. It is automatically
disabled for `OFF` mode transitions.
## Added
- PL PCDU for EM build.
- SCEX: Add warning event if filesystem is unusable.
# [v6.2.0] 2023-07-26
- `eive-tmtc`: v5.3.1

View File

@ -10,8 +10,8 @@
cmake_minimum_required(VERSION 3.13)
set(OBSW_VERSION_MAJOR 6)
set(OBSW_VERSION_MINOR 2)
set(OBSW_VERSION_REVISION 0)
set(OBSW_VERSION_MINOR 5)
set(OBSW_VERSION_REVISION 1)
# set(CMAKE_VERBOSE TRUE)
@ -144,7 +144,7 @@ set(OBSW_ADD_RAD_SENSORS
${INIT_VAL}
CACHE STRING "Add Rad Sensor module")
set(OBSW_ADD_PL_PCDU
${INIT_VAL}
1
CACHE STRING "Add Payload PCDU modukle")
set(OBSW_ADD_SYRLINKS
1
@ -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()

View File

@ -1,7 +1,7 @@
/**
* @brief Auto-generated event translation file. Contains 301 translations.
* @brief Auto-generated event translation file. Contains 306 translations.
* @details
* Generated on: 2023-07-26 12:51:20
* Generated on: 2023-09-12 10:05:17
*/
#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";
@ -261,6 +263,7 @@ const char *TX_OFF_STRING = "TX_OFF";
const char *MISSING_PACKET_STRING = "MISSING_PACKET";
const char *EXPERIMENT_TIMEDOUT_STRING = "EXPERIMENT_TIMEDOUT";
const char *MULTI_PACKET_COMMAND_DONE_STRING = "MULTI_PACKET_COMMAND_DONE";
const char *FS_UNUSABLE_STRING = "FS_UNUSABLE";
const char *SET_CONFIGFILEVALUE_FAILED_STRING = "SET_CONFIGFILEVALUE_FAILED";
const char *GET_CONFIGFILEVALUE_FAILED_STRING = "GET_CONFIGFILEVALUE_FAILED";
const char *INSERT_CONFIGFILEVALUE_FAILED_STRING = "INSERT_CONFIGFILEVALUE_FAILED";
@ -306,6 +309,8 @@ const char *DUMP_NOK_CANCELLED_STRING = "DUMP_NOK_CANCELLED";
const char *DUMP_MISC_CANCELLED_STRING = "DUMP_MISC_CANCELLED";
const char *DUMP_HK_CANCELLED_STRING = "DUMP_HK_CANCELLED";
const char *DUMP_CFDP_CANCELLED_STRING = "DUMP_CFDP_CANCELLED";
const char *TEMPERATURE_ALL_ONES_START_STRING = "TEMPERATURE_ALL_ONES_START";
const char *TEMPERATURE_ALL_ONES_RECOVERY_STRING = "TEMPERATURE_ALL_ONES_RECOVERY";
const char *translateEvents(Event event) {
switch ((event & 0xFFFF)) {
@ -499,6 +504,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):
@ -633,6 +640,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):
@ -821,6 +830,8 @@ const char *translateEvents(Event event) {
return EXPERIMENT_TIMEDOUT_STRING;
case (13802):
return MULTI_PACKET_COMMAND_DONE_STRING;
case (13803):
return FS_UNUSABLE_STRING;
case (13901):
return SET_CONFIGFILEVALUE_FAILED_STRING;
case (13902):
@ -911,6 +922,10 @@ const char *translateEvents(Event event) {
return DUMP_HK_CANCELLED_STRING;
case (14314):
return DUMP_CFDP_CANCELLED_STRING;
case (14500):
return TEMPERATURE_ALL_ONES_START_STRING;
case (14501):
return TEMPERATURE_ALL_ONES_RECOVERY_STRING;
default:
return "UNKNOWN_EVENT";
}

View File

@ -2,7 +2,7 @@
* @brief Auto-generated object translation file.
* @details
* Contains 171 translations.
* Generated on: 2023-07-26 12:51:20
* Generated on: 2023-09-12 10:05:17
*/
#include "translateObjects.h"

View File

@ -94,6 +94,9 @@ void ObjectFactory::produce(void* args) {
#if OBSW_ADD_ACS_BOARD == 1
dummyCfg.addAcsBoardDummies = false;
#endif
#if OBSW_ADD_PL_PCDU == 0
dummyCfg.addPlPcduDummy = true;
#endif
PowerSwitchIF* pwrSwitcher = nullptr;
#if OBSW_ADD_GOMSPACE_PCDU == 0
@ -107,6 +110,9 @@ void ObjectFactory::produce(void* args) {
new CoreController(objects::CORE_CONTROLLER, enableHkSets);
auto* stackHandler = new Stack5VHandler(*pwrSwitcher);
static_cast<void>(stackHandler);
// Initialize chip select to avoid SPI bus issues.
createRadSensorChipSelect(gpioComIF);
@ -146,6 +152,9 @@ void ObjectFactory::produce(void* args) {
createStrComponents(pwrSwitcher);
#endif /* OBSW_ADD_STAR_TRACKER == 1 */
#if OBSW_ADD_PL_PCDU == 1
createPlPcduComponents(gpioComIF, spiMainComIF, pwrSwitcher, *stackHandler);
#endif
createPayloadComponents(gpioComIF, *pwrSwitcher);
#if OBSW_ADD_CCSDS_IP_CORES == 1

View File

@ -81,7 +81,9 @@ void ObjectFactory::produce(void* args) {
createTmpComponents(tmpDevsToAdd);
#endif
createSolarArrayDeploymentComponents(*pwrSwitcher, *gpioComIF);
#if OBSW_ADD_PL_PCDU == 1
createPlPcduComponents(gpioComIF, spiMainComIF, pwrSwitcher, *stackHandler);
#endif
#if OBSW_ADD_SYRLINKS == 1
createSyrlinksComponents(pwrSwitcher);
#endif /* OBSW_ADD_SYRLINKS == 1 */

View File

@ -902,8 +902,6 @@ void ObjectFactory::createPlPcduComponents(LinuxLibgpioIF* gpioComIF, SpiComIF*
new PayloadPcduHandler(objects::PLPCDU_HANDLER, objects::SPI_MAIN_COM_IF, spiCookie,
gpioComIF, SdCardManager::instance(), stackHandler, false);
spiCookie->setCallbackMode(PayloadPcduHandler::extConvAsTwoCallback, plPcduHandler);
// plPcduHandler->enablePeriodicPrintout(true, 5);
// static_cast<void>(plPcduHandler);
#if OBSW_TEST_PL_PCDU == 1
plPcduHandler->setStartUpImmediately();
#endif

View File

@ -40,6 +40,7 @@ enum : uint8_t {
COM_SUBSYSTEM = 142,
PERSISTENT_TM_STORE = 143,
SYRLINKS_COM = 144,
SUS_HANDLER = 145,
COMMON_SUBSYSTEM_ID_END
};

View File

@ -248,9 +248,11 @@ void dummy::createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitcher, GpioIF* gpio
auto* scexDummy = new ScexDummy(objects::SCEX, objects::DUMMY_COM_IF, comCookieDummy);
scexDummy->connectModeTreeParent(satsystem::payload::SUBSYSTEM);
}
auto* plPcduDummy =
new PlPcduDummy(objects::PLPCDU_HANDLER, objects::DUMMY_COM_IF, comCookieDummy);
plPcduDummy->connectModeTreeParent(satsystem::payload::SUBSYSTEM);
if (cfg.addPlPcduDummy) {
auto* plPcduDummy =
new PlPcduDummy(objects::PLPCDU_HANDLER, objects::DUMMY_COM_IF, comCookieDummy);
plPcduDummy->connectModeTreeParent(satsystem::payload::SUBSYSTEM);
}
if (cfg.addPlocDummies) {
auto* plocMpsocDummy =
new PlocMpsocDummy(objects::PLOC_MPSOC_HANDLER, objects::DUMMY_COM_IF, comCookieDummy);

View File

@ -30,6 +30,7 @@ struct DummyCfg {
bool addStrDummy = true;
bool addTmpDummies = true;
bool addRadSensorDummy = true;
bool addPlPcduDummy = false;
Tmp1075Cfg tmp1075Cfg;
bool addCamSwitcherDummy = false;
bool addScexDummy = false;

2
fsfw

@ -1 +1 @@
Subproject commit d575da85407e029dabecaffa5368f0c9f1034941
Subproject commit d246ce34d05ecc5c722fd127e61556374961c899

View File

@ -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
@ -255,6 +257,7 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path
13800;0x35e8;MISSING_PACKET;LOW;No description;mission/payload/scexHelpers.h
13801;0x35e9;EXPERIMENT_TIMEDOUT;LOW;No description;mission/payload/scexHelpers.h
13802;0x35ea;MULTI_PACKET_COMMAND_DONE;INFO;No description;mission/payload/scexHelpers.h
13803;0x35eb;FS_UNUSABLE;LOW;No description;mission/payload/scexHelpers.h
13901;0x364d;SET_CONFIGFILEVALUE_FAILED;MEDIUM;No description;mission/utility/GlobalConfigHandler.h
13902;0x364e;GET_CONFIGFILEVALUE_FAILED;MEDIUM;No description;mission/utility/GlobalConfigHandler.h
13903;0x364f;INSERT_CONFIGFILEVALUE_FAILED;MEDIUM;No description;mission/utility/GlobalConfigHandler.h
@ -300,3 +303,5 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path
14312;0x37e8;DUMP_MISC_CANCELLED;LOW;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h
14313;0x37e9;DUMP_HK_CANCELLED;LOW;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h
14314;0x37ea;DUMP_CFDP_CANCELLED;LOW;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h
14500;0x38a4;TEMPERATURE_ALL_ONES_START;MEDIUM;Detected invalid values, starting invalid message counting;mission/acs/SusHandler.h
14501;0x38a5;TEMPERATURE_ALL_ONES_RECOVERY;INFO;Detected valid values again, resetting invalid message counter. P1: Invalid message counter.;mission/acs/SusHandler.h

1 Event ID (dec) Event ID (hex) Name Severity Description File Path
94 11205 0x2bc5 MEKF_AUTOMATIC_RESET INFO MEKF performed an automatic reset after detection of nonfinite values. mission/acs/defs.h
95 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
96 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
97 11208 0x2bc8 TLE_TOO_OLD INFO The TLE for the SGP4 Propagator has become too old. mission/acs/defs.h
98 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
99 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
100 11302 0x2c26 SWITCHING_Q7S_DENIED MEDIUM No description mission/power/defs.h
162 12412 0x307c PDEC_RESET_FAILED HIGH Failed to pull PDEC reset to low linux/ipcore/pdec.h
163 12413 0x307d OPEN_IRQ_FILE_FAILED HIGH Failed to open the IRQ uio file linux/ipcore/pdec.h
164 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
165 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
166 12500 0x30d4 IMAGE_UPLOAD_FAILED LOW Image upload failed linux/acs/StrComHandler.h
167 12501 0x30d5 IMAGE_DOWNLOAD_FAILED LOW Image download failed linux/acs/StrComHandler.h
168 12502 0x30d6 IMAGE_UPLOAD_SUCCESSFUL LOW Uploading image to star tracker was successfulop linux/acs/StrComHandler.h
257 13800 0x35e8 MISSING_PACKET LOW No description mission/payload/scexHelpers.h
258 13801 0x35e9 EXPERIMENT_TIMEDOUT LOW No description mission/payload/scexHelpers.h
259 13802 0x35ea MULTI_PACKET_COMMAND_DONE INFO No description mission/payload/scexHelpers.h
260 13803 0x35eb FS_UNUSABLE LOW No description mission/payload/scexHelpers.h
261 13901 0x364d SET_CONFIGFILEVALUE_FAILED MEDIUM No description mission/utility/GlobalConfigHandler.h
262 13902 0x364e GET_CONFIGFILEVALUE_FAILED MEDIUM No description mission/utility/GlobalConfigHandler.h
263 13903 0x364f INSERT_CONFIGFILEVALUE_FAILED MEDIUM No description mission/utility/GlobalConfigHandler.h
303 14312 0x37e8 DUMP_MISC_CANCELLED LOW P1: Number of dumped packets. P2: Total dumped bytes. mission/persistentTmStoreDefs.h
304 14313 0x37e9 DUMP_HK_CANCELLED LOW P1: Number of dumped packets. P2: Total dumped bytes. mission/persistentTmStoreDefs.h
305 14314 0x37ea DUMP_CFDP_CANCELLED LOW P1: Number of dumped packets. P2: Total dumped bytes. mission/persistentTmStoreDefs.h
306 14500 0x38a4 TEMPERATURE_ALL_ONES_START MEDIUM Detected invalid values, starting invalid message counting mission/acs/SusHandler.h
307 14501 0x38a5 TEMPERATURE_ALL_ONES_RECOVERY INFO Detected valid values again, resetting invalid message counter. P1: Invalid message counter. mission/acs/SusHandler.h

View File

@ -60,3 +60,4 @@
142;COM_SUBSYSTEM
143;PERSISTENT_TM_STORE
144;SYRLINKS_COM
145;SUS_HANDLER

1 22 MEMORY
60 142 COM_SUBSYSTEM
61 143 PERSISTENT_TM_STORE
62 144 SYRLINKS_COM
63 145 SUS_HANDLER

View File

@ -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
@ -255,6 +257,7 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path
13800;0x35e8;MISSING_PACKET;LOW;No description;mission/payload/scexHelpers.h
13801;0x35e9;EXPERIMENT_TIMEDOUT;LOW;No description;mission/payload/scexHelpers.h
13802;0x35ea;MULTI_PACKET_COMMAND_DONE;INFO;No description;mission/payload/scexHelpers.h
13803;0x35eb;FS_UNUSABLE;LOW;No description;mission/payload/scexHelpers.h
13901;0x364d;SET_CONFIGFILEVALUE_FAILED;MEDIUM;No description;mission/utility/GlobalConfigHandler.h
13902;0x364e;GET_CONFIGFILEVALUE_FAILED;MEDIUM;No description;mission/utility/GlobalConfigHandler.h
13903;0x364f;INSERT_CONFIGFILEVALUE_FAILED;MEDIUM;No description;mission/utility/GlobalConfigHandler.h
@ -300,3 +303,5 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path
14312;0x37e8;DUMP_MISC_CANCELLED;LOW;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h
14313;0x37e9;DUMP_HK_CANCELLED;LOW;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h
14314;0x37ea;DUMP_CFDP_CANCELLED;LOW;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h
14500;0x38a4;TEMPERATURE_ALL_ONES_START;MEDIUM;Detected invalid values, starting invalid message counting;mission/acs/SusHandler.h
14501;0x38a5;TEMPERATURE_ALL_ONES_RECOVERY;INFO;Detected valid values again, resetting invalid message counter. P1: Invalid message counter.;mission/acs/SusHandler.h

1 Event ID (dec) Event ID (hex) Name Severity Description File Path
94 11205 0x2bc5 MEKF_AUTOMATIC_RESET INFO MEKF performed an automatic reset after detection of nonfinite values. mission/acs/defs.h
95 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
96 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
97 11208 0x2bc8 TLE_TOO_OLD INFO The TLE for the SGP4 Propagator has become too old. mission/acs/defs.h
98 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
99 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
100 11302 0x2c26 SWITCHING_Q7S_DENIED MEDIUM No description mission/power/defs.h
162 12412 0x307c PDEC_RESET_FAILED HIGH Failed to pull PDEC reset to low linux/ipcore/pdec.h
163 12413 0x307d OPEN_IRQ_FILE_FAILED HIGH Failed to open the IRQ uio file linux/ipcore/pdec.h
164 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
165 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
166 12500 0x30d4 IMAGE_UPLOAD_FAILED LOW Image upload failed linux/acs/StrComHandler.h
167 12501 0x30d5 IMAGE_DOWNLOAD_FAILED LOW Image download failed linux/acs/StrComHandler.h
168 12502 0x30d6 IMAGE_UPLOAD_SUCCESSFUL LOW Uploading image to star tracker was successfulop linux/acs/StrComHandler.h
257 13800 0x35e8 MISSING_PACKET LOW No description mission/payload/scexHelpers.h
258 13801 0x35e9 EXPERIMENT_TIMEDOUT LOW No description mission/payload/scexHelpers.h
259 13802 0x35ea MULTI_PACKET_COMMAND_DONE INFO No description mission/payload/scexHelpers.h
260 13803 0x35eb FS_UNUSABLE LOW No description mission/payload/scexHelpers.h
261 13901 0x364d SET_CONFIGFILEVALUE_FAILED MEDIUM No description mission/utility/GlobalConfigHandler.h
262 13902 0x364e GET_CONFIGFILEVALUE_FAILED MEDIUM No description mission/utility/GlobalConfigHandler.h
263 13903 0x364f INSERT_CONFIGFILEVALUE_FAILED MEDIUM No description mission/utility/GlobalConfigHandler.h
303 14312 0x37e8 DUMP_MISC_CANCELLED LOW P1: Number of dumped packets. P2: Total dumped bytes. mission/persistentTmStoreDefs.h
304 14313 0x37e9 DUMP_HK_CANCELLED LOW P1: Number of dumped packets. P2: Total dumped bytes. mission/persistentTmStoreDefs.h
305 14314 0x37ea DUMP_CFDP_CANCELLED LOW P1: Number of dumped packets. P2: Total dumped bytes. mission/persistentTmStoreDefs.h
306 14500 0x38a4 TEMPERATURE_ALL_ONES_START MEDIUM Detected invalid values, starting invalid message counting mission/acs/SusHandler.h
307 14501 0x38a5 TEMPERATURE_ALL_ONES_RECOVERY INFO Detected valid values again, resetting invalid message counter. P1: Invalid message counter. mission/acs/SusHandler.h

View File

@ -60,3 +60,4 @@
142;COM_SUBSYSTEM
143;PERSISTENT_TM_STORE
144;SYRLINKS_COM
145;SUS_HANDLER

1 22 MEMORY
60 142 COM_SUBSYSTEM
61 143 PERSISTENT_TM_STORE
62 144 SYRLINKS_COM
63 145 SUS_HANDLER

View File

@ -1,7 +1,7 @@
/**
* @brief Auto-generated event translation file. Contains 301 translations.
* @brief Auto-generated event translation file. Contains 306 translations.
* @details
* Generated on: 2023-07-26 12:51:20
* Generated on: 2023-09-12 10:05:17
*/
#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";
@ -261,6 +263,7 @@ const char *TX_OFF_STRING = "TX_OFF";
const char *MISSING_PACKET_STRING = "MISSING_PACKET";
const char *EXPERIMENT_TIMEDOUT_STRING = "EXPERIMENT_TIMEDOUT";
const char *MULTI_PACKET_COMMAND_DONE_STRING = "MULTI_PACKET_COMMAND_DONE";
const char *FS_UNUSABLE_STRING = "FS_UNUSABLE";
const char *SET_CONFIGFILEVALUE_FAILED_STRING = "SET_CONFIGFILEVALUE_FAILED";
const char *GET_CONFIGFILEVALUE_FAILED_STRING = "GET_CONFIGFILEVALUE_FAILED";
const char *INSERT_CONFIGFILEVALUE_FAILED_STRING = "INSERT_CONFIGFILEVALUE_FAILED";
@ -306,6 +309,8 @@ const char *DUMP_NOK_CANCELLED_STRING = "DUMP_NOK_CANCELLED";
const char *DUMP_MISC_CANCELLED_STRING = "DUMP_MISC_CANCELLED";
const char *DUMP_HK_CANCELLED_STRING = "DUMP_HK_CANCELLED";
const char *DUMP_CFDP_CANCELLED_STRING = "DUMP_CFDP_CANCELLED";
const char *TEMPERATURE_ALL_ONES_START_STRING = "TEMPERATURE_ALL_ONES_START";
const char *TEMPERATURE_ALL_ONES_RECOVERY_STRING = "TEMPERATURE_ALL_ONES_RECOVERY";
const char *translateEvents(Event event) {
switch ((event & 0xFFFF)) {
@ -499,6 +504,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):
@ -633,6 +640,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):
@ -821,6 +830,8 @@ const char *translateEvents(Event event) {
return EXPERIMENT_TIMEDOUT_STRING;
case (13802):
return MULTI_PACKET_COMMAND_DONE_STRING;
case (13803):
return FS_UNUSABLE_STRING;
case (13901):
return SET_CONFIGFILEVALUE_FAILED_STRING;
case (13902):
@ -911,6 +922,10 @@ const char *translateEvents(Event event) {
return DUMP_HK_CANCELLED_STRING;
case (14314):
return DUMP_CFDP_CANCELLED_STRING;
case (14500):
return TEMPERATURE_ALL_ONES_START_STRING;
case (14501):
return TEMPERATURE_ALL_ONES_RECOVERY_STRING;
default:
return "UNKNOWN_EVENT";
}

View File

@ -2,7 +2,7 @@
* @brief Auto-generated object translation file.
* @details
* Contains 175 translations.
* Generated on: 2023-07-26 12:51:20
* Generated on: 2023-09-12 10:05:17
*/
#include "translateObjects.h"

View File

@ -767,6 +767,9 @@ void AcsBoardPolling::mgmRm3100Handler(MgmRm3100& mgm) {
mgm.replyResult = result;
return;
}
// For some reason, bit 1 is sometimes set on the reply, even if it is not set for the
// command.. Ignore it for now by clearing it.
rawReply[1] &= ~(1 << 1);
if (rawReply[1] != mgmRm3100::CMM_VALUE) {
sif::error << "AcsBoardPolling: MGM RM3100 read back CMM invalid" << std::endl;
mgm.replyResult = result;

View File

@ -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<uint8_t>());
localDataPoolMap.emplace(GpsHyperion::FIX_MODE, new PoolEntry<uint8_t>());
poolManager.subscribeForRegularPeriodicPacket({gpsSet.getSid(), enableHkSets, 30.0});
localDataPoolMap.emplace(GpsHyperion::SKYVIEW_UNIX_SECONDS, new PoolEntry<double>());
localDataPoolMap.emplace(GpsHyperion::PRN_ID, new PoolEntry<int16_t>());
localDataPoolMap.emplace(GpsHyperion::AZIMUTH, new PoolEntry<int16_t>());
localDataPoolMap.emplace(GpsHyperion::ELEVATION, new PoolEntry<int16_t>());
localDataPoolMap.emplace(GpsHyperion::SIGNAL2NOISE, new PoolEntry<double>());
localDataPoolMap.emplace(GpsHyperion::USED, new PoolEntry<uint8_t>());
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()) {

View File

@ -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.

View File

@ -170,18 +170,12 @@ ReturnValue_t SusPolling::handleSusPolling() {
}
MutexGuard mg(ipcLock);
susDevs[idx].ownReply.tempRaw = ((rawReply[0] & 0x0f) << 8) | rawReply[1];
// Reply is all ones. Sensor is probably off or faulty when
// it should not be.
if (susDevs[idx].ownReply.tempRaw == 0x0fff) {
susDevs[idx].replyResult = returnvalue::FAILED;
} else {
susDevs[idx].replyResult = returnvalue::OK;
for (unsigned chIdx = 0; chIdx < 6; chIdx++) {
susDevs[idx].ownReply.channelsRaw[chIdx] =
(rawReply[chIdx * 2 + 2] << 8) | rawReply[chIdx * 2 + 3];
}
susDevs[idx].ownReply.dataWasSet = true;
susDevs[idx].replyResult = returnvalue::OK;
for (unsigned chIdx = 0; chIdx < 6; chIdx++) {
susDevs[idx].ownReply.channelsRaw[chIdx] =
(rawReply[chIdx * 2 + 2] << 8) | rawReply[chIdx * 2 + 3];
}
susDevs[idx].ownReply.dataWasSet = true;
}
}
return OK;

View File

@ -11,7 +11,7 @@
#include <array>
//#include "lwgps/lwgps.h"
// #include "lwgps/lwgps.h"
#include "test/TestTask.h"
class ScexUartReader;

View File

@ -1,7 +1,7 @@
/**
* @brief Auto-generated event translation file. Contains 301 translations.
* @brief Auto-generated event translation file. Contains 306 translations.
* @details
* Generated on: 2023-07-26 12:51:20
* Generated on: 2023-09-12 10:05:17
*/
#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";
@ -261,6 +263,7 @@ const char *TX_OFF_STRING = "TX_OFF";
const char *MISSING_PACKET_STRING = "MISSING_PACKET";
const char *EXPERIMENT_TIMEDOUT_STRING = "EXPERIMENT_TIMEDOUT";
const char *MULTI_PACKET_COMMAND_DONE_STRING = "MULTI_PACKET_COMMAND_DONE";
const char *FS_UNUSABLE_STRING = "FS_UNUSABLE";
const char *SET_CONFIGFILEVALUE_FAILED_STRING = "SET_CONFIGFILEVALUE_FAILED";
const char *GET_CONFIGFILEVALUE_FAILED_STRING = "GET_CONFIGFILEVALUE_FAILED";
const char *INSERT_CONFIGFILEVALUE_FAILED_STRING = "INSERT_CONFIGFILEVALUE_FAILED";
@ -306,6 +309,8 @@ const char *DUMP_NOK_CANCELLED_STRING = "DUMP_NOK_CANCELLED";
const char *DUMP_MISC_CANCELLED_STRING = "DUMP_MISC_CANCELLED";
const char *DUMP_HK_CANCELLED_STRING = "DUMP_HK_CANCELLED";
const char *DUMP_CFDP_CANCELLED_STRING = "DUMP_CFDP_CANCELLED";
const char *TEMPERATURE_ALL_ONES_START_STRING = "TEMPERATURE_ALL_ONES_START";
const char *TEMPERATURE_ALL_ONES_RECOVERY_STRING = "TEMPERATURE_ALL_ONES_RECOVERY";
const char *translateEvents(Event event) {
switch ((event & 0xFFFF)) {
@ -499,6 +504,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):
@ -633,6 +640,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):
@ -821,6 +830,8 @@ const char *translateEvents(Event event) {
return EXPERIMENT_TIMEDOUT_STRING;
case (13802):
return MULTI_PACKET_COMMAND_DONE_STRING;
case (13803):
return FS_UNUSABLE_STRING;
case (13901):
return SET_CONFIGFILEVALUE_FAILED_STRING;
case (13902):
@ -911,6 +922,10 @@ const char *translateEvents(Event event) {
return DUMP_HK_CANCELLED_STRING;
case (14314):
return DUMP_CFDP_CANCELLED_STRING;
case (14500):
return TEMPERATURE_ALL_ONES_START_STRING;
case (14501):
return TEMPERATURE_ALL_ONES_RECOVERY_STRING;
default:
return "UNKNOWN_EVENT";
}

View File

@ -2,7 +2,7 @@
* @brief Auto-generated object translation file.
* @details
* Contains 175 translations.
* Generated on: 2023-07-26 12:51:20
* Generated on: 2023-09-12 10:05:17
*/
#include "translateObjects.h"

View File

@ -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<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint32_t>(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);
}

View File

@ -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();
/**

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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<uint16_t>({0}));
localDataPoolMap.emplace(supv::ADC_ENG_15, new PoolEntry<uint16_t>({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;
// }

View File

@ -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);

View File

@ -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;

View File

@ -20,6 +20,9 @@ void SusHandler::doStartUp() {
}
if (internalState == InternalState::STARTUP) {
if (commandExecuted) {
if (waitingForRecovery) {
waitingForRecovery = false;
}
setMode(MODE_ON);
internalState = InternalState::NONE;
commandExecuted = false;
@ -83,15 +86,36 @@ ReturnValue_t SusHandler::scanForReply(const uint8_t *start, size_t len, DeviceC
}
ReturnValue_t SusHandler::interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) {
const auto *reply = reinterpret_cast<const acs::SusReply *>(packet);
if (reply->dataWasSet) {
if (internalState == InternalState::STARTUP) {
commandExecuted = true;
}
PoolReadGuard pg(&dataset);
dataset.setValidity(true, true);
dataset.tempC = max1227::getTemperature(reply->tempRaw);
std::memcpy(dataset.channels.value, reply->channelsRaw, sizeof(reply->channelsRaw));
if (!reply->dataWasSet) {
return returnvalue::OK;
}
if (internalState == InternalState::STARTUP) {
commandExecuted = true;
}
PoolReadGuard pg(&dataset);
// Simple FDIR variant to make the handler more robust to invalid messages which
// appear sometimes for the SUS device: Allow invalid message up to a certain threshold
// before triggering FDIR reactions.
if (reply->tempRaw == 0xfff and not waitingForRecovery) {
if (invalidMsgCounter == 0) {
triggerEvent(TEMPERATURE_ALL_ONES_START);
} else if (invalidMsgCounter == susMax1227::MAX_INVALID_MSG_COUNT) {
triggerEvent(DeviceHandlerIF::DEVICE_WANTS_HARD_REBOOT);
waitingForRecovery = true;
}
invalidMsgCounter++;
dataset.setValidity(false, true);
dataset.tempC = thermal::INVALID_TEMPERATURE;
std::memset(dataset.channels.value, 0, sizeof(dataset.channels.value));
return returnvalue::OK;
}
if (invalidMsgCounter > 0) {
triggerEvent(TEMPERATURE_ALL_ONES_RECOVERY, invalidMsgCounter);
invalidMsgCounter = 0;
}
dataset.setValidity(true, true);
dataset.tempC = max1227::getTemperature(reply->tempRaw);
std::memcpy(dataset.channels.value, reply->channelsRaw, sizeof(reply->channelsRaw));
return returnvalue::OK;
}

View File

@ -15,7 +15,15 @@ class SusHandler : public DeviceHandlerBase {
static constexpr DeviceCommandId_t REPLY = 0x77;
static const uint8_t INTERFACE_ID = CLASS_ID::SUS_HANDLER;
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SUS_BOARD_ASS;
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SUS_HANDLER;
//! [EXPORT] : [COMMENT] Detected invalid values, starting invalid message counting
static constexpr Event TEMPERATURE_ALL_ONES_START =
event::makeEvent(SUBSYSTEM_ID, 0, severity::MEDIUM);
//! [EXPORT] : [COMMENT] Detected valid values again, resetting invalid message counter.
//! P1: Invalid message counter.
static constexpr Event TEMPERATURE_ALL_ONES_RECOVERY =
event::makeEvent(SUBSYSTEM_ID, 1, severity::INFO);
SusHandler(uint32_t objectId, uint8_t susIdx, object_id_t deviceCommunication,
CookieIF *comCookie);
@ -46,6 +54,8 @@ class SusHandler : public DeviceHandlerBase {
susMax1227::SusDataset dataset;
acs::SusRequest request{};
uint8_t susIdx;
bool waitingForRecovery = true;
uint32_t invalidMsgCounter = 0;
uint32_t transitionDelay = 1000;
bool goToNormalMode = false;

View File

@ -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<GpsHyperion::CORE_DATASET_ENTRIES> {
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<GpsHyperion::SKYVIEW_ENTRIES> {
public:
SkyviewDataset(object_id_t gpsId)
: StaticLocalDataSet(sid_t(gpsId, GpsHyperion::SKYVIEW_DATASET)) {
setAllVariablesReadOnly();
}
lp_var_t<double> unixSeconds =
lp_var_t<double>(sid.objectId, GpsHyperion::SKYVIEW_UNIX_SECONDS, this);
lp_vec_t<int16_t, GpsHyperion::MAX_SATELLITES> prn_id =
lp_vec_t<int16_t, GpsHyperion::MAX_SATELLITES>(sid.objectId, GpsHyperion::PRN_ID, this);
lp_vec_t<int16_t, GpsHyperion::MAX_SATELLITES> azimuth =
lp_vec_t<int16_t, GpsHyperion::MAX_SATELLITES>(sid.objectId, GpsHyperion::AZIMUTH, this);
lp_vec_t<int16_t, GpsHyperion::MAX_SATELLITES> elevation =
lp_vec_t<int16_t, GpsHyperion::MAX_SATELLITES>(sid.objectId, GpsHyperion::ELEVATION, this);
lp_vec_t<double, GpsHyperion::MAX_SATELLITES> signal2noise =
lp_vec_t<double, GpsHyperion::MAX_SATELLITES>(sid.objectId, GpsHyperion::SIGNAL2NOISE, this);
lp_vec_t<uint8_t, GpsHyperion::MAX_SATELLITES> used =
lp_vec_t<uint8_t, GpsHyperion::MAX_SATELLITES>(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_ */

View File

@ -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);

View File

@ -8,6 +8,14 @@
namespace susMax1227 {
// This is 16 seconds for a polling frequency of 0.4 seconds.
static constexpr uint32_t MAX_INVALID_MSG_COUNT = 40;
// Using a decrement time of 32 seconds should cause faulty device incrementation to best faster
// the decrementation, so that FDIR reactions will eventuall be triggered.
// NOTE: Not used currently, we perform the strange reply check logic in the handler and trigger
// a reboot directly using the appropriate event.
static constexpr uint32_t FAULTY_COM_DECREMENT_TIME_MS = 32000;
static const DeviceCommandId_t NONE = 0x0; // Set when no command is pending
static const DeviceCommandId_t WRITE_SETUP = 1;

View File

@ -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,10 +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);
ReturnValue_t result = navigation.useMekf(&sensorValues, &gyrDataProcessed, &mgmDataProcessed,
&susDataProcessed, &mekfData, &acsParameters);
fusedRotationEstimation.estimateFusedRotationRateSafe(&susDataProcessed, &mgmDataProcessed,
&gyrDataProcessed, &fusedRotRateData);
result = navigation.useMekf(&sensorValues, &gyrDataProcessed, &mgmDataProcessed,
&susDataProcessed, &mekfData, &acsParameters);
if (result != MultiplicativeKalmanFilter::MEKF_RUNNING &&
result != MultiplicativeKalmanFilter::MEKF_INITIALIZED) {
if (not mekfInvalidFlag) {
@ -321,18 +358,18 @@ void AcsController::performDetumble() {
if (acsParameters.safeModeControllerParameters.useMekf) {
if (mekfData.satRotRateMekf.isValid() and
VectorOperations<double>::norm(mekfData.satRotRateMekf.value, 3) <
acsParameters.detumbleParameter.omegaDetumbleStart) {
acsParameters.detumbleParameter.omegaDetumbleEnd) {
detumbleCounter++;
}
} else if (acsParameters.safeModeControllerParameters.useGyr) {
if (gyrDataProcessed.gyrVecTot.isValid() and
VectorOperations<double>::norm(gyrDataProcessed.gyrVecTot.value, 3) <
acsParameters.detumbleParameter.omegaDetumbleStart) {
acsParameters.detumbleParameter.omegaDetumbleEnd) {
detumbleCounter++;
}
} else if (fusedRotRateData.rotRateTotal.isValid() and
VectorOperations<double>::norm(fusedRotRateData.rotRateTotal.value, 3) <
acsParameters.detumbleParameter.omegaDetumbleStart) {
acsParameters.detumbleParameter.omegaDetumbleEnd) {
detumbleCounter++;
} else if (detumbleCounter > 0) {
detumbleCounter -= 1;
@ -345,7 +382,7 @@ void AcsController::performDetumble() {
startTransition(mode, acs::SafeSubmode::DEFAULT);
}
disableCtrlValData();
updateCtrlValData(safeCtrlStrat);
updateActuatorCmdData(cmdDipoleMtqs);
commandActuators(cmdDipoleMtqs[0], cmdDipoleMtqs[1], cmdDipoleMtqs[2],
acsParameters.magnetorquerParameter.torqueDuration);
@ -355,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++;
@ -616,6 +660,23 @@ void AcsController::updateActuatorCmdData(const double *rwTargetTorque,
}
}
void AcsController::updateCtrlValData(uint8_t safeModeStrat) {
PoolReadGuard pg(&ctrlValData);
if (pg.getReadResult() == returnvalue::OK) {
std::memcpy(ctrlValData.tgtQuat.value, ZERO_VEC4, 4 * sizeof(double));
ctrlValData.tgtQuat.setValid(false);
std::memcpy(ctrlValData.errQuat.value, ZERO_VEC4, 4 * sizeof(double));
ctrlValData.errQuat.setValid(false);
ctrlValData.errAng.value = 0;
ctrlValData.errAng.setValid(false);
std::memcpy(ctrlValData.tgtRotRate.value, ZERO_VEC3, 3 * sizeof(double));
ctrlValData.tgtRotRate.setValid(false);
ctrlValData.safeStrat.value = safeModeStrat;
ctrlValData.safeStrat.setValid(true);
ctrlValData.setValidity(true, false);
}
}
void AcsController::updateCtrlValData(double errAng, uint8_t safeModeStrat) {
PoolReadGuard pg(&ctrlValData);
if (pg.getReadResult() == returnvalue::OK) {
@ -646,17 +707,6 @@ void AcsController::updateCtrlValData(const double *tgtQuat, const double *errQu
}
}
void AcsController::disableCtrlValData() {
PoolReadGuard pg(&ctrlValData);
if (pg.getReadResult() == returnvalue::OK) {
std::memcpy(ctrlValData.tgtQuat.value, ZERO_VEC4, 4 * sizeof(double));
std::memcpy(ctrlValData.errQuat.value, ZERO_VEC4, 4 * sizeof(double));
ctrlValData.errAng.value = 0;
std::memcpy(ctrlValData.tgtRotRate.value, ZERO_VEC3, 3 * sizeof(double));
ctrlValData.setValidity(false, true);
}
}
ReturnValue_t AcsController::initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
LocalDataPoolManager &poolManager) {
// MGM Raw
@ -727,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);
@ -750,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;
}

View File

@ -3,6 +3,7 @@
#include <eive/objects.h>
#include <fsfw/controller/ExtendedControllerBase.h>
#include <fsfw/coordinates/Sgp4Propagator.h>
#include <fsfw/globalfunctions/math/VectorOperations.h>
#include <fsfw/health/HealthTable.h>
#include <fsfw/parameters/ParameterHelper.h>
@ -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.
@ -117,10 +120,10 @@ class AcsController : public ExtendedControllerBase, public ReceivesParameterMes
void updateActuatorCmdData(const int16_t* mtqTargetDipole);
void updateActuatorCmdData(const double* rwTargetTorque, const int32_t* rwTargetSpeed,
const int16_t* mtqTargetDipole);
void updateCtrlValData(uint8_t safeModeStrat);
void updateCtrlValData(double errAng, uint8_t safeModeStrat);
void updateCtrlValData(const double* tgtQuat, const double* errQuat, double errAng,
const double* tgtRotRate);
void disableCtrlValData();
/* ACS Sensor Values */
ACS::SensorValues sensorValues;
@ -207,6 +210,7 @@ class AcsController : public ExtendedControllerBase, public ReceivesParameterMes
PoolEntry<double> altitude = PoolEntry<double>();
PoolEntry<double> gpsPosition = PoolEntry<double>(3);
PoolEntry<double> gpsVelocity = PoolEntry<double>(3);
PoolEntry<uint8_t> gpsSource = PoolEntry<uint8_t>();
// MEKF
acsctrl::MekfData mekfData;
@ -234,6 +238,11 @@ class AcsController : public ExtendedControllerBase, public ReceivesParameterMes
PoolEntry<double> rotRateParallel = PoolEntry<double>(3);
PoolEntry<double> rotRateTotal = PoolEntry<double>(3);
// TLE Dataset
acsctrl::TleData tleData;
PoolEntry<uint8_t> line1 = PoolEntry<uint8_t>(69);
PoolEntry<uint8_t> line2 = PoolEntry<uint8_t>(69);
// Initial delay to make sure all pool variables have been initialized their owners
Countdown initialCountdown = Countdown(INIT_DELAY);
};

View File

@ -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;

View File

@ -26,6 +26,9 @@ ReturnValue_t AcsParameters::getParameter(uint8_t domainId, uint8_t parameterId,
case 0x1:
parameterWrapper->set(onBoardParams.mekfViolationTimer);
break;
case 0x2:
parameterWrapper->set(onBoardParams.fusedRateSafeDuringEclipse);
break;
default:
return INVALID_IDENTIFIER_ID;
}
@ -110,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;
}
@ -662,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;
}

View File

@ -19,6 +19,7 @@ class AcsParameters : public HasParametersIF {
struct OnBoardParams {
double sampleTime = 0.4; // [s]
uint16_t mekfViolationTimer = 750;
uint8_t fusedRateSafeDuringEclipse = true;
} onBoardParams;
struct InertiaEIVE {
@ -78,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 {
@ -769,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 {
@ -832,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;
@ -915,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 {

View File

@ -18,10 +18,18 @@ void FusedRotationEstimation::estimateFusedRotationRateSafe(
std::memcpy(fusedRotRateData->rotRateTotal.value, ZERO_VEC, 3 * sizeof(double));
fusedRotRateData->setValidity(false, true);
}
// store for calculation of angular acceleration
if (gyrDataProcessed->gyrVecTot.isValid()) {
std::memcpy(rotRateOldB, gyrDataProcessed->gyrVecTot.value, 3 * sizeof(double));
}
return;
}
if (not susDataProcessed->susVecTot.isValid()) {
estimateFusedRotationRateEclipse(gyrDataProcessed, fusedRotRateData);
// store for calculation of angular acceleration
if (gyrDataProcessed->gyrVecTot.isValid()) {
std::memcpy(rotRateOldB, gyrDataProcessed->gyrVecTot.value, 3 * sizeof(double));
}
return;
}
@ -42,6 +50,10 @@ void FusedRotationEstimation::estimateFusedRotationRateSafe(
fusedRotRateParallel, 3);
} else {
estimateFusedRotationRateEclipse(gyrDataProcessed, fusedRotRateData);
// store for calculation of angular acceleration
if (gyrDataProcessed->gyrVecTot.isValid()) {
std::memcpy(rotRateOldB, gyrDataProcessed->gyrVecTot.value, 3 * sizeof(double));
}
return;
}
@ -58,11 +70,6 @@ void FusedRotationEstimation::estimateFusedRotationRateSafe(
double fusedRotRateTotal[3] = {0, 0, 0};
VectorOperations<double>::add(fusedRotRateParallel, fusedRotRateOrthogonal, fusedRotRateTotal);
// store for calculation of angular acceleration
if (gyrDataProcessed->gyrVecTot.isValid()) {
std::memcpy(rotRateOldB, gyrDataProcessed->gyrVecTot.value, 3 * sizeof(double));
}
{
PoolReadGuard pg(fusedRotRateData);
std::memcpy(fusedRotRateData->rotRateOrthogonal.value, fusedRotRateOrthogonal,
@ -71,11 +78,17 @@ void FusedRotationEstimation::estimateFusedRotationRateSafe(
std::memcpy(fusedRotRateData->rotRateTotal.value, fusedRotRateTotal, 3 * sizeof(double));
fusedRotRateData->setValidity(true, true);
}
// store for calculation of angular acceleration
if (gyrDataProcessed->gyrVecTot.isValid()) {
std::memcpy(rotRateOldB, gyrDataProcessed->gyrVecTot.value, 3 * sizeof(double));
}
}
void FusedRotationEstimation::estimateFusedRotationRateEclipse(
acsctrl::GyrDataProcessed *gyrDataProcessed, acsctrl::FusedRotRateData *fusedRotRateData) {
if (not gyrDataProcessed->gyrVecTot.isValid() or
if (not acsParameters->onBoardParams.fusedRateSafeDuringEclipse or
not gyrDataProcessed->gyrVecTot.isValid() or
VectorOperations<double>::norm(fusedRotRateData->rotRateTotal.value, 3) == 0) {
{
PoolReadGuard pg(fusedRotRateData);

View File

@ -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);
}

View File

@ -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 <fsfw/coordinates/Sgp4Propagator.h>
#include <mission/acs/defs.h>
#include <mission/controller/acs/AcsParameters.h>
#include <mission/controller/acs/MultiplicativeKalmanFilter.h>
#include <mission/controller/acs/SensorProcessing.h>
#include <mission/controller/acs/SensorValues.h>
#include <mission/controller/controllerdefinitions/AcsCtrlDefinitions.h>
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_ */

View File

@ -1,19 +1,5 @@
#include "SensorProcessing.h"
#include <fsfw/datapool/PoolReadGuard.h>
#include <fsfw/globalfunctions/constants.h>
#include <fsfw/globalfunctions/math/MatrixOperations.h>
#include <fsfw/globalfunctions/math/QuaternionOperations.h>
#include <fsfw/globalfunctions/math/VectorOperations.h>
#include <fsfw/globalfunctions/timevalOperations.h>
#include <math.h>
#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<float>::mulScalar(mgm4Value, 1e-3, mgm4ValueUT, 3); // nT to uT
MatrixOperations<float>::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<double>::norm(savedMgmVecTot, 3) != 0) {
VectorOperations<double>::subtract(mgmVecTot, savedMgmVecTot, mgmVecTotDerivative, 3);
VectorOperations<double>::mulScalar(mgmVecTotDerivative, 1. / timeDiff, mgmVecTotDerivative, 3);
mgmVecTotDerivativeValid = true;
}
timeOfSavedMagFieldEst = timeOfMgmMeasurement;
std::memcpy(savedMgmVecTot, mgmVecTot, sizeof(savedMgmVecTot));
if (VectorOperations<double>::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<double>::norm(savedSusVecTot, 3) != 0) {
VectorOperations<double>::subtract(susVecTot, savedSusVecTot, susVecTotDerivative, 3);
VectorOperations<double>::mulScalar(susVecTotDerivative, 1. / timeDiff, susVecTotDerivative, 3);
susVecTotDerivativeValid = true;
}
std::memcpy(savedSusVecTot, susVecTot, sizeof(savedSusVecTot));
if (VectorOperations<double>::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<double>::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(),

View File

@ -1,15 +1,23 @@
#ifndef SENSORPROCESSING_H_
#define SENSORPROCESSING_H_
#include <common/config/eive/resultClassIds.h>
#include <fsfw/datapool/PoolReadGuard.h>
#include <fsfw/globalfunctions/constants.h>
#include <fsfw/globalfunctions/math/MatrixOperations.h>
#include <fsfw/globalfunctions/math/QuaternionOperations.h>
#include <fsfw/globalfunctions/math/VectorOperations.h>
#include <fsfw/globalfunctions/timevalOperations.h>
#include <fsfw/returnvalues/returnvalue.h>
#include <stdint.h> //uint8_t
#include <time.h> /*purpose, timeval ?*/
#include <mission/acs/defs.h>
#include <mission/controller/acs/AcsParameters.h>
#include <mission/controller/acs/Igrf13Model.h>
#include <mission/controller/acs/SensorValues.h>
#include <mission/controller/acs/SusConverter.h>
#include <mission/controller/acs/util/MathOperations.h>
#include <mission/controller/controllerdefinitions/AcsCtrlDefinitions.h>
#include "../controllerdefinitions/AcsCtrlDefinitions.h"
#include "AcsParameters.h"
#include "SensorValues.h"
#include "SusConverter.h"
#include "eive/resultClassIds.h"
#include <cmath>
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,

View File

@ -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<double>::mulScalar(magFieldB, 1e-6, magFieldBT, 3);
@ -105,8 +108,14 @@ void SafeCtrl::safeSusMgm(const double *magFieldB, const double *rotRateParallel
double dotSun = VectorOperations<double>::dot(sunDirRefB, sunDirB);
errorAngle = acos(dotSun);
std::memcpy(satRotRateParallelB, rotRateParallelB, sizeof(satRotRateParallelB));
std::memcpy(satRotRateOrthogonalB, rotRateOrthogonalB, sizeof(satRotRateOrthogonalB));
if (VectorOperations<double>::norm(rotRateParallelB, 3) != 0 and
VectorOperations<double>::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,

View File

@ -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);

View File

@ -3,14 +3,15 @@
#include <fsfw/src/fsfw/globalfunctions/constants.h>
#include <fsfw/src/fsfw/globalfunctions/math/MatrixOperations.h>
#include <math.h>
#include <fsfw/src/fsfw/globalfunctions/sign.h>
#include <stdint.h>
#include <string.h>
#include <sys/time.h>
#include <cmath>
#include <iostream>
using namespace Math;
#include "fsfw/serviceinterface.h"
template <typename T1, typename T2 = T1>
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);

View File

@ -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<GPS_SET_PROCESSED_ENTRIES> {
lp_var_t<double> altitude = lp_var_t<double>(sid.objectId, ALTITUDE, this);
lp_vec_t<double, 3> gpsPosition = lp_vec_t<double, 3>(sid.objectId, GPS_POSITION, this);
lp_vec_t<double, 3> gpsVelocity = lp_vec_t<double, 3>(sid.objectId, GPS_VELOCITY, this);
lp_var_t<uint8_t> source = lp_var_t<uint8_t>(sid.objectId, SOURCE, this);
private:
};
@ -292,6 +299,16 @@ class FusedRotRateData : public StaticLocalDataSet<FUSED_ROT_RATE_SET_ENTRIES> {
private:
};
class TleData : public StaticLocalDataSet<TLE_SET_ENTRIES> {
public:
TleData(HasLocalDataPoolIF* hkOwner) : StaticLocalDataSet(hkOwner, TLE_SET) {}
lp_vec_t<uint8_t, 69> line1 = lp_vec_t<uint8_t, 69>(sid.objectId, TLE_LINE_1, this);
lp_vec_t<uint8_t, 69> line2 = lp_vec_t<uint8_t, 69>(sid.objectId, TLE_LINE_1, this);
private:
};
} // namespace acsctrl
#endif /* MISSION_CONTROLLER_CONTROLLERDEFINITIONS_ACSCTRLDEFINITIONS_H_ */

View File

@ -1,7 +1,9 @@
#include <fsfw/src/fsfw/datapool/PoolReadGuard.h>
#include <fsfw/datapool/PoolReadGuard.h>
#include <fsfw/tasks/TaskFactory.h>
#include <mission/payload/PayloadPcduHandler.h>
#include "OBSWConfig.h"
#include "fsfw/thermal/tcsDefinitions.h"
#ifdef XIPHOS_Q7S
#include <fsfw_hal/linux/UnixFileGuard.h>
@ -64,6 +66,16 @@ void PayloadPcduHandler::doShutDown() {
return;
}
state = States::PL_PCDU_OFF;
quickTransitionAlreadyCalled = false;
{
PoolReadGuard pg(&adcSet);
adcSet.setReportingEnabled(false);
adcSet.tempC = thermal::INVALID_TEMPERATURE;
std::memset(adcSet.channels.value, 0, sizeof(adcSet.channels.value));
std::memset(adcSet.processed.value, 0, sizeof(adcSet.processed.value));
adcSet.setValidity(false, true);
}
// No need to set mode _MODE_POWER_DOWN, power switching was already handled
setMode(MODE_OFF);
}
@ -73,14 +85,7 @@ void PayloadPcduHandler::doTransition(Mode_t modeFrom, Submode_t subModeFrom) {
stateMachineToNormal(modeFrom, subModeFrom);
return;
} else if (getMode() == _MODE_TO_ON and modeFrom == MODE_NORMAL) {
gpioIF->pullLow(gpioIds::PLPCDU_ENB_HPA);
gpioIF->pullLow(gpioIds::PLPCDU_ENB_MPA);
gpioIF->pullLow(gpioIds::PLPCDU_ENB_TX);
gpioIF->pullLow(gpioIds::PLPCDU_ENB_X8);
gpioIF->pullLow(gpioIds::PLPCDU_ENB_DRO);
gpioIF->pullLow(gpioIds::PLPCDU_ENB_TX);
gpioIF->pullLow(gpioIds::PLPCDU_ENB_VBAT0);
gpioIF->pullLow(gpioIds::PLPCDU_ENB_VBAT1);
pullAllGpiosLow(200);
state = States::STACK_5V_CORRECT;
}
DeviceHandlerBase::doTransition(modeFrom, subModeFrom);
@ -89,6 +94,11 @@ void PayloadPcduHandler::doTransition(Mode_t modeFrom, Submode_t subModeFrom) {
ReturnValue_t PayloadPcduHandler::stateMachineToNormal(Mode_t modeFrom, Submode_t subModeFrom) {
using namespace plpcdu;
bool doFinish = true;
if (toNormalOneShot) {
PoolReadGuard pg(&adcSet);
adcSet.setReportingEnabled(true);
toNormalOneShot = false;
}
if (((getSubmode() >> SOLID_STATE_RELAYS_ADC_ON) & 0b1) == 1) {
if (state == States::PL_PCDU_OFF) {
sif::error << "PayloadPcduHandler::stateMachineToNormal: Unexpected state PL_PCDU_OFF"
@ -114,23 +124,23 @@ ReturnValue_t PayloadPcduHandler::stateMachineToNormal(Mode_t modeFrom, Submode_
state = States::ON_TRANS_ADC_CLOSE_ZERO;
adcCountdown.setTimeout(50);
adcCountdown.resetTimer();
adcState = AdcStates::BOOT_DELAY;
adcState = AdcState::BOOT_DELAY;
doFinish = false;
// If the values are not close to zero, we should not allow transition
monMode = MonitoringMode::CLOSE_TO_ZERO;
}
}
if (state == States::ON_TRANS_ADC_CLOSE_ZERO) {
if (adcState == AdcStates::BOOT_DELAY) {
if (adcState == AdcState::BOOT_DELAY) {
doFinish = false;
if (adcCountdown.hasTimedOut()) {
adcState = AdcStates::SEND_SETUP;
adcState = AdcState::SEND_SETUP;
adcCmdExecuted = false;
}
}
if (adcState == AdcStates::SEND_SETUP) {
if (adcState == AdcState::SEND_SETUP) {
if (adcCmdExecuted) {
adcState = AdcStates::NORMAL;
adcState = AdcState::NORMAL;
doFinish = true;
adcCountdown.setTimeout(100);
adcCountdown.resetTimer();
@ -167,6 +177,7 @@ ReturnValue_t PayloadPcduHandler::stateMachineToNormal(Mode_t modeFrom, Submode_
switchHandler(MPA_ON, gpioIds::PLPCDU_ENB_MPA, "MPA");
switchHandler(HPA_ON, gpioIds::PLPCDU_ENB_HPA, "HPA");
if (doFinish) {
toNormalOneShot = true;
setMode(MODE_NORMAL);
}
return returnvalue::OK;
@ -174,11 +185,11 @@ ReturnValue_t PayloadPcduHandler::stateMachineToNormal(Mode_t modeFrom, Submode_
ReturnValue_t PayloadPcduHandler::buildNormalDeviceCommand(DeviceCommandId_t* id) {
switch (adcState) {
case (AdcStates::SEND_SETUP): {
case (AdcState::SEND_SETUP): {
*id = plpcdu::SETUP_CMD;
return buildCommandFromCommand(*id, nullptr, 0);
}
case (AdcStates::NORMAL): {
case (AdcState::NORMAL): {
*id = plpcdu::READ_WITH_TEMP_EXT;
return buildCommandFromCommand(*id, nullptr, 0);
}
@ -190,7 +201,7 @@ ReturnValue_t PayloadPcduHandler::buildNormalDeviceCommand(DeviceCommandId_t* id
}
ReturnValue_t PayloadPcduHandler::buildTransitionDeviceCommand(DeviceCommandId_t* id) {
if (adcState == AdcStates::SEND_SETUP) {
if (adcState == AdcState::SEND_SETUP) {
*id = plpcdu::SETUP_CMD;
return buildCommandFromCommand(*id, nullptr, 0);
}
@ -211,9 +222,9 @@ void PayloadPcduHandler::updateSwitchGpio(gpioId_t id, gpio::Levels level) {
}
void PayloadPcduHandler::fillCommandAndReplyMap() {
insertInCommandAndReplyMap(plpcdu::READ_CMD, 2, &adcSet);
insertInCommandAndReplyMap(plpcdu::READ_TEMP_EXT, 1, &adcSet);
insertInCommandAndReplyMap(plpcdu::READ_WITH_TEMP_EXT, 1, &adcSet);
insertInCommandAndReplyMap(plpcdu::READ_CMD, 2);
insertInCommandAndReplyMap(plpcdu::READ_TEMP_EXT, 1);
insertInCommandAndReplyMap(plpcdu::READ_WITH_TEMP_EXT, 1);
insertInCommandAndReplyMap(plpcdu::SETUP_CMD, 1);
}
@ -277,27 +288,31 @@ ReturnValue_t PayloadPcduHandler::interpretDeviceReply(DeviceCommandId_t id,
break;
}
case (READ_CMD): {
PoolReadGuard pg(&adcSet);
if (pg.getReadResult() != returnvalue::OK) {
return pg.getReadResult();
{
PoolReadGuard pg(&adcSet);
if (pg.getReadResult() != returnvalue::OK) {
return pg.getReadResult();
}
handleExtConvRead(packet);
checkAdcValues();
adcSet.setValidity(true, true);
}
handleExtConvRead(packet);
checkAdcValues();
adcSet.setValidity(true, true);
handlePrintout();
break;
}
case (READ_WITH_TEMP_EXT): {
PoolReadGuard pg(&adcSet);
if (pg.getReadResult() != returnvalue::OK) {
return pg.getReadResult();
{
PoolReadGuard pg(&adcSet);
if (pg.getReadResult() != returnvalue::OK) {
return pg.getReadResult();
}
handleExtConvRead(packet);
uint8_t tempStartIdx = ADC_REPLY_SIZE + TEMP_REPLY_SIZE - 2;
adcSet.tempC.value =
max1227::getTemperature(packet[tempStartIdx] << 8 | packet[tempStartIdx + 1]);
checkAdcValues();
adcSet.setValidity(true, true);
}
handleExtConvRead(packet);
uint8_t tempStartIdx = ADC_REPLY_SIZE + TEMP_REPLY_SIZE - 2;
adcSet.tempC.value =
max1227::getTemperature(packet[tempStartIdx] << 8 | packet[tempStartIdx + 1]);
checkAdcValues();
adcSet.setValidity(true, true);
handlePrintout();
break;
}
@ -367,16 +382,9 @@ void PayloadPcduHandler::enablePeriodicPrintout(bool enable, uint8_t divider) {
void PayloadPcduHandler::quickTransitionBackToOff(bool startTransitionToOff, bool notifyFdir) {
States currentState = state;
gpioIF->pullLow(gpioIds::PLPCDU_ENB_HPA);
gpioIF->pullLow(gpioIds::PLPCDU_ENB_MPA);
gpioIF->pullLow(gpioIds::PLPCDU_ENB_TX);
gpioIF->pullLow(gpioIds::PLPCDU_ENB_X8);
gpioIF->pullLow(gpioIds::PLPCDU_ENB_DRO);
gpioIF->pullLow(gpioIds::PLPCDU_ENB_TX);
gpioIF->pullLow(gpioIds::PLPCDU_ENB_VBAT0);
gpioIF->pullLow(gpioIds::PLPCDU_ENB_VBAT1);
pullAllGpiosLow(200);
state = States::STACK_5V_SWITCHING;
adcState = AdcStates::OFF;
adcState = AdcState::OFF;
if (startTransitionToOff) {
startTransition(MODE_OFF, 0);
}
@ -405,10 +413,13 @@ void PayloadPcduHandler::checkAdcValues() {
adcSet.processed[U_DRO_DIV_6] = static_cast<float>(adcSet.channels[11]) * SCALE_VOLTAGE;
float lowerBound = 0.0;
float upperBound = 0.0;
bool adcTransition = false;
adcTransition = state == States::ON_TRANS_DRO and adcCountdown.isBusy();
// Now check against voltage and current limits, depending on state
if (state >= States::ON_TRANS_DRO and not adcTransition) {
bool adcTransition = adcState == AdcState::NORMAL and adcCountdown.isBusy();
if (NO_ADC_CHECKS or adcTransition) {
return;
}
// Now check against voltage and current limits.
uint8_t submode = getSubmode();
if (((submode >> NormalSubmodeBits::DRO_ON) & 0b1) == 0b1) {
if (ssrToDroInjectionRequested) {
handleFailureInjection("SSR to DRO", NEG_V_OUT_OF_BOUNDS);
ssrToDroInjectionRequested = false;
@ -435,8 +446,7 @@ void PayloadPcduHandler::checkAdcValues() {
return;
}
}
adcTransition = state == States::ON_TRANS_X8 and adcCountdown.isBusy();
if (state >= States::ON_TRANS_X8 and not adcTransition) {
if (((submode >> NormalSubmodeBits::X8_ON) & 0b1) == 0b1) {
if (droToX8InjectionRequested) {
handleFailureInjection("X8 to TX", U_X8_OUT_OF_BOUNDS);
droToX8InjectionRequested = false;
@ -453,8 +463,7 @@ void PayloadPcduHandler::checkAdcValues() {
return;
}
}
adcTransition = state == States::ON_TRANS_TX and adcCountdown.isBusy();
if (state >= States::ON_TRANS_TX and not adcTransition) {
if (((submode >> NormalSubmodeBits::TX_ON) & 0b1) == 0b1) {
if (txToMpaInjectionRequested) {
handleFailureInjection("TX to MPA", U_TX_OUT_OF_BOUNDS);
txToMpaInjectionRequested = false;
@ -471,8 +480,7 @@ void PayloadPcduHandler::checkAdcValues() {
return;
}
}
adcTransition = state == States::ON_TRANS_MPA and adcCountdown.isBusy();
if (state >= States::ON_TRANS_MPA and not adcTransition) {
if (((submode >> NormalSubmodeBits::MPA_ON) & 0b1) == 0b1) {
if (mpaToHpaInjectionRequested) {
handleFailureInjection("MPA to HPA", U_HPA_OUT_OF_BOUNDS);
mpaToHpaInjectionRequested = false;
@ -489,8 +497,7 @@ void PayloadPcduHandler::checkAdcValues() {
return;
}
}
adcTransition = state == States::ON_TRANS_HPA and adcCountdown.isBusy();
if (state >= States::ON_TRANS_HPA and not adcTransition) {
if (((submode >> NormalSubmodeBits::HPA_ON) & 0b1) == 0b1) {
if (allOnInjectRequested) {
handleFailureInjection("All On", U_HPA_OUT_OF_BOUNDS);
allOnInjectRequested = false;
@ -677,6 +684,18 @@ void PayloadPcduHandler::handleFailureInjection(std::string output, Event event)
droToX8InjectionRequested = false;
}
void PayloadPcduHandler::pullAllGpiosLow(uint32_t delayBeforeSwitchingOffDro) {
sif::info << "Pulling all PL PCDU GPIOs to low" << std::endl;
gpioIF->pullLow(gpioIds::PLPCDU_ENB_HPA);
gpioIF->pullLow(gpioIds::PLPCDU_ENB_MPA);
gpioIF->pullLow(gpioIds::PLPCDU_ENB_TX);
gpioIF->pullLow(gpioIds::PLPCDU_ENB_X8);
TaskFactory::delayTask(delayBeforeSwitchingOffDro);
gpioIF->pullLow(gpioIds::PLPCDU_ENB_DRO);
gpioIF->pullLow(gpioIds::PLPCDU_ENB_VBAT0);
gpioIF->pullLow(gpioIds::PLPCDU_ENB_VBAT1);
}
ReturnValue_t PayloadPcduHandler::handleDoubleParamUpdate(std::string key,
ParameterWrapper* parameterWrapper,
const ParameterWrapper* newValues) {
@ -692,6 +711,8 @@ ReturnValue_t PayloadPcduHandler::handleDoubleParamUpdate(std::string key,
return params.writeJsonFile();
}
LocalPoolDataSetBase* PayloadPcduHandler::getDataSetHandle(sid_t sid) { return &adcSet; }
#ifdef XIPHOS_Q7S
ReturnValue_t PayloadPcduHandler::extConvAsTwoCallback(SpiComIF* comIf, SpiCookie* cookie,
const uint8_t* sendData, size_t sendLen,

View File

@ -76,6 +76,8 @@ class PayloadPcduHandler : public DeviceHandlerBase {
#endif
private:
static constexpr bool NO_ADC_CHECKS = false;
enum class States : uint8_t {
PL_PCDU_OFF,
STACK_5V_SWITCHING,
@ -84,20 +86,7 @@ class PayloadPcduHandler : public DeviceHandlerBase {
// Solid State Relay, enable battery voltages VBAT0 and VBAT1. This will also switch on
// the ADC
ON_TRANS_SSR,
ON_TRANS_ADC_CLOSE_ZERO,
// Enable Dielectric Resonant Oscillator and start monitoring voltages as
// soon as DRO voltage reaches 6V
ON_TRANS_DRO,
// Switch on X8 compoennt and monitor voltages for 5 seconds
ON_TRANS_X8,
// Switch on TX component and monitor voltages for 5 seconds
ON_TRANS_TX,
// Switch on MPA component and monitor voltages for 5 seconds
ON_TRANS_MPA,
// Switch on HPA component and monitor voltages for 5 seconds
ON_TRANS_HPA,
// All components of the experiment are on
PL_PCDU_ON,
ON_TRANS_ADC_CLOSE_ZERO
} state = States::PL_PCDU_OFF;
duallane::Submodes pwrSubmode = duallane::Submodes::A_SIDE;
@ -106,7 +95,7 @@ class PayloadPcduHandler : public DeviceHandlerBase {
enum class MonitoringMode { NONE, CLOSE_TO_ZERO, NEGATIVE } monMode = MonitoringMode::NONE;
enum class AdcStates { OFF, BOOT_DELAY, SEND_SETUP, NORMAL } adcState = AdcStates::OFF;
enum class AdcState { OFF, BOOT_DELAY, SEND_SETUP, NORMAL } adcState = AdcState::OFF;
bool goToNormalMode = false;
plpcdu::PlPcduAdcSet adcSet;
@ -128,6 +117,7 @@ class PayloadPcduHandler : public DeviceHandlerBase {
bool mpaToHpaInjectionRequested = false;
bool allOnInjectRequested = false;
bool clearSetOnOffFlag = true;
bool toNormalOneShot = true;
PeriodicOperationDivider opDivider = PeriodicOperationDivider(5);
uint8_t tempReadDivisor = 1;
@ -168,6 +158,7 @@ class PayloadPcduHandler : public DeviceHandlerBase {
void handleExtConvRead(const uint8_t* bufStart);
void handlePrintout();
void pullAllGpiosLow(uint32_t delayBeforeSwitchingOffDro);
void checkAdcValues();
void handleOutOfBoundsPrintout();
void checkJsonFileInit();
@ -178,6 +169,7 @@ class PayloadPcduHandler : public DeviceHandlerBase {
ReturnValue_t serializeFloat(uint32_t& param, float val);
ReturnValue_t handleDoubleParamUpdate(std::string key, ParameterWrapper* parameterWrapper,
const ParameterWrapper* newValues);
LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;
};
#endif /* LINUX_DEVICES_PLPCDUHANDLER_H_ */

View File

@ -19,11 +19,16 @@ using namespace returnvalue;
ScexDeviceHandler::ScexDeviceHandler(object_id_t objectId, ScexUartReader& reader, CookieIF* cookie,
SdCardMountedIF& sdcMan)
: DeviceHandlerBase(objectId, reader.getObjectId(), cookie), sdcMan(sdcMan), reader(reader) {}
: DeviceHandlerBase(objectId, reader.getObjectId(), cookie), sdcMan(sdcMan), reader(reader) {
fsUnusableEventCd.timeOut();
}
ScexDeviceHandler::~ScexDeviceHandler() {}
void ScexDeviceHandler::doStartUp() { setMode(MODE_ON); }
void ScexDeviceHandler::doStartUp() {
filesystemChecks();
setMode(MODE_ON);
}
void ScexDeviceHandler::doShutDown() {
reader.reset();
@ -47,7 +52,7 @@ ReturnValue_t ScexDeviceHandler::buildCommandFromCommand(DeviceCommandId_t devic
return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED;
}
bool tempCheck = false;
if (commandDataLen == 1) {
if (commandDataLen >= 1) {
tempCheck = commandData[0];
}
if (commandActive) {
@ -215,8 +220,12 @@ ReturnValue_t ScexDeviceHandler::interpretDeviceReply(DeviceCommandId_t id, cons
}
fileNameSet = true;
} else {
ofstream out(fileName,
ofstream::binary | ofstream::app); // append
if (!sdcMan.isSdCardUsable(std::nullopt)) {
fsUnsableEvent();
return returnvalue::FAILED;
}
// Append to existing file.
ofstream out(fileName, ofstream::binary | ofstream::app);
if (out.bad()) {
sif::error << "ScexDeviceHandler::handleValidReply: Could not open file " << fileName
<< std::endl;
@ -280,18 +289,8 @@ ReturnValue_t ScexDeviceHandler::interpretDeviceReply(DeviceCommandId_t id, cons
}
void ScexDeviceHandler::performOperationHook() {
auto mntPrefix = sdcMan.getCurrentMountPrefix();
if (mntPrefix != nullptr) {
std::filesystem::path fullFilePath = mntPrefix;
std::error_code e;
fullFilePath /= "scex";
bool fileExists = std::filesystem::exists(fullFilePath, e);
if (not fileExists) {
bool created = std::filesystem::create_directory(fullFilePath, e);
if (not created) {
sif::error << "Could not create SCEX directory: " << e << std::endl;
}
}
if (getMode() != MODE_OFF) {
filesystemChecks();
}
uint32_t remainingMillis = finishCountdown.getRemainingMillis();
if (commandActive and finishCountdown.hasTimedOut()) {
@ -319,6 +318,33 @@ ReturnValue_t ScexDeviceHandler::initializeLocalDataPool(localpool::DataPool& lo
return OK;
}
void ScexDeviceHandler::filesystemChecks() {
auto mntPrefix = sdcMan.getCurrentMountPrefix();
if (mntPrefix == nullptr or !sdcMan.isSdCardUsable(std::nullopt)) {
sif::warning << "SCEX: Filesystem currently unavailable" << std::endl;
fsUnsableEvent();
} else {
std::filesystem::path fullFilePath = mntPrefix;
std::error_code e;
fullFilePath /= "scex";
bool fileExists = std::filesystem::exists(fullFilePath, e);
if (not fileExists) {
bool created = std::filesystem::create_directory(fullFilePath, e);
if (not created) {
sif::error << "Could not create SCEX directory: " << e << std::endl;
}
}
}
}
void ScexDeviceHandler::fsUnsableEvent() {
if (fsUnusableEventCd.isBusy()) {
return;
}
triggerEvent(scex::FS_UNUSABLE);
fsUnusableEventCd.resetTimer();
}
ReturnValue_t ScexDeviceHandler::generateNewScexFile(const char* cmdName) {
char timeString[64]{};
auto activeSd = sdcMan.getActiveSdCard();
@ -328,7 +354,8 @@ ReturnValue_t ScexDeviceHandler::generateNewScexFile(const char* cmdName) {
std::ostringstream oss;
auto prefix = sdcMan.getCurrentMountPrefix();
if (prefix == nullptr) {
if (prefix == nullptr or !sdcMan.isSdCardUsable(std::nullopt)) {
fsUnsableEvent();
return returnvalue::FAILED;
}
timeval tv;

View File

@ -42,6 +42,7 @@ class ScexDeviceHandler : public DeviceHandlerBase {
scex::Cmds currCmd = scex::Cmds::PING;
SdCardMountedIF &sdcMan;
Countdown finishCountdown = Countdown(LONG_CD);
Countdown fsUnusableEventCd = Countdown(10000);
// DeviceHandlerBase private function implementation
void doStartUp() override;
@ -49,12 +50,15 @@ class ScexDeviceHandler : public DeviceHandlerBase {
ScexHelper helper;
ScexUartReader &reader;
void fsUnsableEvent();
void performOperationHook() override;
ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t *id) override;
ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t *id) override;
ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, const uint8_t *commandData,
size_t commandDataLen) override;
void fillCommandAndReplyMap() override;
void filesystemChecks();
ReturnValue_t scanForReply(const uint8_t *start, size_t remainingSize, DeviceCommandId_t *foundId,
size_t *foundLen) override;
ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) override;

View File

@ -20,6 +20,7 @@ static constexpr Event EXPERIMENT_TIMEDOUT = event::makeEvent(SUBSYSTEM_ID, 1, s
//! FRAM, One Cell or All cells command finished. P1: Command ID
static constexpr Event MULTI_PACKET_COMMAND_DONE =
event::makeEvent(SUBSYSTEM_ID, 2, severity::INFO);
static constexpr Event FS_UNUSABLE = event::makeEvent(SUBSYSTEM_ID, 3, severity::LOW);
enum Cmds : DeviceCommandId_t {
PING = 0b00111,

View File

@ -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

View File

@ -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;
}
@ -195,10 +199,21 @@ void EiveSystem::i2cRecoveryLogic() {
// Try recovery.
executeAction(EXECUTE_I2C_REBOOT, MessageQueueIF::NO_QUEUE, nullptr, 0);
} else {
if (waitingForI2cReboot) {
return;
}
triggerEvent(core::I2C_REBOOT);
// Some delay to ensure that the event is stored in the persistent TM store as well.
TaskFactory::delayTask(500);
// We already tried an I2C recovery but the bus is still broken.
// Send full reboot request to core controller.
sendFullRebootCommand();
// Send reboot request to core controller.
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.
return;
}
waitingForI2cReboot = true;
return;
}
}
@ -285,29 +300,39 @@ ReturnValue_t EiveSystem::sendFullRebootCommand() {
}
void EiveSystem::pdecRecoveryLogic() {
if (ptmeResetWasAttempted and ptmeResetWasAttemptedCd.hasTimedOut()) {
ptmeResetWasAttempted = 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 (ptmeResetWasAttempted) {
triggerEvent(core::PDEC_REBOOT);
// Send reboot command.
sendFullRebootCommand();
} 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);
ptmeResetWasAttemptedCd.resetTimer();
ptmeResetWasAttempted = 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();
}
}
@ -329,3 +354,17 @@ ReturnValue_t EiveSystem::handleCommandMessage(CommandMessage* message) {
}
return Subsystem::handleCommandMessage(message);
}
ReturnValue_t EiveSystem::sendSelfRebootCommand() {
CommandMessage msg;
uint8_t data[1];
// This option is used to target the same image.
data[0] = true;
store_address_t storeId;
ReturnValue_t result = IPCStore->addData(&storeId, data, sizeof(data));
if (result != returnvalue::OK) {
return result;
}
ActionMessage::setCommand(&msg, core::XSC_REBOOT_OBC, storeId);
return commandQueue->sendMessage(coreCtrlQueueId, &msg);
}

View File

@ -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,9 +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 ptmeResetWasAttemptedCd = Countdown(120000);
bool ptmeResetWasAttempted = 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;
@ -63,6 +66,7 @@ class EiveSystem : public Subsystem, public HasActionsIF {
ReturnValue_t handleCommandMessage(CommandMessage* message) override;
ReturnValue_t sendFullRebootCommand();
ReturnValue_t sendSelfRebootCommand();
void pdecRecoveryLogic();

View File

@ -1,6 +1,7 @@
#include "SusFdir.h"
#include "eive/objects.h"
#include "mission/acs/susMax1227Helpers.h"
SusFdir::SusFdir(object_id_t sensorId)
: DeviceHandlerFailureIsolation(sensorId, objects::SUS_BOARD_ASS) {}

View File

@ -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++;
};

2
tmtc

@ -1 +1 @@
Subproject commit cbcc06ede704d36e1558aae922092470fee5ff66
Subproject commit d23cc6834ad0895c230d2378b0c8d9ba4f374f8d