Compare commits
135 Commits
Author | SHA1 | Date | |
---|---|---|---|
087db386d7 | |||
2f5f47a02c | |||
8821cc1079 | |||
14cea6369a | |||
0a37db617b | |||
101117cebe | |||
4863dad1cd | |||
c6289e27ae | |||
6538005a30 | |||
fa5883bdf3 | |||
b261a4ecfa | |||
a6dfe02128 | |||
bcd31c9248 | |||
bf73f2ff04 | |||
b2a8c5d7ec | |||
2dd97a55f8 | |||
ccf03b131b | |||
c48268ffa9 | |||
97a78fc4c9 | |||
0bdc6d3d7c | |||
66583e8009 | |||
c0f01a75e4 | |||
6a15aa14a2 | |||
11e9d71775 | |||
d30bab7bc0 | |||
a366ef0960 | |||
930f7a5233 | |||
68f4323d14 | |||
01e97c8381 | |||
1b73e7de7d | |||
8759f86889 | |||
a2d5138c71 | |||
f5c4e2b788 | |||
af1c18e8cf | |||
c562c4a240 | |||
45e1e7250b | |||
70e2a3f5f8 | |||
e6a5847e9c | |||
72ae6aee94 | |||
25e5f8d2a4 | |||
0f25f95307 | |||
af5d4e12c5 | |||
fd62efcae2 | |||
1b00029202 | |||
72174c76cd | |||
7476f33905 | |||
e48d080673 | |||
888ade0bfb | |||
a2fd590280 | |||
23c9e8eed7 | |||
1f8f62457d | |||
cb43688f38 | |||
f84e7e42d6 | |||
51317782c3 | |||
97bb255d53 | |||
97888953ec | |||
112cfa3ee7 | |||
5de7653600 | |||
bf7e4b4b8c | |||
e3389c32a7 | |||
58db0d7184 | |||
5218202824 | |||
c169229107 | |||
d2daa89d89 | |||
ca7fbcf6a9 | |||
db2905c834 | |||
2ccd2a832c | |||
892d2f5939 | |||
cee56f6d02 | |||
3016683db3 | |||
f66777a23c | |||
e38b39b3b2 | |||
4e9646fe10 | |||
ca6556c000 | |||
6aae94823e | |||
0dc26ec8b2 | |||
3b5ecb43cc | |||
e7a1c9f402 | |||
ff9a5fc1bf | |||
2fcba4028c | |||
85d0ac92da | |||
b3a14e9a9b | |||
bf61724374 | |||
8c9424f02b | |||
350b892bb7 | |||
586f04e488 | |||
1f7ab7c2ce | |||
9d8991491a | |||
b64cc8f404 | |||
acae88c67c | |||
4fa5aa6b84 | |||
b48a6e2318 | |||
193ed01bce | |||
d18a0e98a5 | |||
6e10ccd2d6 | |||
3b61697615 | |||
f82cc2aeda | |||
0b2aff56e5 | |||
7f141aa1e8 | |||
c8d09debf7 | |||
1938addaa8 | |||
e6b5ee65f3 | |||
4d6ccaeb4b | |||
3003a4c4d1 | |||
f96fbf707d | |||
80115640ba | |||
4c1b79fd66 | |||
c8a2395d61 | |||
f6f3f17505 | |||
300f3230d1 | |||
c71a1a29f3 | |||
cfbc53792d | |||
5b5489c8da | |||
773e1c9ecc | |||
f041655378 | |||
206c29bb25 | |||
e8da0885eb | |||
f209ac6b2d | |||
04e3d2486d | |||
34807c94ba | |||
0919acf2d5 | |||
69ea16c36d | |||
e2cb88da0e | |||
f2ffb12219 | |||
26d8e852dc | |||
74ffbf1dcd | |||
e52c909580 | |||
7a8816e49a | |||
543568be39 | |||
a8e886200f | |||
c09d94f003 | |||
cf42ca7835 | |||
d3fc9a4491 | |||
0cb7446297 | |||
f789380343 |
78
CHANGELOG.md
78
CHANGELOG.md
@ -16,6 +16,82 @@ will consitute of a breaking change warranting a new major release:
|
||||
|
||||
# [unreleased]
|
||||
|
||||
# [v1.36.0] 2023-03-08
|
||||
|
||||
eive-tmtc: v2.17.2
|
||||
|
||||
## Added
|
||||
|
||||
- Star Tracker Assembly
|
||||
- New `REBOOT_COUNTER` and `INDIVIDUAL_BOOT_COUNTS` events. The first contains the total boot count
|
||||
as a u64, the second one contains the individual boot counts as 4 u16. Add new core controller
|
||||
action command `ANNOUNCE_BOOT_COUNTS` with action ID 3 which triggers both events. These events
|
||||
will also be triggered on each reboot.
|
||||
|
||||
## Changed
|
||||
|
||||
- Persistent TM stores will now create new files on each reboot.
|
||||
- Fast ACS subsystem commanding: Command SUS board consecutively with other devices now
|
||||
- Star Tracker: Use ground confguration for EM and flight config for FM by default.
|
||||
|
||||
## Fixed
|
||||
|
||||
- Command TCS controller off first for TCS subsystem transition to off.
|
||||
- Health handling for TCS board assembly
|
||||
- Mode fallback from IDLE mode to SAFE mode due to ACS errors/events now works properly for
|
||||
the ACS subsystem
|
||||
- Bugfix in IDLE transition for system.
|
||||
- `std::filesystem` API usages: Avoid exceptions by using variants which return an error code
|
||||
instead of throwing exceptions.
|
||||
- GPS fix loss was not reported if mode is unset.
|
||||
- Star Tracker: OFF to NORMAL transition now posssible. Requires FSFW bump which sets
|
||||
transition source modes properly for those transitions.
|
||||
FSFW PR: https://egit.irs.uni-stuttgart.de/eive/fsfw/pulls/131
|
||||
- Star Tracker JSON initialization is now done during object initization instead of redoing it
|
||||
when building a command. This avoids missed deadlines issues in the ACS PST.
|
||||
- Allow arbitrary submodes for dual lane boards to avoid FDIR reactions of subsystem components.
|
||||
Bump FSFW to allow this.
|
||||
- PUS 15 was not scheduled
|
||||
- Transmitter timeout set to 2 minutes instead of 15 minutes. This will prevent to discharge the
|
||||
battery in case the syrlinks starts transmitting due to detection of unintentional bitlock. This
|
||||
happened e.g. on ground when the uplink to the flying latop was established.
|
||||
- ACS system components are now always scheduled (EM specific)
|
||||
|
||||
# [v1.35.1] 2023-03-04
|
||||
|
||||
## Fixed
|
||||
|
||||
- ACS Board Assembly FDIR: Prevent permanent SAFE mode fallbacks by introducing special health
|
||||
handling.
|
||||
PR: https://egit.irs.uni-stuttgart.de/eive/eive-obsw/pulls/418/files
|
||||
- Watchdog fixes
|
||||
- IMTQ timing fixes
|
||||
|
||||
## Added
|
||||
|
||||
- Add IMTQ assembly
|
||||
|
||||
# [v1.35.0] 2023-03-04
|
||||
|
||||
eive-tmtc: v2.16.4
|
||||
|
||||
## Added
|
||||
|
||||
- Improved the OBSW watchdog by adding a watch functionality. The watch functionality is optional
|
||||
and has to be enabled specifically by the application being watched by the watchdog when
|
||||
starting the watchdog. If the watch functionality is enabled and the OBSW has not pinged
|
||||
the watchdog via the FIFO for 2 minutes, the watchdog will restart the OBSW service via systemd.
|
||||
The primary OBSW will only activate the watch functionality if it is the OBSW inside the
|
||||
`/usr/bin` directory. This allows debugging the system by leaving flashed or manually copied
|
||||
debugging images 2 minutes to start the watchdog without the watch functionality.
|
||||
|
||||
## Fixed
|
||||
|
||||
- Bumped FSFW: `Countdown` and `Stopwatch` use new monotonic clock API now.
|
||||
- IMTQ: Various fixes, most notably missing buffer time after starting MGM measurement
|
||||
and corrections for actuator commanding.
|
||||
PR: https://egit.irs.uni-stuttgart.de/eive/eive-obsw/pulls/430
|
||||
|
||||
# [v1.34.0] 2023-03-03
|
||||
|
||||
eive-tmtc: v2.16.3
|
||||
@ -26,6 +102,8 @@ the `/proc/uptime` file is read.
|
||||
|
||||
## Changed
|
||||
|
||||
- The SD card prefix is now set earlier inside the `CoreController` constructor
|
||||
- The watchdog handling was moved outside the `CoreController` into the main loop.
|
||||
- Moved polling of all SPI parts to the same PST.
|
||||
- Allow quicker transition for the EIVE system component by allowing consecutive TCS and ACS
|
||||
component commanding again.
|
||||
|
@ -10,7 +10,7 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
set(OBSW_VERSION_MAJOR 1)
|
||||
set(OBSW_VERSION_MINOR 34)
|
||||
set(OBSW_VERSION_MINOR 36)
|
||||
set(OBSW_VERSION_REVISION 0)
|
||||
|
||||
# set(CMAKE_VERBOSE TRUE)
|
||||
@ -71,11 +71,13 @@ if(EIVE_Q7S_EM)
|
||||
1
|
||||
CACHE STRING "Q7S EM configuration")
|
||||
set(INIT_VAL 0)
|
||||
set(OBSW_STAR_TRACKER_GROUND_CONFIG 1)
|
||||
else()
|
||||
set(OBSW_Q7S_EM
|
||||
0
|
||||
CACHE STRING "Q7S EM configuration")
|
||||
set(INIT_VAL 1)
|
||||
set(OBSW_STAR_TRACKER_GROUND_CONFIG 0)
|
||||
endif()
|
||||
set(OBSW_ADD_MGT
|
||||
${INIT_VAL}
|
||||
@ -295,8 +297,10 @@ include(BuildType)
|
||||
set_build_type()
|
||||
|
||||
set(FSFW_DEBUG_INFO 0)
|
||||
set(Q7S_CHECK_FOR_ALREADY_RUNNING_IMG 0)
|
||||
if(RELEASE_BUILD MATCHES 0)
|
||||
set(FSFW_DEBUG_INFO 1)
|
||||
set(Q7S_CHECK_FOR_ALREADY_RUNNING_IMG 1)
|
||||
endif()
|
||||
|
||||
# Configuration files
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @brief Auto-generated event translation file. Contains 267 translations.
|
||||
* @brief Auto-generated event translation file. Contains 269 translations.
|
||||
* @details
|
||||
* Generated on: 2023-03-02 17:08:11
|
||||
* Generated on: 2023-03-08 16:44:32
|
||||
*/
|
||||
#include "translateEvents.h"
|
||||
|
||||
@ -257,6 +257,8 @@ const char *REBOOT_HW_STRING = "REBOOT_HW";
|
||||
const char *NO_SD_CARD_ACTIVE_STRING = "NO_SD_CARD_ACTIVE";
|
||||
const char *VERSION_INFO_STRING = "VERSION_INFO";
|
||||
const char *CURRENT_IMAGE_INFO_STRING = "CURRENT_IMAGE_INFO";
|
||||
const char *REBOOT_COUNTER_STRING = "REBOOT_COUNTER";
|
||||
const char *INDIVIDUAL_BOOT_COUNTS_STRING = "INDIVIDUAL_BOOT_COUNTS";
|
||||
const char *NO_VALID_SENSOR_TEMPERATURE_STRING = "NO_VALID_SENSOR_TEMPERATURE";
|
||||
const char *NO_HEALTHY_HEATER_AVAILABLE_STRING = "NO_HEALTHY_HEATER_AVAILABLE";
|
||||
const char *SYRLINKS_OVERHEATING_STRING = "SYRLINKS_OVERHEATING";
|
||||
@ -774,6 +776,10 @@ const char *translateEvents(Event event) {
|
||||
return VERSION_INFO_STRING;
|
||||
case (14006):
|
||||
return CURRENT_IMAGE_INFO_STRING;
|
||||
case (14007):
|
||||
return REBOOT_COUNTER_STRING;
|
||||
case (14008):
|
||||
return INDIVIDUAL_BOOT_COUNTS_STRING;
|
||||
case (14100):
|
||||
return NO_VALID_SENSOR_TEMPERATURE_STRING;
|
||||
case (14101):
|
||||
|
@ -1,8 +1,8 @@
|
||||
/**
|
||||
* @brief Auto-generated object translation file.
|
||||
* @details
|
||||
* Contains 158 translations.
|
||||
* Generated on: 2023-03-02 17:08:11
|
||||
* Contains 160 translations.
|
||||
* Generated on: 2023-03-08 16:44:32
|
||||
*/
|
||||
#include "translateObjects.h"
|
||||
|
||||
@ -145,6 +145,8 @@ const char *TCS_BOARD_ASS_STRING = "TCS_BOARD_ASS";
|
||||
const char *RW_ASSY_STRING = "RW_ASSY";
|
||||
const char *CAM_SWITCHER_STRING = "CAM_SWITCHER";
|
||||
const char *SYRLINKS_ASSY_STRING = "SYRLINKS_ASSY";
|
||||
const char *IMTQ_ASSY_STRING = "IMTQ_ASSY";
|
||||
const char *STR_ASSY_STRING = "STR_ASSY";
|
||||
const char *TM_FUNNEL_STRING = "TM_FUNNEL";
|
||||
const char *PUS_TM_FUNNEL_STRING = "PUS_TM_FUNNEL";
|
||||
const char *CFDP_TM_FUNNEL_STRING = "CFDP_TM_FUNNEL";
|
||||
@ -445,6 +447,10 @@ const char *translateObject(object_id_t object) {
|
||||
return CAM_SWITCHER_STRING;
|
||||
case 0x73000007:
|
||||
return SYRLINKS_ASSY_STRING;
|
||||
case 0x73000008:
|
||||
return IMTQ_ASSY_STRING;
|
||||
case 0x73000009:
|
||||
return STR_ASSY_STRING;
|
||||
case 0x73000100:
|
||||
return TM_FUNNEL_STRING;
|
||||
case 0x73000101:
|
||||
|
@ -67,7 +67,7 @@
|
||||
#define OBSW_PRINT_MISSED_DEADLINES 1
|
||||
|
||||
#define OBSW_MPSOC_JTAG_BOOT 0
|
||||
#define OBSW_STAR_TRACKER_GROUND_CONFIG 1
|
||||
#define OBSW_STAR_TRACKER_GROUND_CONFIG @OBSW_STAR_TRACKER_GROUND_CONFIG@
|
||||
#define OBSW_SYRLINKS_SIMULATED @OBSW_SYRLINKS_SIMULATED@
|
||||
#define OBSW_ADD_TEST_CODE 0
|
||||
#define OBSW_ADD_TEST_TASK 0
|
||||
|
@ -17,7 +17,7 @@
|
||||
/*******************************************************************/
|
||||
|
||||
// Probably better if this is disabled for mission code. Convenient for development
|
||||
#define Q7S_CHECK_FOR_ALREADY_RUNNING_IMG 1
|
||||
#define Q7S_CHECK_FOR_ALREADY_RUNNING_IMG @Q7S_CHECK_FOR_ALREADY_RUNNING_IMG@
|
||||
|
||||
#define Q7S_SIMPLE_ADD_FILE_SYSTEM_TEST 0
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
target_sources(${OBSW_NAME} PRIVATE CoreController.cpp scheduling.cpp
|
||||
ObjectFactory.cpp)
|
||||
ObjectFactory.cpp WatchdogHandler.cpp)
|
||||
|
||||
target_sources(${SIMPLE_OBSW_NAME} PRIVATE scheduling.cpp)
|
||||
|
@ -33,12 +33,7 @@ xsc::Copy CoreController::CURRENT_COPY = xsc::Copy::NO_COPY;
|
||||
|
||||
CoreController::CoreController(object_id_t objectId)
|
||||
: ExtendedControllerBase(objectId, 5), opDivider5(5), opDivider10(10), hkSet(this) {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
try {
|
||||
result = initWatchdogFifo();
|
||||
if (result != returnvalue::OK) {
|
||||
sif::warning << "CoreController::CoreController: Watchdog FIFO init failed" << std::endl;
|
||||
}
|
||||
sdcMan = SdCardManager::instance();
|
||||
if (sdcMan == nullptr) {
|
||||
sif::error << "CoreController::CoreController: SD card manager invalid!" << std::endl;
|
||||
@ -47,6 +42,16 @@ CoreController::CoreController(object_id_t objectId)
|
||||
if (not BLOCKING_SD_INIT) {
|
||||
sdcMan->setBlocking(false);
|
||||
}
|
||||
auto sdCard = sdcMan->getPreferredSdCard();
|
||||
if (not sdCard.has_value()) {
|
||||
sif::error << "CoreController::initializeAfterTaskCreation: "
|
||||
"Issues getting preferred SD card, setting to 0"
|
||||
<< std::endl;
|
||||
sdCard = sd::SdCard::SLOT_0;
|
||||
}
|
||||
sdInfo.active = sdCard.value();
|
||||
sdcMan->setActiveSdCard(sdInfo.active);
|
||||
currMntPrefix = sdcMan->getCurrentMountPrefix();
|
||||
|
||||
getCurrentBootCopy(CURRENT_CHIP, CURRENT_COPY);
|
||||
|
||||
@ -54,6 +59,10 @@ CoreController::CoreController(object_id_t objectId)
|
||||
} catch (const std::filesystem::filesystem_error &e) {
|
||||
sif::error << "CoreController::CoreController: Failed with exception " << e.what() << std::endl;
|
||||
}
|
||||
// Add script folder to path
|
||||
char *currentEnvPath = getenv("PATH");
|
||||
std::string updatedEnvPath = std::string(currentEnvPath) + ":/home/root/scripts:/usr/local/bin";
|
||||
setenv("PATH", updatedEnvPath.c_str(), true);
|
||||
sdCardCheckCd.timeOut();
|
||||
eventQueue = QueueFactory::instance()->createMessageQueue(5, EventMessage::MAX_MESSAGE_SIZE);
|
||||
}
|
||||
@ -78,7 +87,6 @@ void CoreController::performControlOperation() {
|
||||
}
|
||||
}
|
||||
}
|
||||
performWatchdogControlOperation();
|
||||
sdStateMachine();
|
||||
performMountedSdCardOperations();
|
||||
if (sdCardCheckCd.hasTimedOut()) {
|
||||
@ -148,22 +156,6 @@ ReturnValue_t CoreController::initialize() {
|
||||
|
||||
ReturnValue_t CoreController::initializeAfterTaskCreation() {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
auto sdCard = sdcMan->getPreferredSdCard();
|
||||
if (not sdCard) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
sdInfo.active = sdCard.value();
|
||||
if (sdInfo.active == sd::SdCard::NONE) {
|
||||
sif::error << "CoreController::initializeAfterTaskCreation: "
|
||||
"Issues getting preferred SD card, setting to 0"
|
||||
<< std::endl;
|
||||
sdInfo.active = sd::SdCard::SLOT_0;
|
||||
}
|
||||
sdcMan->setActiveSdCard(sdInfo.active);
|
||||
currMntPrefix = sdcMan->getCurrentMountPrefix();
|
||||
if (currMntPrefix == "") {
|
||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||
}
|
||||
if (BLOCKING_SD_INIT) {
|
||||
result = initSdCardBlocking();
|
||||
if (result != returnvalue::OK and result != SdCardManager::ALREADY_MOUNTED) {
|
||||
@ -175,12 +167,7 @@ ReturnValue_t CoreController::initializeAfterTaskCreation() {
|
||||
if (result != returnvalue::OK) {
|
||||
sif::warning << "CoreController::initialize: Version initialization failed" << std::endl;
|
||||
}
|
||||
// Add script folder to path
|
||||
char *currentEnvPath = getenv("PATH");
|
||||
std::string updatedEnvPath = std::string(currentEnvPath) + ":/home/root/scripts:/usr/local/bin";
|
||||
setenv("PATH", updatedEnvPath.c_str(), true);
|
||||
updateProtInfo();
|
||||
initPrint();
|
||||
return ExtendedControllerBase::initializeAfterTaskCreation();
|
||||
}
|
||||
|
||||
@ -203,6 +190,10 @@ ReturnValue_t CoreController::executeAction(ActionId_t actionId, MessageQueueId_
|
||||
triggerEvent(VERSION_INFO, p1, p2);
|
||||
return HasActionsIF::EXECUTION_FINISHED;
|
||||
}
|
||||
case (ANNOUNCE_BOOT_COUNTS): {
|
||||
announceBootCounts();
|
||||
return HasActionsIF::EXECUTION_FINISHED;
|
||||
}
|
||||
case (ANNOUNCE_CURRENT_IMAGE): {
|
||||
triggerEvent(CURRENT_IMAGE_INFO, CURRENT_CHIP, CURRENT_COPY);
|
||||
return HasActionsIF::EXECUTION_FINISHED;
|
||||
@ -614,7 +605,8 @@ ReturnValue_t CoreController::sdCardSetup(sd::SdCard sdCard, sd::SdState targetS
|
||||
sif::info << "Unmounting SD card " << sdChar << std::endl;
|
||||
return sdcMan->unmountSdCard(sdCard);
|
||||
} else {
|
||||
if (std::filesystem::exists(mountString)) {
|
||||
std::error_code e;
|
||||
if (std::filesystem::exists(mountString, e)) {
|
||||
sif::info << "SD card " << sdChar << " already on and mounted at " << mountString
|
||||
<< std::endl;
|
||||
return SdCardManager::ALREADY_MOUNTED;
|
||||
@ -711,7 +703,8 @@ ReturnValue_t CoreController::initVersionFile() {
|
||||
std::string versionFilePath = currMntPrefix + VERSION_FILE;
|
||||
std::fstream versionFile;
|
||||
|
||||
if (not std::filesystem::exists(versionFilePath)) {
|
||||
std::error_code e;
|
||||
if (not std::filesystem::exists(versionFilePath, e)) {
|
||||
sif::info << "Writing version file " << versionFilePath << ".." << std::endl;
|
||||
versionFile.open(versionFilePath, std::ios_base::out);
|
||||
versionFile << fullObswVersionString << std::endl;
|
||||
@ -823,7 +816,8 @@ ReturnValue_t CoreController::actionListDirectoryIntoFile(ActionId_t actionId,
|
||||
}
|
||||
|
||||
ReturnValue_t CoreController::initBootCopyFile() {
|
||||
if (not std::filesystem::exists(CURR_COPY_FILE)) {
|
||||
std::error_code e;
|
||||
if (not std::filesystem::exists(CURR_COPY_FILE, e)) {
|
||||
// This file is created by the systemd service eive-early-config so this should
|
||||
// not happen normally
|
||||
std::string cmd = "xsc_boot_copy > " + std::string(CURR_COPY_FILE);
|
||||
@ -844,36 +838,6 @@ void CoreController::getCurrentBootCopy(xsc::Chip &chip, xsc::Copy ©) {
|
||||
copy = static_cast<xsc::Copy>(xscCopy);
|
||||
}
|
||||
|
||||
ReturnValue_t CoreController::initWatchdogFifo() {
|
||||
if (not std::filesystem::exists(watchdog::FIFO_NAME)) {
|
||||
// Still return returnvalue::OK for now
|
||||
sif::info << "Watchdog FIFO " << watchdog::FIFO_NAME << " does not exist, can't initiate"
|
||||
<< " watchdog" << std::endl;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
// Open FIFO write only and non-blocking to prevent SW from killing itself.
|
||||
watchdogFifoFd = open(watchdog::FIFO_NAME.c_str(), O_WRONLY | O_NONBLOCK);
|
||||
if (watchdogFifoFd < 0) {
|
||||
if (errno == ENXIO) {
|
||||
watchdogFifoFd = RETRY_FIFO_OPEN;
|
||||
sif::info << "eive-watchdog not running. FIFO can not be opened" << std::endl;
|
||||
} else {
|
||||
sif::error << "Opening pipe " << watchdog::FIFO_NAME << " write-only failed with " << errno
|
||||
<< ": " << strerror(errno) << std::endl;
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
void CoreController::initPrint() {
|
||||
#if OBSW_VERBOSE_LEVEL >= 1
|
||||
if (watchdogFifoFd > 0) {
|
||||
sif::info << "Opened watchdog FIFO successfully.." << std::endl;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ReturnValue_t CoreController::actionXscReboot(const uint8_t *data, size_t size) {
|
||||
if (size < 1) {
|
||||
return HasActionsIF::INVALID_PARAMETERS;
|
||||
@ -1157,7 +1121,8 @@ ReturnValue_t CoreController::updateProtInfo(bool regenerateChipStateFile) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (not filesystem::exists(CHIP_STATE_FILE)) {
|
||||
std::error_code e;
|
||||
if (not filesystem::exists(CHIP_STATE_FILE, e)) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
ifstream chipStateFile(CHIP_STATE_FILE);
|
||||
@ -1231,43 +1196,19 @@ ReturnValue_t CoreController::handleProtInfoUpdateLine(std::string nextLine) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
void CoreController::performWatchdogControlOperation() {
|
||||
// Only perform each fifth iteration
|
||||
if (watchdogFifoFd != 0 and opDivider5.check()) {
|
||||
if (watchdogFifoFd == RETRY_FIFO_OPEN) {
|
||||
// Open FIFO write only and non-blocking
|
||||
watchdogFifoFd = open(watchdog::FIFO_NAME.c_str(), O_WRONLY | O_NONBLOCK);
|
||||
if (watchdogFifoFd < 0) {
|
||||
if (errno == ENXIO) {
|
||||
watchdogFifoFd = RETRY_FIFO_OPEN;
|
||||
// No printout for now, would be spam
|
||||
return;
|
||||
} else {
|
||||
sif::error << "Opening pipe " << watchdog::FIFO_NAME << " write-only failed with "
|
||||
<< errno << ": " << strerror(errno) << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
sif::info << "Opened " << watchdog::FIFO_NAME << " successfully" << std::endl;
|
||||
} else if (watchdogFifoFd > 0) {
|
||||
// Write to OBSW watchdog FIFO here
|
||||
const char writeChar = 'a';
|
||||
ssize_t writtenBytes = write(watchdogFifoFd, &writeChar, 1);
|
||||
if (writtenBytes < 0) {
|
||||
sif::error << "Errors writing to watchdog FIFO, code " << errno << ": " << strerror(errno)
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CoreController::performMountedSdCardOperations() {
|
||||
auto mountedSdCardOp = [&](sd::SdCard sdCard, std::string mntPoint) {
|
||||
if (not performOneShotSdCardOpsSwitch) {
|
||||
std::ostringstream path;
|
||||
path << mntPoint << "/" << CONF_FOLDER;
|
||||
if (not std::filesystem::exists(path.str())) {
|
||||
std::filesystem::create_directory(path.str());
|
||||
std::error_code e;
|
||||
if (not std::filesystem::exists(path.str()), e) {
|
||||
bool created = std::filesystem::create_directory(path.str(), e);
|
||||
if (not created) {
|
||||
sif::error << "Could not create CONF folder at " << path.str() << ": " << e.message()
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
initVersionFile();
|
||||
ReturnValue_t result = initBootCopyFile();
|
||||
@ -1352,7 +1293,8 @@ ReturnValue_t CoreController::performSdCardCheck() {
|
||||
void CoreController::performRebootFileHandling(bool recreateFile) {
|
||||
using namespace std;
|
||||
std::string path = currMntPrefix + REBOOT_FILE;
|
||||
if (not std::filesystem::exists(path) or recreateFile) {
|
||||
std::error_code e;
|
||||
if (not std::filesystem::exists(path, e) or recreateFile) {
|
||||
#if OBSW_VERBOSE_LEVEL >= 1
|
||||
sif::info << "CoreController::performRebootFileHandling: Recreating reboot file" << std::endl;
|
||||
#endif
|
||||
@ -1394,13 +1336,13 @@ void CoreController::performRebootFileHandling(bool recreateFile) {
|
||||
if (rebootFile.bootFlag) {
|
||||
// Trigger event to inform ground that a reboot was triggered
|
||||
uint32_t p1 = rebootFile.lastChip << 16 | rebootFile.lastCopy;
|
||||
uint32_t p2 = rebootFile.img00Cnt << 24 | rebootFile.img01Cnt << 16 | rebootFile.img10Cnt << 8 |
|
||||
rebootFile.img11Cnt;
|
||||
triggerEvent(REBOOT_MECHANISM_TRIGGERED, p1, p2);
|
||||
triggerEvent(REBOOT_MECHANISM_TRIGGERED, p1, 0);
|
||||
// Clear the boot flag
|
||||
rebootFile.bootFlag = false;
|
||||
}
|
||||
|
||||
announceBootCounts();
|
||||
|
||||
if (rebootFile.mechanismNextChip != xsc::NO_CHIP and
|
||||
rebootFile.mechanismNextCopy != xsc::NO_COPY) {
|
||||
if (CURRENT_CHIP != rebootFile.mechanismNextChip or
|
||||
@ -1819,7 +1761,8 @@ ReturnValue_t CoreController::initClockFromTimeFile() {
|
||||
using namespace GpsHyperion;
|
||||
using namespace std;
|
||||
std::string fileName = currMntPrefix + BACKUP_TIME_FILE;
|
||||
if (sdcMan->isSdCardUsable(std::nullopt) and std::filesystem::exists(fileName) and
|
||||
std::error_code e;
|
||||
if (sdcMan->isSdCardUsable(std::nullopt) and std::filesystem::exists(fileName, e) and
|
||||
((gpsFix == FixMode::UNKNOWN or gpsFix == FixMode::NOT_SEEN) or
|
||||
not utility::timeSanityCheck())) {
|
||||
ifstream timeFile(fileName);
|
||||
@ -1944,7 +1887,8 @@ ReturnValue_t CoreController::executeSwUpdate(SwUpdateSources sourceDir, const u
|
||||
prefixPath = path("/tmp");
|
||||
}
|
||||
path archivePath = prefixPath / path(config::OBSW_UPDATE_ARCHIVE_FILE_NAME);
|
||||
if (not exists(archivePath)) {
|
||||
std::error_code e;
|
||||
if (not exists(archivePath, e)) {
|
||||
return HasFileSystemIF::FILE_DOES_NOT_EXIST;
|
||||
}
|
||||
ostringstream cmd("tar -xJf", ios::app);
|
||||
@ -1954,12 +1898,12 @@ ReturnValue_t CoreController::executeSwUpdate(SwUpdateSources sourceDir, const u
|
||||
utility::handleSystemError(result, "CoreController::executeAction: SW Update Decompression");
|
||||
}
|
||||
path strippedImagePath = prefixPath / path(config::STRIPPED_OBSW_BINARY_FILE_NAME);
|
||||
if (!exists(strippedImagePath)) {
|
||||
if (!exists(strippedImagePath, e)) {
|
||||
// TODO: Custom returnvalue?
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
path obswVersionFilePath = prefixPath / path(config::OBSW_VERSION_FILE_NAME);
|
||||
if (!exists(obswVersionFilePath)) {
|
||||
if (!exists(obswVersionFilePath, e)) {
|
||||
// TODO: Custom returnvalue?
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
@ -2056,6 +2000,15 @@ bool CoreController::startSdStateMachine(sd::SdCard targetActiveSd, SdCfgMode mo
|
||||
return true;
|
||||
}
|
||||
|
||||
void CoreController::announceBootCounts() {
|
||||
uint64_t totalBootCount =
|
||||
rebootFile.img00Cnt + rebootFile.img01Cnt + rebootFile.img10Cnt + rebootFile.img11Cnt;
|
||||
uint32_t individualBootCountsP1 = (rebootFile.img00Cnt << 16) | rebootFile.img01Cnt;
|
||||
uint32_t individualBootCountsP2 = (rebootFile.img10Cnt << 16) | rebootFile.img11Cnt;
|
||||
triggerEvent(INDIVIDUAL_BOOT_COUNTS, individualBootCountsP1, individualBootCountsP2);
|
||||
triggerEvent(REBOOT_COUNTER, (totalBootCount >> 32) & 0xffffffff, totalBootCount & 0xffffffff);
|
||||
}
|
||||
|
||||
bool CoreController::isNumber(const std::string &s) {
|
||||
return !s.empty() && std::find_if(s.begin(), s.end(),
|
||||
[](unsigned char c) { return !std::isdigit(c); }) == s.end();
|
||||
|
@ -78,6 +78,7 @@ class CoreController : public ExtendedControllerBase {
|
||||
static constexpr ActionId_t LIST_DIRECTORY_INTO_FILE = 0;
|
||||
static constexpr ActionId_t ANNOUNCE_VERSION = 1;
|
||||
static constexpr ActionId_t ANNOUNCE_CURRENT_IMAGE = 2;
|
||||
static constexpr ActionId_t ANNOUNCE_BOOT_COUNTS = 3;
|
||||
static constexpr ActionId_t SWITCH_REBOOT_FILE_HANDLING = 5;
|
||||
static constexpr ActionId_t RESET_REBOOT_COUNTERS = 6;
|
||||
static constexpr ActionId_t SWITCH_IMG_LOCK = 7;
|
||||
@ -102,7 +103,7 @@ class CoreController : public ExtendedControllerBase {
|
||||
static constexpr Event ALLOC_FAILURE = event::makeEvent(SUBSYSTEM_ID, 0, severity::MEDIUM);
|
||||
//! [EXPORT] : [COMMENT] Software reboot occurred. Can also be a systemd reboot.
|
||||
//! P1: Current Chip, P2: Current Copy
|
||||
static constexpr Event REBOOT_SW = event::makeEvent(SUBSYSTEM_ID, 1, severity::MEDIUM);
|
||||
static constexpr Event REBOOT_SW = event::makeEvent(SUBSYSTEM_ID, 1, severity::LOW);
|
||||
//! [EXPORT] : [COMMENT] The reboot mechanism was triggered.
|
||||
//! P1: First 16 bits: Last Chip, Last 16 bits: Last Copy,
|
||||
//! P2: Each byte is the respective reboot count for the slots
|
||||
@ -119,6 +120,13 @@ class CoreController : public ExtendedControllerBase {
|
||||
static constexpr Event VERSION_INFO = event::makeEvent(SUBSYSTEM_ID, 5, severity::INFO);
|
||||
//! [EXPORT] : [COMMENT] P1: Current Chip, P2: Current Copy
|
||||
static constexpr Event CURRENT_IMAGE_INFO = event::makeEvent(SUBSYSTEM_ID, 6, severity::INFO);
|
||||
//! [EXPORT] : [COMMENT] Total reboot counter, which is the sum of the boot count of all
|
||||
//! individual images.
|
||||
static constexpr Event REBOOT_COUNTER = event::makeEvent(SUBSYSTEM_ID, 7, severity::INFO);
|
||||
//! [EXPORT] : [COMMENT] Get the boot count of the individual images.
|
||||
//! P1: First 16 bits boot count of image 0 0, last 16 bits boot count of image 0 1.
|
||||
//! P2: First 16 bits boot count of image 1 0, last 16 bits boot count of image 1 1.
|
||||
static constexpr Event INDIVIDUAL_BOOT_COUNTS = event::makeEvent(SUBSYSTEM_ID, 8, severity::INFO);
|
||||
|
||||
CoreController(object_id_t objectId);
|
||||
virtual ~CoreController();
|
||||
@ -164,9 +172,6 @@ class CoreController : public ExtendedControllerBase {
|
||||
static constexpr uint32_t BOOT_OFFSET_SECONDS = 15;
|
||||
static constexpr MutexIF::TimeoutType TIMEOUT_TYPE = MutexIF::TimeoutType::WAITING;
|
||||
static constexpr uint32_t MUTEX_TIMEOUT = 20;
|
||||
// Designated value for rechecking FIFO open
|
||||
static constexpr int RETRY_FIFO_OPEN = -2;
|
||||
int watchdogFifoFd = 0;
|
||||
GpsHyperion::FixMode gpsFix = GpsHyperion::FixMode::UNKNOWN;
|
||||
|
||||
// States for SD state machine, which is used in non-blocking mode
|
||||
@ -263,7 +268,6 @@ class CoreController : public ExtendedControllerBase {
|
||||
ReturnValue_t performSdCardCheck();
|
||||
ReturnValue_t backupTimeFileHandler();
|
||||
ReturnValue_t initBootCopyFile();
|
||||
ReturnValue_t initWatchdogFifo();
|
||||
ReturnValue_t initSdCardBlocking();
|
||||
bool startSdStateMachine(sd::SdCard targetActiveSd, SdCfgMode mode, MessageQueueId_t commander,
|
||||
DeviceCommandId_t actionId);
|
||||
@ -288,8 +292,6 @@ class CoreController : public ExtendedControllerBase {
|
||||
|
||||
ReturnValue_t gracefulShutdownTasks(xsc::Chip chip, xsc::Copy copy, bool& protOpPerformed);
|
||||
|
||||
void performWatchdogControlOperation();
|
||||
|
||||
ReturnValue_t handleProtInfoUpdateLine(std::string nextLine);
|
||||
int handleBootCopyProtAtIndex(xsc::Chip targetChip, xsc::Copy targetCopy, bool protect,
|
||||
bool& protOperationPerformed, bool selfChip, bool selfCopy,
|
||||
@ -300,6 +302,7 @@ class CoreController : public ExtendedControllerBase {
|
||||
void setRebootMechanismLock(bool lock, xsc::Chip tgtChip, xsc::Copy tgtCopy);
|
||||
bool parseRebootFile(std::string path, RebootFile& file);
|
||||
void rewriteRebootFile(RebootFile file);
|
||||
void announceBootCounts();
|
||||
void readHkData();
|
||||
bool isNumber(const std::string& s);
|
||||
};
|
||||
|
@ -7,7 +7,10 @@
|
||||
#include <mission/devices/GyrL3gCustomHandler.h>
|
||||
#include <mission/devices/MgmLis3CustomHandler.h>
|
||||
#include <mission/devices/MgmRm3100CustomHandler.h>
|
||||
#include <mission/system/fdir/StrFdir.h>
|
||||
#include <mission/system/objects/CamSwitcher.h>
|
||||
#include <mission/system/objects/ImtqAssembly.h>
|
||||
#include <mission/system/objects/StrAssembly.h>
|
||||
#include <mission/system/objects/SyrlinksAssembly.h>
|
||||
|
||||
#include "OBSWConfig.h"
|
||||
@ -902,26 +905,47 @@ void ObjectFactory::createTestComponents(LinuxLibgpioIF* gpioComIF) {
|
||||
}
|
||||
|
||||
void ObjectFactory::createStrComponents(PowerSwitchIF* pwrSwitcher) {
|
||||
auto* strAssy = new StrAssembly(objects::STR_ASSY);
|
||||
strAssy->connectModeTreeParent(satsystem::acs::ACS_SUBSYSTEM);
|
||||
auto* starTrackerCookie =
|
||||
new SerialCookie(objects::STAR_TRACKER, q7s::UART_STAR_TRACKER_DEV, uart::STAR_TRACKER_BAUD,
|
||||
startracker::MAX_FRAME_SIZE * 2 + 2, UartModes::NON_CANONICAL);
|
||||
starTrackerCookie->setNoFixedSizeReply();
|
||||
StrHelper* strHelper = new StrHelper(objects::STR_HELPER);
|
||||
|
||||
const char* paramJsonFile = nullptr;
|
||||
#ifdef EGSE
|
||||
paramJsonFile = "/home/pi/arcsec/json/flight-config.json";
|
||||
#else
|
||||
#if OBSW_STAR_TRACKER_GROUND_CONFIG == 1
|
||||
paramJsonFile = "/mnt/sd0/startracker/ground-config.json";
|
||||
#else
|
||||
paramJsonFile = "/mnt/sd0/startracker/flight-config.json";
|
||||
#endif
|
||||
#endif
|
||||
if (paramJsonFile == nullptr) {
|
||||
sif::error << "No valid Star Tracker parameter JSON file" << std::endl;
|
||||
}
|
||||
auto strFdir = new StrFdir(objects::STAR_TRACKER);
|
||||
auto starTracker =
|
||||
new StarTrackerHandler(objects::STAR_TRACKER, objects::UART_COM_IF, starTrackerCookie,
|
||||
strHelper, pcdu::PDU1_CH2_STAR_TRACKER_5V);
|
||||
paramJsonFile, strHelper, pcdu::PDU1_CH2_STAR_TRACKER_5V);
|
||||
starTracker->setPowerSwitcher(pwrSwitcher);
|
||||
starTracker->connectModeTreeParent(satsystem::acs::ACS_SUBSYSTEM);
|
||||
starTracker->connectModeTreeParent(*strAssy);
|
||||
starTracker->setCustomFdir(strFdir);
|
||||
}
|
||||
|
||||
void ObjectFactory::createImtqComponents(PowerSwitchIF* pwrSwitcher) {
|
||||
auto* imtqAssy = new ImtqAssembly(objects::IMTQ_ASSY);
|
||||
imtqAssy->connectModeTreeParent(satsystem::acs::ACS_SUBSYSTEM);
|
||||
|
||||
new ImtqPollingTask(objects::IMTQ_POLLING);
|
||||
I2cCookie* imtqI2cCookie = new I2cCookie(addresses::IMTQ, imtq::MAX_REPLY_SIZE, q7s::I2C_PL_EIVE);
|
||||
auto imtqHandler = new ImtqHandler(objects::IMTQ_HANDLER, objects::IMTQ_POLLING, imtqI2cCookie,
|
||||
pcdu::Switches::PDU1_CH3_MGT_5V);
|
||||
imtqHandler->enableThermalModule(ThermalStateCfg());
|
||||
imtqHandler->setPowerSwitcher(pwrSwitcher);
|
||||
imtqHandler->connectModeTreeParent(satsystem::acs::ACS_SUBSYSTEM);
|
||||
imtqHandler->connectModeTreeParent(*imtqAssy);
|
||||
static_cast<void>(imtqHandler);
|
||||
#if OBSW_TEST_IMTQ == 1
|
||||
imtqHandler->setStartUpImmediately();
|
||||
|
87
bsp_q7s/core/WatchdogHandler.cpp
Normal file
87
bsp_q7s/core/WatchdogHandler.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
#include "WatchdogHandler.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
|
||||
#include "fsfw/serviceinterface.h"
|
||||
#include "watchdog/definitions.h"
|
||||
|
||||
WatchdogHandler::WatchdogHandler() {}
|
||||
|
||||
void WatchdogHandler::periodicOperation() {
|
||||
if (watchdogFifoFd != 0) {
|
||||
if (watchdogFifoFd == RETRY_FIFO_OPEN) {
|
||||
// Open FIFO write only and non-blocking
|
||||
watchdogFifoFd = open(watchdog::FIFO_NAME.c_str(), O_WRONLY | O_NONBLOCK);
|
||||
if (watchdogFifoFd < 0) {
|
||||
if (errno == ENXIO) {
|
||||
watchdogFifoFd = RETRY_FIFO_OPEN;
|
||||
// No printout for now, would be spam
|
||||
return;
|
||||
} else {
|
||||
sif::error << "Opening pipe " << watchdog::FIFO_NAME << " write-only failed with "
|
||||
<< errno << ": " << strerror(errno) << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
sif::info << "Opened " << watchdog::FIFO_NAME << " successfully" << std::endl;
|
||||
performStartHandling();
|
||||
} else if (watchdogFifoFd > 0) {
|
||||
// Write to OBSW watchdog FIFO here
|
||||
const char writeChar = watchdog::first::IDLE_CHAR;
|
||||
ssize_t writtenBytes = write(watchdogFifoFd, &writeChar, 1);
|
||||
if (writtenBytes < 0) {
|
||||
sif::error << "Errors writing to watchdog FIFO, code " << errno << ": " << strerror(errno)
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t WatchdogHandler::initialize(bool enableWatchdogFunction) {
|
||||
using namespace std::filesystem;
|
||||
this->enableWatchFunction = enableWatchdogFunction;
|
||||
std::error_code e;
|
||||
if (not std::filesystem::exists(watchdog::FIFO_NAME, e)) {
|
||||
// Still return returnvalue::OK for now
|
||||
sif::info << "Watchdog FIFO " << watchdog::FIFO_NAME << " does not exist, can't initiate"
|
||||
<< " watchdog" << std::endl;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
// Open FIFO write only and non-blocking to prevent SW from killing itself.
|
||||
watchdogFifoFd = open(watchdog::FIFO_NAME.c_str(), O_WRONLY | O_NONBLOCK);
|
||||
if (watchdogFifoFd < 0) {
|
||||
if (errno == ENXIO) {
|
||||
watchdogFifoFd = RETRY_FIFO_OPEN;
|
||||
sif::info << "eive-watchdog not running. FIFO can not be opened" << std::endl;
|
||||
} else {
|
||||
sif::error << "Opening pipe " << watchdog::FIFO_NAME << " write-only failed with " << errno
|
||||
<< ": " << strerror(errno) << std::endl;
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
}
|
||||
return performStartHandling();
|
||||
}
|
||||
|
||||
ReturnValue_t WatchdogHandler::performStartHandling() {
|
||||
char startBuf[2];
|
||||
ssize_t writeLen = 1;
|
||||
startBuf[0] = watchdog::first::START_CHAR;
|
||||
if (enableWatchFunction) {
|
||||
writeLen += 1;
|
||||
startBuf[1] = watchdog::second::WATCH_FLAG;
|
||||
}
|
||||
ssize_t writtenBytes = write(watchdogFifoFd, &startBuf, writeLen);
|
||||
if (writtenBytes < 0) {
|
||||
sif::error << "WatchdogHandler: Errors writing to watchdog FIFO, code " << errno << ": "
|
||||
<< strerror(errno) << std::endl;
|
||||
return returnvalue::FAILED;
|
||||
} else if (writtenBytes != writeLen) {
|
||||
sif::warning << "WatchdogHandler: Not all bytes were written, possible error" << std::endl;
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
23
bsp_q7s/core/WatchdogHandler.h
Normal file
23
bsp_q7s/core/WatchdogHandler.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef BSP_Q7S_CORE_WATCHDOGHANDLER_H_
|
||||
#define BSP_Q7S_CORE_WATCHDOGHANDLER_H_
|
||||
|
||||
#include "fsfw/returnvalues/returnvalue.h"
|
||||
|
||||
class WatchdogHandler {
|
||||
public:
|
||||
WatchdogHandler();
|
||||
|
||||
ReturnValue_t initialize(bool enableWatchFunction);
|
||||
void periodicOperation();
|
||||
|
||||
private:
|
||||
// Designated value for rechecking FIFO open
|
||||
static constexpr int RETRY_FIFO_OPEN = -2;
|
||||
|
||||
int watchdogFifoFd = 0;
|
||||
bool enableWatchFunction = false;
|
||||
|
||||
ReturnValue_t performStartHandling();
|
||||
};
|
||||
|
||||
#endif /* BSP_Q7S_CORE_WATCHDOGHANDLER_H_ */
|
@ -240,24 +240,26 @@ void scheduling::initTasks() {
|
||||
if (result != returnvalue::OK) {
|
||||
scheduling::printAddObjectError("ACS_SUBSYSTEM", objects::ACS_SUBSYSTEM);
|
||||
}
|
||||
#if OBSW_ADD_ACS_BOARD == 1
|
||||
result = acsSysTask->addComponent(objects::IMTQ_ASSY);
|
||||
if (result != returnvalue::OK) {
|
||||
scheduling::printAddObjectError("IMTQ_ASSY", objects::IMTQ_ASSY);
|
||||
}
|
||||
result = acsSysTask->addComponent(objects::ACS_BOARD_ASS);
|
||||
if (result != returnvalue::OK) {
|
||||
scheduling::printAddObjectError("ACS_BOARD_ASS", objects::ACS_BOARD_ASS);
|
||||
}
|
||||
#endif /* OBSW_ADD_ACS_HANDLERS */
|
||||
#if OBSW_ADD_RW == 1
|
||||
result = acsSysTask->addComponent(objects::RW_ASSY);
|
||||
if (result != returnvalue::OK) {
|
||||
scheduling::printAddObjectError("RW_ASS", objects::RW_ASSY);
|
||||
}
|
||||
#endif
|
||||
#if OBSW_ADD_SUS_BOARD_ASS == 1
|
||||
result = acsSysTask->addComponent(objects::SUS_BOARD_ASS);
|
||||
if (result != returnvalue::OK) {
|
||||
scheduling::printAddObjectError("SUS_BOARD_ASS", objects::SUS_BOARD_ASS);
|
||||
}
|
||||
#endif
|
||||
result = acsSysTask->addComponent(objects::STR_ASSY);
|
||||
if (result != returnvalue::OK) {
|
||||
scheduling::printAddObjectError("STR_ASSY", objects::STR_ASSY);
|
||||
}
|
||||
|
||||
PeriodicTaskIF* tcsSystemTask = factory->createPeriodicTask(
|
||||
"TCS_TASK", 55, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.5, missedDeadlineFunc);
|
||||
@ -521,6 +523,10 @@ void scheduling::createPusTasks(TaskFactory& factory, TaskDeadlineMissedFunction
|
||||
if (result != returnvalue::OK) {
|
||||
scheduling::printAddObjectError("PUS_8", objects::PUS_SERVICE_8_FUNCTION_MGMT);
|
||||
}
|
||||
result = pusMedPrio->addComponent(objects::PUS_SERVICE_15_TM_STORAGE);
|
||||
if (result != returnvalue::OK) {
|
||||
scheduling::printAddObjectError("PUS_15", objects::PUS_SERVICE_15_TM_STORAGE);
|
||||
}
|
||||
result = pusMedPrio->addComponent(objects::PUS_SERVICE_11_TC_SCHEDULER);
|
||||
if (result != returnvalue::OK) {
|
||||
scheduling::printAddObjectError("PUS_11", objects::PUS_SERVICE_11_TC_SCHEDULER);
|
||||
|
@ -21,15 +21,15 @@ SdCardManager* SdCardManager::INSTANCE = nullptr;
|
||||
|
||||
SdCardManager::SdCardManager() : SystemObject(objects::SDC_MANAGER), cmdExecutor(256) {
|
||||
sdLock = MutexFactory::instance()->createMutex();
|
||||
ReturnValue_t result = sdLock->lockMutex();
|
||||
if (result != returnvalue::OK) {
|
||||
prefLock = MutexFactory::instance()->createMutex();
|
||||
defaultLock = MutexFactory::instance()->createMutex();
|
||||
|
||||
MutexGuard mg(prefLock, LOCK_TYPE, OTHER_TIMEOUT, LOCK_CTX);
|
||||
if (mg.getLockResult() != returnvalue::OK) {
|
||||
sif::error << "SdCardManager::SdCardManager: Mutex lock failed" << std::endl;
|
||||
}
|
||||
uint8_t prefSdRaw = 0;
|
||||
result = scratch::readNumber(scratch::PREFERED_SDC_KEY, prefSdRaw);
|
||||
if (sdLock->unlockMutex() != returnvalue::OK) {
|
||||
sif::error << "SdCardManager::SdCardManager: Mutex unlock failed" << std::endl;
|
||||
}
|
||||
ReturnValue_t result = scratch::readNumber(scratch::PREFERED_SDC_KEY, prefSdRaw);
|
||||
|
||||
if (result != returnvalue::OK) {
|
||||
if (result == scratch::KEY_NOT_FOUND) {
|
||||
@ -37,14 +37,16 @@ SdCardManager::SdCardManager() : SystemObject(objects::SDC_MANAGER), cmdExecutor
|
||||
"Preferred SD card not set. Setting to 0"
|
||||
<< std::endl;
|
||||
setPreferredSdCard(sd::SdCard::SLOT_0);
|
||||
sdInfo.pref = sd::SdCard::SLOT_0;
|
||||
scratch::writeNumber(scratch::PREFERED_SDC_KEY, static_cast<uint8_t>(sd::SdCard::SLOT_0));
|
||||
prefSdRaw = sd::SdCard::SLOT_0;
|
||||
|
||||
} else {
|
||||
// Should not happen.
|
||||
// TODO: Maybe trigger event?
|
||||
sif::error << "SdCardManager::SdCardManager: Reading preferred SD card from scratch"
|
||||
"buffer failed"
|
||||
<< std::endl;
|
||||
sdInfo.pref = sd::SdCard::SLOT_0;
|
||||
prefSdRaw = sd::SdCard::SLOT_0;
|
||||
}
|
||||
}
|
||||
sdInfo.pref = static_cast<sd::SdCard>(prefSdRaw);
|
||||
@ -195,8 +197,9 @@ ReturnValue_t SdCardManager::setSdCardState(sd::SdCard sdCard, bool on) {
|
||||
|
||||
ReturnValue_t SdCardManager::getSdCardsStatus(SdStatePair& active) {
|
||||
using namespace std;
|
||||
MutexGuard mg(sdLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX);
|
||||
if (not filesystem::exists(SD_STATE_FILE)) {
|
||||
MutexGuard mg(sdLock, LOCK_TYPE, SD_LOCK_TIMEOUT, LOCK_CTX);
|
||||
std::error_code e;
|
||||
if (not filesystem::exists(SD_STATE_FILE, e)) {
|
||||
return STATUS_FILE_NEXISTS;
|
||||
}
|
||||
|
||||
@ -237,7 +240,8 @@ ReturnValue_t SdCardManager::mountSdCard(sd::SdCard sdCard) {
|
||||
mountDev = SD_1_DEV_NAME;
|
||||
mountPoint = config::SD_1_MOUNT_POINT;
|
||||
}
|
||||
if (not filesystem::exists(mountDev)) {
|
||||
std::error_code e;
|
||||
if (not filesystem::exists(mountDev, e)) {
|
||||
sif::warning << "SdCardManager::mountSdCard: Device file does not exists. Make sure to"
|
||||
" turn on the SD card"
|
||||
<< std::endl;
|
||||
@ -272,7 +276,8 @@ ReturnValue_t SdCardManager::unmountSdCard(sd::SdCard sdCard) {
|
||||
} else if (sdCard == sd::SdCard::SLOT_1) {
|
||||
mountPoint = config::SD_1_MOUNT_POINT;
|
||||
}
|
||||
if (not filesystem::exists(mountPoint)) {
|
||||
std::error_code e;
|
||||
if (not filesystem::exists(mountPoint, e)) {
|
||||
sif::error << "SdCardManager::unmountSdCard: Default mount point " << mountPoint
|
||||
<< "does not exist" << std::endl;
|
||||
return UNMOUNT_ERROR;
|
||||
@ -378,7 +383,7 @@ void SdCardManager::processSdStatusLine(std::pair<sd::SdState, sd::SdState>& act
|
||||
}
|
||||
|
||||
std::optional<sd::SdCard> SdCardManager::getPreferredSdCard() const {
|
||||
MutexGuard mg(sdLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX);
|
||||
MutexGuard mg(prefLock, LOCK_TYPE, OTHER_TIMEOUT, LOCK_CTX);
|
||||
auto res = mg.getLockResult();
|
||||
if (res != returnvalue::OK) {
|
||||
sif::error << "SdCardManager::getPreferredSdCard: Lock error" << std::endl;
|
||||
@ -387,7 +392,7 @@ std::optional<sd::SdCard> SdCardManager::getPreferredSdCard() const {
|
||||
}
|
||||
|
||||
ReturnValue_t SdCardManager::setPreferredSdCard(sd::SdCard sdCard) {
|
||||
MutexGuard mg(sdLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX);
|
||||
MutexGuard mg(prefLock, LOCK_TYPE, OTHER_TIMEOUT, LOCK_CTX);
|
||||
if (sdCard == sd::SdCard::BOTH) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
@ -399,7 +404,7 @@ ReturnValue_t SdCardManager::updateSdCardStateFile() {
|
||||
if (cmdExecutor.getCurrentState() == CommandExecutor::States::PENDING) {
|
||||
return CommandExecutor::COMMAND_PENDING;
|
||||
}
|
||||
MutexGuard mg(sdLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX);
|
||||
MutexGuard mg(sdLock, LOCK_TYPE, SD_LOCK_TIMEOUT, LOCK_CTX);
|
||||
// Use q7hw utility and pipe the command output into the state file
|
||||
std::string updateCmd = "q7hw sd info all > " + std::string(SD_STATE_FILE);
|
||||
cmdExecutor.load(updateCmd, blocking, printCmdOutput);
|
||||
@ -411,7 +416,7 @@ ReturnValue_t SdCardManager::updateSdCardStateFile() {
|
||||
}
|
||||
|
||||
const char* SdCardManager::getCurrentMountPrefix() const {
|
||||
MutexGuard mg(sdLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX);
|
||||
MutexGuard mg(defaultLock, LOCK_TYPE, OTHER_TIMEOUT, LOCK_CTX);
|
||||
if (currentPrefix.has_value()) {
|
||||
return currentPrefix.value().c_str();
|
||||
}
|
||||
@ -464,7 +469,7 @@ void SdCardManager::setPrintCommandOutput(bool print) { this->printCmdOutput = p
|
||||
|
||||
bool SdCardManager::isSdCardUsable(std::optional<sd::SdCard> sdCard) {
|
||||
{
|
||||
MutexGuard mg(sdLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX);
|
||||
MutexGuard mg(defaultLock, LOCK_TYPE, OTHER_TIMEOUT, LOCK_CTX);
|
||||
if (markedUnusable) {
|
||||
return false;
|
||||
}
|
||||
@ -560,7 +565,7 @@ ReturnValue_t SdCardManager::performFsck(sd::SdCard sdcard, bool printOutput, in
|
||||
}
|
||||
|
||||
void SdCardManager::setActiveSdCard(sd::SdCard sdCard) {
|
||||
MutexGuard mg(sdLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX);
|
||||
MutexGuard mg(defaultLock, LOCK_TYPE, OTHER_TIMEOUT, LOCK_CTX);
|
||||
sdInfo.active = sdCard;
|
||||
if (sdInfo.active == sd::SdCard::SLOT_0) {
|
||||
currentPrefix = config::SD_0_MOUNT_POINT;
|
||||
@ -570,7 +575,7 @@ void SdCardManager::setActiveSdCard(sd::SdCard sdCard) {
|
||||
}
|
||||
|
||||
std::optional<sd::SdCard> SdCardManager::getActiveSdCard() const {
|
||||
MutexGuard mg(sdLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX);
|
||||
MutexGuard mg(defaultLock, LOCK_TYPE, OTHER_TIMEOUT, LOCK_CTX);
|
||||
if (markedUnusable) {
|
||||
return std::nullopt;
|
||||
}
|
||||
@ -578,6 +583,6 @@ std::optional<sd::SdCard> SdCardManager::getActiveSdCard() const {
|
||||
}
|
||||
|
||||
void SdCardManager::markUnusable() {
|
||||
MutexGuard mg(sdLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX);
|
||||
MutexGuard mg(defaultLock, LOCK_TYPE, OTHER_TIMEOUT, LOCK_CTX);
|
||||
markedUnusable = true;
|
||||
}
|
||||
|
@ -224,8 +224,11 @@ class SdCardManager : public SystemObject, public SdCardMountedIF {
|
||||
bool printCmdOutput = true;
|
||||
bool markedUnusable = false;
|
||||
MutexIF* sdLock = nullptr;
|
||||
MutexIF* prefLock = nullptr;
|
||||
MutexIF* defaultLock = nullptr;
|
||||
static constexpr MutexIF::TimeoutType LOCK_TYPE = MutexIF::TimeoutType::WAITING;
|
||||
static constexpr uint32_t LOCK_TIMEOUT = 40;
|
||||
static constexpr uint32_t SD_LOCK_TIMEOUT = 250;
|
||||
static constexpr uint32_t OTHER_TIMEOUT = 20;
|
||||
static constexpr char LOCK_CTX[] = "SdCardManager";
|
||||
|
||||
SdCardManager();
|
||||
|
@ -12,10 +12,10 @@
|
||||
* @brief This is the main program for the target hardware.
|
||||
* @return
|
||||
*/
|
||||
int main(void) {
|
||||
int main(int argc, char* argv[]) {
|
||||
using namespace std;
|
||||
#if Q7S_SIMPLE_MODE == 0
|
||||
return obsw::obsw();
|
||||
return obsw::obsw(argc, argv);
|
||||
#else
|
||||
return simple::simple();
|
||||
#endif
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef BSP_Q7S_MEMORY_LOCALPARAMETERHANDLER_H_
|
||||
#define BSP_Q7S_MEMORY_LOCALPARAMETERHANDLER_H_
|
||||
|
||||
#include <mission/memory/NVMParameterBase.h>
|
||||
#include <mission/memory/NvmParameterBase.h>
|
||||
#include <mission/memory/SdCardMountedIF.h>
|
||||
|
||||
#include <string>
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "OBSWConfig.h"
|
||||
#include "bsp_q7s/core/WatchdogHandler.h"
|
||||
#include "commonConfig.h"
|
||||
#include "core/scheduling.h"
|
||||
#include "fsfw/tasks/TaskFactory.h"
|
||||
@ -18,13 +19,16 @@
|
||||
#include "q7sConfig.h"
|
||||
#include "watchdog/definitions.h"
|
||||
|
||||
static int OBSW_ALREADY_RUNNING = -2;
|
||||
static constexpr int OBSW_ALREADY_RUNNING = -2;
|
||||
#if OBSW_Q7S_EM == 0
|
||||
static const char* DEV_STRING = "Xiphos Q7S FM";
|
||||
#else
|
||||
static const char* DEV_STRING = "Xiphos Q7S EM";
|
||||
#endif
|
||||
int obsw::obsw() {
|
||||
|
||||
WatchdogHandler WATCHDOG_HANDLER;
|
||||
|
||||
int obsw::obsw(int argc, char* argv[]) {
|
||||
using namespace fsfw;
|
||||
std::cout << "-- EIVE OBSW --" << std::endl;
|
||||
std::cout << "-- Compiled for Linux (" << DEV_STRING << ") --" << std::endl;
|
||||
@ -33,9 +37,10 @@ int obsw::obsw() {
|
||||
std::cout << "-- " << __DATE__ << " " << __TIME__ << " --" << std::endl;
|
||||
|
||||
#if Q7S_CHECK_FOR_ALREADY_RUNNING_IMG == 1
|
||||
std::error_code e;
|
||||
// Check special file here. This file is created or deleted by the eive-watchdog application
|
||||
// or systemd service!
|
||||
if (std::filesystem::exists(watchdog::RUNNING_FILE_NAME)) {
|
||||
if (std::filesystem::exists(watchdog::RUNNING_FILE_NAME, e)) {
|
||||
sif::warning << "File " << watchdog::RUNNING_FILE_NAME
|
||||
<< " exists so the software might "
|
||||
"already be running. Check if obsw systemd service has been stopped."
|
||||
@ -44,14 +49,45 @@ int obsw::obsw() {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Delay the boot if applicable.
|
||||
bootDelayHandling();
|
||||
|
||||
bool initWatchFunction = false;
|
||||
std::string fullExecPath = argv[0];
|
||||
if (fullExecPath.find("/usr/bin") != std::string::npos) {
|
||||
initWatchFunction = true;
|
||||
}
|
||||
ReturnValue_t result = WATCHDOG_HANDLER.initialize(initWatchFunction);
|
||||
if (result != returnvalue::OK) {
|
||||
std::cerr << "Initiating EIVE watchdog handler failed" << std::endl;
|
||||
}
|
||||
|
||||
scheduling::initMission();
|
||||
|
||||
// Command the EIVE system to safe mode
|
||||
#if OBSW_COMMAND_SAFE_MODE_AT_STARTUP == 1
|
||||
commandEiveSystemToSafe();
|
||||
#else
|
||||
announceAllModes();
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
WATCHDOG_HANDLER.periodicOperation();
|
||||
TaskFactory::delayTask(2000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void obsw::bootDelayHandling() {
|
||||
const char* homedir = nullptr;
|
||||
homedir = getenv("HOME");
|
||||
if (homedir == nullptr) {
|
||||
homedir = getpwuid(getuid())->pw_dir;
|
||||
}
|
||||
std::filesystem::path bootDelayFile = std::filesystem::path(homedir) / "boot_delay_secs.txt";
|
||||
std::error_code e;
|
||||
// Init delay handling.
|
||||
if (std::filesystem::exists(bootDelayFile)) {
|
||||
if (std::filesystem::exists(bootDelayFile, e)) {
|
||||
std::ifstream ifile(bootDelayFile);
|
||||
std::string lineStr;
|
||||
unsigned int bootDelaySecs = 0;
|
||||
@ -71,31 +107,26 @@ int obsw::obsw() {
|
||||
std::cout << "Delaying OBSW start for " << bootDelaySecs << " seconds" << std::endl;
|
||||
TaskFactory::delayTask(bootDelaySecs * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
scheduling::initMission();
|
||||
|
||||
// Command the EIVE system to safe mode
|
||||
void obsw::commandEiveSystemToSafe() {
|
||||
auto sysQueueId = satsystem::EIVE_SYSTEM.getCommandQueue();
|
||||
CommandMessage msg;
|
||||
#if OBSW_COMMAND_SAFE_MODE_AT_STARTUP == 1
|
||||
ModeMessage::setCmdModeMessage(msg, acs::AcsMode::SAFE, 0);
|
||||
ReturnValue_t result =
|
||||
MessageQueueSenderIF::sendMessage(sysQueueId, &msg, MessageQueueIF::NO_QUEUE, false);
|
||||
if (result != returnvalue::OK) {
|
||||
sif::error << "Sending safe mode command to EIVE system failed" << std::endl;
|
||||
}
|
||||
#else
|
||||
}
|
||||
|
||||
void obsw::announceAllModes() {
|
||||
auto sysQueueId = satsystem::EIVE_SYSTEM.getCommandQueue();
|
||||
CommandMessage msg;
|
||||
ModeMessage::setModeAnnounceMessage(msg, true);
|
||||
ReturnValue_t result =
|
||||
MessageQueueSenderIF::sendMessage(sysQueueId, &msg, MessageQueueIF::NO_QUEUE, false);
|
||||
if (result != returnvalue::OK) {
|
||||
sif::error << "Sending safe mode command to EIVE system failed" << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
/* Suspend main thread by sleeping it. */
|
||||
TaskFactory::delayTask(5000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -3,8 +3,12 @@
|
||||
|
||||
namespace obsw {
|
||||
|
||||
int obsw();
|
||||
int obsw(int argc, char* argv[]);
|
||||
|
||||
};
|
||||
void bootDelayHandling();
|
||||
void commandEiveSystemToSafe();
|
||||
void announceAllModes();
|
||||
|
||||
}; // namespace obsw
|
||||
|
||||
#endif /* BSP_Q7S_CORE_OBSW_H_ */
|
||||
|
@ -59,10 +59,10 @@ namespace spiSched {
|
||||
|
||||
static constexpr uint32_t SCHED_BLOCK_1_SUS_READ_MS = 15;
|
||||
static constexpr uint32_t SCHED_BLOCK_2_SENSOR_READ_MS = 30;
|
||||
static constexpr uint32_t SCHED_BLOCK_3_READ_IMTQ_MGM_MS = 42;
|
||||
static constexpr uint32_t SCHED_BLOCK_3_READ_IMTQ_MGM_MS = 43;
|
||||
static constexpr uint32_t SCHED_BLOCK_4_ACS_CTRL_MS = 45;
|
||||
static constexpr uint32_t SCHED_BLOCK_5_ACTUATOR_MS = 55;
|
||||
static constexpr uint32_t SCHED_BLOCK_6_IMTQ_BLOCK_2_MS = 95;
|
||||
static constexpr uint32_t SCHED_BLOCK_6_IMTQ_BLOCK_2_MS = 105;
|
||||
static constexpr uint32_t SCHED_BLOCK_RTD = 150;
|
||||
static constexpr uint32_t SCHED_BLOCK_7_RW_READ_MS = 300;
|
||||
static constexpr uint32_t SCHED_BLOCK_8_PLPCDU_MS = 320;
|
||||
|
@ -145,6 +145,8 @@ enum commonObjects : uint32_t {
|
||||
RW_ASSY = 0x73000004,
|
||||
CAM_SWITCHER = 0x73000006,
|
||||
SYRLINKS_ASSY = 0x73000007,
|
||||
IMTQ_ASSY = 0x73000008,
|
||||
STR_ASSY = 0x73000009,
|
||||
EIVE_SYSTEM = 0x73010000,
|
||||
ACS_SUBSYSTEM = 0x73010001,
|
||||
PL_SUBSYSTEM = 0x73010002,
|
||||
|
2
fsfw
2
fsfw
Submodule fsfw updated: 33de15205b...26e4445189
@ -250,12 +250,14 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path
|
||||
13904;0x3650;WRITE_CONFIGFILE_FAILED;MEDIUM;No description;mission/utility/GlobalConfigHandler.h
|
||||
13905;0x3651;READ_CONFIGFILE_FAILED;MEDIUM;No description;mission/utility/GlobalConfigHandler.h
|
||||
14000;0x36b0;ALLOC_FAILURE;MEDIUM;No description;bsp_q7s/core/CoreController.h
|
||||
14001;0x36b1;REBOOT_SW;MEDIUM; Software reboot occurred. Can also be a systemd reboot. P1: Current Chip, P2: Current Copy;bsp_q7s/core/CoreController.h
|
||||
14001;0x36b1;REBOOT_SW;LOW; Software reboot occurred. Can also be a systemd reboot. P1: Current Chip, P2: Current Copy;bsp_q7s/core/CoreController.h
|
||||
14002;0x36b2;REBOOT_MECHANISM_TRIGGERED;MEDIUM;The reboot mechanism was triggered. P1: First 16 bits: Last Chip, Last 16 bits: Last Copy, P2: Each byte is the respective reboot count for the slots;bsp_q7s/core/CoreController.h
|
||||
14003;0x36b3;REBOOT_HW;MEDIUM;No description;bsp_q7s/core/CoreController.h
|
||||
14004;0x36b4;NO_SD_CARD_ACTIVE;HIGH;No SD card was active. Core controller will attempt to re-initialize a SD card.;bsp_q7s/core/CoreController.h
|
||||
14005;0x36b5;VERSION_INFO;INFO;P1: Byte 0: Major, Byte 1: Minor, Byte 2: Patch, Byte 3: Has Git Hash P2: First four letters of Git SHA is the last byte of P1 is set.;bsp_q7s/core/CoreController.h
|
||||
14006;0x36b6;CURRENT_IMAGE_INFO;INFO;P1: Current Chip, P2: Current Copy;bsp_q7s/core/CoreController.h
|
||||
14007;0x36b7;REBOOT_COUNTER;INFO;Total reboot counter, which is the sum of the boot count of all individual images.;bsp_q7s/core/CoreController.h
|
||||
14008;0x36b8;INDIVIDUAL_BOOT_COUNTS;INFO;Get the boot count of the individual images. P1: First 16 bits boot count of image 0 0, last 16 bits boot count of image 0 1. P2: First 16 bits boot count of image 1 0, last 16 bits boot count of image 1 1.;bsp_q7s/core/CoreController.h
|
||||
14100;0x3714;NO_VALID_SENSOR_TEMPERATURE;MEDIUM;No description;mission/controller/ThermalController.h
|
||||
14101;0x3715;NO_HEALTHY_HEATER_AVAILABLE;MEDIUM;No description;mission/controller/ThermalController.h
|
||||
14102;0x3716;SYRLINKS_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
|
||||
|
|
@ -137,6 +137,8 @@
|
||||
0x73000004;RW_ASSY
|
||||
0x73000006;CAM_SWITCHER
|
||||
0x73000007;SYRLINKS_ASSY
|
||||
0x73000008;IMTQ_ASSY
|
||||
0x73000009;STR_ASSY
|
||||
0x73000100;TM_FUNNEL
|
||||
0x73000101;PUS_TM_FUNNEL
|
||||
0x73000102;CFDP_TM_FUNNEL
|
||||
|
|
@ -1,7 +1,7 @@
|
||||
Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path
|
||||
0x0000;OK;System-wide code for ok.;0;HasReturnvaluesIF;fsfw/returnvalues/returnvalue.h
|
||||
0x0001;Failed;Unspecified system-wide code for failed.;1;HasReturnvaluesIF;fsfw/returnvalues/returnvalue.h
|
||||
0x63a0;NVMB_KeyNotExists;Specified key does not exist in json file;160;NVM_PARAM_BASE;mission/memory/NVMParameterBase.h
|
||||
0x63a0;NVMB_KeyNotExists;Specified key does not exist in json file;160;NVM_PARAM_BASE;mission/memory/NvmParameterBase.h
|
||||
0x5100;IMTQ_InvalidCommandCode;No description;0;IMTQ_HANDLER;mission/devices/devicedefinitions/imtqHelpers.h
|
||||
0x5101;IMTQ_MgmMeasurementLowLevelError;No description;1;IMTQ_HANDLER;mission/devices/devicedefinitions/imtqHelpers.h
|
||||
0x5102;IMTQ_ActuateCmdLowLevelError;No description;2;IMTQ_HANDLER;mission/devices/devicedefinitions/imtqHelpers.h
|
||||
|
|
@ -250,12 +250,14 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path
|
||||
13904;0x3650;WRITE_CONFIGFILE_FAILED;MEDIUM;No description;mission/utility/GlobalConfigHandler.h
|
||||
13905;0x3651;READ_CONFIGFILE_FAILED;MEDIUM;No description;mission/utility/GlobalConfigHandler.h
|
||||
14000;0x36b0;ALLOC_FAILURE;MEDIUM;No description;bsp_q7s/core/CoreController.h
|
||||
14001;0x36b1;REBOOT_SW;MEDIUM; Software reboot occurred. Can also be a systemd reboot. P1: Current Chip, P2: Current Copy;bsp_q7s/core/CoreController.h
|
||||
14001;0x36b1;REBOOT_SW;LOW; Software reboot occurred. Can also be a systemd reboot. P1: Current Chip, P2: Current Copy;bsp_q7s/core/CoreController.h
|
||||
14002;0x36b2;REBOOT_MECHANISM_TRIGGERED;MEDIUM;The reboot mechanism was triggered. P1: First 16 bits: Last Chip, Last 16 bits: Last Copy, P2: Each byte is the respective reboot count for the slots;bsp_q7s/core/CoreController.h
|
||||
14003;0x36b3;REBOOT_HW;MEDIUM;No description;bsp_q7s/core/CoreController.h
|
||||
14004;0x36b4;NO_SD_CARD_ACTIVE;HIGH;No SD card was active. Core controller will attempt to re-initialize a SD card.;bsp_q7s/core/CoreController.h
|
||||
14005;0x36b5;VERSION_INFO;INFO;P1: Byte 0: Major, Byte 1: Minor, Byte 2: Patch, Byte 3: Has Git Hash P2: First four letters of Git SHA is the last byte of P1 is set.;bsp_q7s/core/CoreController.h
|
||||
14006;0x36b6;CURRENT_IMAGE_INFO;INFO;P1: Current Chip, P2: Current Copy;bsp_q7s/core/CoreController.h
|
||||
14007;0x36b7;REBOOT_COUNTER;INFO;Total reboot counter, which is the sum of the boot count of all individual images.;bsp_q7s/core/CoreController.h
|
||||
14008;0x36b8;INDIVIDUAL_BOOT_COUNTS;INFO;Get the boot count of the individual images. P1: First 16 bits boot count of image 0 0, last 16 bits boot count of image 0 1. P2: First 16 bits boot count of image 1 0, last 16 bits boot count of image 1 1.;bsp_q7s/core/CoreController.h
|
||||
14100;0x3714;NO_VALID_SENSOR_TEMPERATURE;MEDIUM;No description;mission/controller/ThermalController.h
|
||||
14101;0x3715;NO_HEALTHY_HEATER_AVAILABLE;MEDIUM;No description;mission/controller/ThermalController.h
|
||||
14102;0x3716;SYRLINKS_OVERHEATING;HIGH;No description;mission/controller/ThermalController.h
|
||||
|
|
@ -142,6 +142,8 @@
|
||||
0x73000004;RW_ASSY
|
||||
0x73000006;CAM_SWITCHER
|
||||
0x73000007;SYRLINKS_ASSY
|
||||
0x73000008;IMTQ_ASSY
|
||||
0x73000009;STR_ASSY
|
||||
0x73000100;TM_FUNNEL
|
||||
0x73000101;PUS_TM_FUNNEL
|
||||
0x73000102;CFDP_TM_FUNNEL
|
||||
|
|
@ -1,7 +1,7 @@
|
||||
Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path
|
||||
0x0000;OK;System-wide code for ok.;0;HasReturnvaluesIF;fsfw/returnvalues/returnvalue.h
|
||||
0x0001;Failed;Unspecified system-wide code for failed.;1;HasReturnvaluesIF;fsfw/returnvalues/returnvalue.h
|
||||
0x63a0;NVMB_KeyNotExists;Specified key does not exist in json file;160;NVM_PARAM_BASE;mission/memory/NVMParameterBase.h
|
||||
0x63a0;NVMB_KeyNotExists;Specified key does not exist in json file;160;NVM_PARAM_BASE;mission/memory/NvmParameterBase.h
|
||||
0x5100;IMTQ_InvalidCommandCode;No description;0;IMTQ_HANDLER;mission/devices/devicedefinitions/imtqHelpers.h
|
||||
0x5101;IMTQ_MgmMeasurementLowLevelError;No description;1;IMTQ_HANDLER;mission/devices/devicedefinitions/imtqHelpers.h
|
||||
0x5102;IMTQ_ActuateCmdLowLevelError;No description;2;IMTQ_HANDLER;mission/devices/devicedefinitions/imtqHelpers.h
|
||||
|
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @brief Auto-generated event translation file. Contains 267 translations.
|
||||
* @brief Auto-generated event translation file. Contains 269 translations.
|
||||
* @details
|
||||
* Generated on: 2023-03-02 17:08:11
|
||||
* Generated on: 2023-03-08 16:44:32
|
||||
*/
|
||||
#include "translateEvents.h"
|
||||
|
||||
@ -257,6 +257,8 @@ const char *REBOOT_HW_STRING = "REBOOT_HW";
|
||||
const char *NO_SD_CARD_ACTIVE_STRING = "NO_SD_CARD_ACTIVE";
|
||||
const char *VERSION_INFO_STRING = "VERSION_INFO";
|
||||
const char *CURRENT_IMAGE_INFO_STRING = "CURRENT_IMAGE_INFO";
|
||||
const char *REBOOT_COUNTER_STRING = "REBOOT_COUNTER";
|
||||
const char *INDIVIDUAL_BOOT_COUNTS_STRING = "INDIVIDUAL_BOOT_COUNTS";
|
||||
const char *NO_VALID_SENSOR_TEMPERATURE_STRING = "NO_VALID_SENSOR_TEMPERATURE";
|
||||
const char *NO_HEALTHY_HEATER_AVAILABLE_STRING = "NO_HEALTHY_HEATER_AVAILABLE";
|
||||
const char *SYRLINKS_OVERHEATING_STRING = "SYRLINKS_OVERHEATING";
|
||||
@ -774,6 +776,10 @@ const char *translateEvents(Event event) {
|
||||
return VERSION_INFO_STRING;
|
||||
case (14006):
|
||||
return CURRENT_IMAGE_INFO_STRING;
|
||||
case (14007):
|
||||
return REBOOT_COUNTER_STRING;
|
||||
case (14008):
|
||||
return INDIVIDUAL_BOOT_COUNTS_STRING;
|
||||
case (14100):
|
||||
return NO_VALID_SENSOR_TEMPERATURE_STRING;
|
||||
case (14101):
|
||||
|
@ -1,8 +1,8 @@
|
||||
/**
|
||||
* @brief Auto-generated object translation file.
|
||||
* @details
|
||||
* Contains 162 translations.
|
||||
* Generated on: 2023-03-02 17:08:11
|
||||
* Contains 164 translations.
|
||||
* Generated on: 2023-03-08 16:44:32
|
||||
*/
|
||||
#include "translateObjects.h"
|
||||
|
||||
@ -150,6 +150,8 @@ const char *TCS_BOARD_ASS_STRING = "TCS_BOARD_ASS";
|
||||
const char *RW_ASSY_STRING = "RW_ASSY";
|
||||
const char *CAM_SWITCHER_STRING = "CAM_SWITCHER";
|
||||
const char *SYRLINKS_ASSY_STRING = "SYRLINKS_ASSY";
|
||||
const char *IMTQ_ASSY_STRING = "IMTQ_ASSY";
|
||||
const char *STR_ASSY_STRING = "STR_ASSY";
|
||||
const char *TM_FUNNEL_STRING = "TM_FUNNEL";
|
||||
const char *PUS_TM_FUNNEL_STRING = "PUS_TM_FUNNEL";
|
||||
const char *CFDP_TM_FUNNEL_STRING = "CFDP_TM_FUNNEL";
|
||||
@ -459,6 +461,10 @@ const char *translateObject(object_id_t object) {
|
||||
return CAM_SWITCHER_STRING;
|
||||
case 0x73000007:
|
||||
return SYRLINKS_ASSY_STRING;
|
||||
case 0x73000008:
|
||||
return IMTQ_ASSY_STRING;
|
||||
case 0x73000009:
|
||||
return STR_ASSY_STRING;
|
||||
case 0x73000100:
|
||||
return TM_FUNNEL_STRING;
|
||||
case 0x73000101:
|
||||
|
@ -214,16 +214,14 @@ ReturnValue_t GpsHyperionLinuxController::handleGpsReadData() {
|
||||
}
|
||||
|
||||
bool validFix = false;
|
||||
uint8_t newFix = 0;
|
||||
if (modeIsSet) {
|
||||
// 0: Not seen, 1: No fix, 2: 2D-Fix, 3: 3D-Fix
|
||||
if (gps.fix.mode == 2 or gps.fix.mode == 3) {
|
||||
validFix = true;
|
||||
}
|
||||
if (gpsSet.fixMode.value != gps.fix.mode) {
|
||||
triggerEvent(GpsHyperion::GPS_FIX_CHANGE, gpsSet.fixMode.value, gps.fix.mode);
|
||||
}
|
||||
gpsSet.fixMode.value = gps.fix.mode;
|
||||
if (gps.fix.mode == 0 or gps.fix.mode == 1) {
|
||||
newFix = gps.fix.mode;
|
||||
if (newFix == 0 or newFix == 1) {
|
||||
if (modeCommanded and maxTimeToReachFix.hasTimedOut()) {
|
||||
// We are supposed to be on and functioning, but no fix was found
|
||||
if (mode == MODE_ON or mode == MODE_NORMAL) {
|
||||
@ -233,6 +231,10 @@ ReturnValue_t GpsHyperionLinuxController::handleGpsReadData() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gpsSet.fixMode.value != newFix) {
|
||||
triggerEvent(GpsHyperion::GPS_FIX_CHANGE, gpsSet.fixMode.value, newFix);
|
||||
}
|
||||
gpsSet.fixMode = newFix;
|
||||
gpsSet.fixMode.setValid(modeIsSet);
|
||||
|
||||
// Only set on specific messages, so only set a valid flag to invalid
|
||||
|
@ -28,6 +28,8 @@ ReturnValue_t ImtqPollingTask::performOperation(uint8_t operationCode) {
|
||||
// Stopwatch watch;
|
||||
switch (currentRequest) {
|
||||
case imtq::RequestType::MEASURE_NO_ACTUATION: {
|
||||
// Measured to take 24 ms for debug and release builds.
|
||||
// Stopwatch watch;
|
||||
handleMeasureStep();
|
||||
break;
|
||||
}
|
||||
@ -35,6 +37,9 @@ ReturnValue_t ImtqPollingTask::performOperation(uint8_t operationCode) {
|
||||
handleActuateStep();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
return returnvalue::OK;
|
||||
@ -44,6 +49,9 @@ void ImtqPollingTask::handleMeasureStep() {
|
||||
size_t replyLen = 0;
|
||||
uint8_t* replyPtr;
|
||||
ImtqRepliesDefault replies(replyBuf.data());
|
||||
// If some startup handling is added later, set configured after it was done once.
|
||||
replies.setConfigured();
|
||||
|
||||
// Can be used later to verify correct timing (e.g. all data has been read)
|
||||
clearReadFlagsDefault(replies);
|
||||
auto i2cCmdExecMeasure = [&](imtq::CC::CC cc) {
|
||||
@ -118,12 +126,19 @@ void ImtqPollingTask::handleMeasureStep() {
|
||||
}
|
||||
// Takes a bit of time to take measurements. Subtract a bit because of the delay of previous
|
||||
// commands.
|
||||
TaskFactory::delayTask(currentIntegrationTimeMs);
|
||||
TaskFactory::delayTask(currentIntegrationTimeMs + MGM_READ_BUFFER_TIME_MS);
|
||||
|
||||
cmdBuf[0] = imtq::CC::GET_RAW_MTM_MEASUREMENT;
|
||||
if (i2cCmdExecMeasure(imtq::CC::GET_RAW_MTM_MEASUREMENT) != returnvalue::OK) {
|
||||
return;
|
||||
}
|
||||
bool mgmMeasurementTooOld = false;
|
||||
// See p.39 of the iMTQ user manual. If the NEW bit of the STAT bitfield is not set, we probably
|
||||
// have old data. Which can be really bad for ACS. And everything.
|
||||
if ((replyPtr[2] >> 7) == 0) {
|
||||
replyPtr[0] = false;
|
||||
mgmMeasurementTooOld = true;
|
||||
}
|
||||
|
||||
cmdBuf[0] = imtq::CC::GET_ENG_HK_DATA;
|
||||
if (i2cCmdExecMeasure(imtq::CC::GET_ENG_HK_DATA) != returnvalue::OK) {
|
||||
@ -134,7 +149,9 @@ void ImtqPollingTask::handleMeasureStep() {
|
||||
if (i2cCmdExecMeasure(imtq::CC::GET_CAL_MTM_MEASUREMENT) != returnvalue::OK) {
|
||||
return;
|
||||
}
|
||||
// sif::debug << "measure done" << std::endl;
|
||||
if (mgmMeasurementTooOld) {
|
||||
sif::error << "IMTQ: MGM measurement too old" << std::endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -157,23 +174,36 @@ void ImtqPollingTask::handleActuateStep() {
|
||||
return;
|
||||
}
|
||||
|
||||
TaskFactory::delayTask(10);
|
||||
|
||||
cmdLen = 1;
|
||||
cmdBuf[0] = imtq::CC::START_MTM_MEASUREMENT;
|
||||
if (i2cCmdExecActuate(imtq::CC::START_MTM_MEASUREMENT) != returnvalue::OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
TaskFactory::delayTask(currentIntegrationTimeMs);
|
||||
TaskFactory::delayTask(currentIntegrationTimeMs + MGM_READ_BUFFER_TIME_MS);
|
||||
|
||||
cmdBuf[0] = imtq::CC::GET_RAW_MTM_MEASUREMENT;
|
||||
if (i2cCmdExecActuate(imtq::CC::GET_RAW_MTM_MEASUREMENT) != returnvalue::OK) {
|
||||
return;
|
||||
}
|
||||
bool measurementWasTooOld = false;
|
||||
// See p.39 of the iMTQ user manual. If the NEW bit of the STAT bitfield is not set, we probably
|
||||
// have old data. Which can be really bad for ACS. And everything.
|
||||
if ((replyPtr[2] >> 7) == 0) {
|
||||
measurementWasTooOld = true;
|
||||
replyPtr[0] = false;
|
||||
}
|
||||
|
||||
cmdBuf[0] = imtq::CC::GET_ENG_HK_DATA;
|
||||
if (i2cCmdExecActuate(imtq::CC::GET_ENG_HK_DATA) != returnvalue::OK) {
|
||||
return;
|
||||
}
|
||||
// sif::debug << "measure with torque done" << std::endl;
|
||||
|
||||
if (measurementWasTooOld) {
|
||||
sif::error << "IMTQ: MGM measurement too old" << std::endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -192,15 +222,15 @@ ReturnValue_t ImtqPollingTask::initializeInterface(CookieIF* cookie) {
|
||||
|
||||
ReturnValue_t ImtqPollingTask::sendMessage(CookieIF* cookie, const uint8_t* sendData,
|
||||
size_t sendLen) {
|
||||
ImtqRequest request(sendData, sendLen);
|
||||
const auto* imtqReq = reinterpret_cast<const imtq::Request*>(sendData);
|
||||
{
|
||||
MutexGuard mg(ipcLock);
|
||||
currentRequest = request.getRequestType();
|
||||
if (currentRequest == imtq::RequestType::ACTUATE) {
|
||||
std::memcpy(dipoles, request.getDipoles(), 6);
|
||||
torqueDuration = request.getTorqueDuration();
|
||||
if (imtqReq->request == imtq::RequestType::ACTUATE) {
|
||||
std::memcpy(dipoles, imtqReq->dipoles, sizeof(dipoles));
|
||||
torqueDuration = imtqReq->torqueDuration;
|
||||
}
|
||||
specialRequest = request.getSpecialRequest();
|
||||
currentRequest = imtqReq->request;
|
||||
specialRequest = imtqReq->specialRequest;
|
||||
if (state != InternalState::IDLE) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
@ -309,6 +339,8 @@ void ImtqPollingTask::buildDipoleCommand() {
|
||||
}
|
||||
SerializeAdapter::serialize(&torqueDuration, &serPtr, &serLen, cmdBuf.size(),
|
||||
SerializeIF::Endianness::LITTLE);
|
||||
// sif::debug << "Dipole X: " << dipoles[0] << std::endl;
|
||||
// sif::debug << "Torqeu Dur: " << torqueDuration << std::endl;
|
||||
cmdLen = 1 + serLen;
|
||||
}
|
||||
|
||||
@ -325,9 +357,11 @@ ReturnValue_t ImtqPollingTask::readReceivedMessage(CookieIF* cookie, uint8_t** b
|
||||
if (currentRequest == imtq::RequestType::MEASURE_NO_ACTUATION) {
|
||||
replyLen = getExchangeBufLen(specialRequest);
|
||||
memcpy(exchangeBuf.data(), replyBuf.data(), replyLen);
|
||||
} else {
|
||||
} else if (currentRequest == imtq::RequestType::ACTUATE) {
|
||||
replyLen = ImtqRepliesWithTorque::BASE_LEN;
|
||||
memcpy(exchangeBuf.data(), replyBufActuation.data(), replyLen);
|
||||
} else {
|
||||
*size = 0;
|
||||
}
|
||||
*buffer = exchangeBuf.data();
|
||||
*size = replyLen;
|
||||
|
@ -32,12 +32,13 @@ class ImtqPollingTask : public SystemObject,
|
||||
const char* i2cDev = nullptr;
|
||||
address_t i2cAddr = 0;
|
||||
uint32_t currentIntegrationTimeMs = 10;
|
||||
// Required in addition to integration time, otherwise old data might be read.
|
||||
static constexpr uint32_t MGM_READ_BUFFER_TIME_MS = 6;
|
||||
bool ignoreNextActuateRequest = false;
|
||||
|
||||
imtq::SpecialRequest specialRequest = imtq::SpecialRequest::NONE;
|
||||
int16_t dipoles[3] = {};
|
||||
uint16_t torqueDuration = 0;
|
||||
// uint8_t startActuateRawBuf[3] = {};
|
||||
|
||||
std::array<uint8_t, 32> cmdBuf;
|
||||
std::array<uint8_t, 524> replyBuf;
|
||||
|
@ -5,14 +5,14 @@
|
||||
ArcsecJsonParamBase::ArcsecJsonParamBase(std::string setName) : setName(setName) {}
|
||||
|
||||
ReturnValue_t ArcsecJsonParamBase::create(std::string fullname, uint8_t* buffer) {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
result = init(fullname);
|
||||
if (result != returnvalue::OK) {
|
||||
sif::warning << "ArcsecJsonParamBase::create: Failed to init parameter command for set "
|
||||
<< setName << std::endl;
|
||||
return result;
|
||||
}
|
||||
result = createCommand(buffer);
|
||||
// ReturnValue_t result = returnvalue::OK;
|
||||
// result = init(fullname);
|
||||
// if (result != returnvalue::OK) {
|
||||
// sif::warning << "ArcsecJsonParamBase::create: Failed to init parameter command for set "
|
||||
// << setName << std::endl;
|
||||
// return result;
|
||||
// }
|
||||
ReturnValue_t result = createCommand(buffer);
|
||||
if (result != returnvalue::OK) {
|
||||
sif::warning << "ArcsecJsonParamBase::create: Failed to create parameter command for set "
|
||||
<< setName << std::endl;
|
||||
@ -74,12 +74,17 @@ ReturnValue_t ArcsecJsonParamBase::init(const std::string filename) {
|
||||
<< std::endl;
|
||||
return JSON_FILE_NOT_EXISTS;
|
||||
}
|
||||
createJsonObject(filename);
|
||||
result = initSet();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
try {
|
||||
createJsonObject(filename);
|
||||
result = initSet();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
return returnvalue::OK;
|
||||
} catch (json::exception& e) {
|
||||
// TODO: Re-create json file from backup here.
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
void ArcsecJsonParamBase::createJsonObject(const std::string fullname) {
|
||||
|
@ -41,6 +41,17 @@ class ArcsecJsonParamBase {
|
||||
*/
|
||||
ArcsecJsonParamBase(std::string setName);
|
||||
|
||||
/**
|
||||
* @brief Initializes the properties json object and the set json object
|
||||
*
|
||||
* @param fullname Name including absolute path to json file
|
||||
* @param setName The name of the set to work on
|
||||
*
|
||||
* @param return JSON_FILE_NOT_EXISTS if specified file does not exist, otherwise
|
||||
* returnvalue::OK
|
||||
*/
|
||||
ReturnValue_t init(const std::string filename);
|
||||
|
||||
/**
|
||||
* @brief Fills a buffer with a parameter set
|
||||
*
|
||||
@ -124,17 +135,6 @@ class ArcsecJsonParamBase {
|
||||
*/
|
||||
virtual ReturnValue_t createCommand(uint8_t* buffer) = 0;
|
||||
|
||||
/**
|
||||
* @brief Initializes the properties json object and the set json object
|
||||
*
|
||||
* @param fullname Name including absolute path to json file
|
||||
* @param setName The name of the set to work on
|
||||
*
|
||||
* @param return JSON_FILE_NOT_EXISTS if specified file does not exist, otherwise
|
||||
* returnvalue::OK
|
||||
*/
|
||||
ReturnValue_t init(const std::string filename);
|
||||
|
||||
void createJsonObject(const std::string fullname);
|
||||
|
||||
/**
|
||||
|
@ -1,8 +1,11 @@
|
||||
#include "StarTrackerHandler.h"
|
||||
|
||||
#include <fsfw/ipc/QueueFactory.h>
|
||||
#include <fsfw/timemanager/Stopwatch.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <fstream>
|
||||
#include <thread>
|
||||
|
||||
#include "OBSWConfig.h"
|
||||
#include "StarTrackerJsonCommands.h"
|
||||
@ -14,8 +17,11 @@ extern "C" {
|
||||
#include "common/misc.h"
|
||||
}
|
||||
|
||||
std::atomic_bool JCFG_DONE(false);
|
||||
|
||||
StarTrackerHandler::StarTrackerHandler(object_id_t objectId, object_id_t comIF, CookieIF* comCookie,
|
||||
StrHelper* strHelper, power::Switch_t powerSwitch)
|
||||
const char* jsonFileStr, StrHelper* strHelper,
|
||||
power::Switch_t powerSwitch)
|
||||
: DeviceHandlerBase(objectId, comIF, comCookie),
|
||||
temperatureSet(this),
|
||||
versionSet(this),
|
||||
@ -40,6 +46,7 @@ StarTrackerHandler::StarTrackerHandler(object_id_t objectId, object_id_t comIF,
|
||||
logSubscriptionSet(this),
|
||||
debugCameraSet(this),
|
||||
strHelper(strHelper),
|
||||
paramJsonFile(jsonFileStr),
|
||||
powerSwitch(powerSwitch) {
|
||||
if (comCookie == nullptr) {
|
||||
sif::error << "StarTrackerHandler: Invalid com cookie" << std::endl;
|
||||
@ -59,6 +66,11 @@ ReturnValue_t StarTrackerHandler::initialize() {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Spin up a thread to do the JSON initialization, takes 200-250 ms which would
|
||||
// delay whole satellite boot process.
|
||||
jcfgCountdown.resetTimer();
|
||||
jsonCfgTask = std::thread{setUpJsonCfgs, std::ref(jcfgs), paramJsonFile.c_str()};
|
||||
|
||||
EventManagerIF* manager = ObjectManager::instance()->get<EventManagerIF>(objects::EVENT_MANAGER);
|
||||
if (manager == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
@ -240,8 +252,19 @@ void StarTrackerHandler::doStartUp() {
|
||||
// the device handler's submode to the star tracker's mode
|
||||
return;
|
||||
case StartupState::DONE:
|
||||
if (jcfgCountdown.isBusy()) {
|
||||
startupState = StartupState::WAIT_JCFG;
|
||||
return;
|
||||
}
|
||||
startupState = StartupState::IDLE;
|
||||
break;
|
||||
case StartupState::WAIT_JCFG: {
|
||||
if (jcfgCountdown.hasTimedOut()) {
|
||||
startupState = StartupState::IDLE;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
@ -419,8 +442,7 @@ ReturnValue_t StarTrackerHandler::buildCommandFromCommand(DeviceCommandId_t devi
|
||||
return returnvalue::OK;
|
||||
}
|
||||
case (startracker::SUBSCRIPTION): {
|
||||
Subscription subscription;
|
||||
result = prepareParamCommand(commandData, commandDataLen, subscription);
|
||||
result = prepareParamCommand(commandData, commandDataLen, jcfgs.subscription);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
case (startracker::REQ_SOLUTION): {
|
||||
@ -436,68 +458,55 @@ ReturnValue_t StarTrackerHandler::buildCommandFromCommand(DeviceCommandId_t devi
|
||||
return returnvalue::OK;
|
||||
}
|
||||
case (startracker::LIMITS): {
|
||||
Limits limits;
|
||||
result = prepareParamCommand(commandData, commandDataLen, limits);
|
||||
result = prepareParamCommand(commandData, commandDataLen, jcfgs.limits);
|
||||
return result;
|
||||
}
|
||||
case (startracker::MOUNTING): {
|
||||
Mounting mounting;
|
||||
result = prepareParamCommand(commandData, commandDataLen, mounting);
|
||||
result = prepareParamCommand(commandData, commandDataLen, jcfgs.mounting);
|
||||
return result;
|
||||
}
|
||||
case (startracker::IMAGE_PROCESSOR): {
|
||||
ImageProcessor imageProcessor;
|
||||
result = prepareParamCommand(commandData, commandDataLen, imageProcessor);
|
||||
result = prepareParamCommand(commandData, commandDataLen, jcfgs.imageProcessor);
|
||||
return result;
|
||||
}
|
||||
case (startracker::CAMERA): {
|
||||
Camera camera;
|
||||
result = prepareParamCommand(commandData, commandDataLen, camera);
|
||||
result = prepareParamCommand(commandData, commandDataLen, jcfgs.camera);
|
||||
return result;
|
||||
}
|
||||
case (startracker::CENTROIDING): {
|
||||
Centroiding centroiding;
|
||||
result = prepareParamCommand(commandData, commandDataLen, centroiding);
|
||||
result = prepareParamCommand(commandData, commandDataLen, jcfgs.centroiding);
|
||||
return result;
|
||||
}
|
||||
case (startracker::LISA): {
|
||||
Lisa lisa;
|
||||
result = prepareParamCommand(commandData, commandDataLen, lisa);
|
||||
result = prepareParamCommand(commandData, commandDataLen, jcfgs.lisa);
|
||||
return result;
|
||||
}
|
||||
case (startracker::MATCHING): {
|
||||
Matching matching;
|
||||
result = prepareParamCommand(commandData, commandDataLen, matching);
|
||||
result = prepareParamCommand(commandData, commandDataLen, jcfgs.matching);
|
||||
return result;
|
||||
}
|
||||
case (startracker::VALIDATION): {
|
||||
Validation validation;
|
||||
result = prepareParamCommand(commandData, commandDataLen, validation);
|
||||
result = prepareParamCommand(commandData, commandDataLen, jcfgs.validation);
|
||||
return result;
|
||||
}
|
||||
case (startracker::ALGO): {
|
||||
Algo algo;
|
||||
result = prepareParamCommand(commandData, commandDataLen, algo);
|
||||
result = prepareParamCommand(commandData, commandDataLen, jcfgs.algo);
|
||||
return result;
|
||||
}
|
||||
case (startracker::TRACKING): {
|
||||
Tracking tracking;
|
||||
result = prepareParamCommand(commandData, commandDataLen, tracking);
|
||||
result = prepareParamCommand(commandData, commandDataLen, jcfgs.tracking);
|
||||
return result;
|
||||
}
|
||||
case (startracker::LOGLEVEL): {
|
||||
LogLevel logLevel;
|
||||
result = prepareParamCommand(commandData, commandDataLen, logLevel);
|
||||
result = prepareParamCommand(commandData, commandDataLen, jcfgs.logLevel);
|
||||
return result;
|
||||
}
|
||||
case (startracker::LOGSUBSCRIPTION): {
|
||||
LogSubscription logSubscription;
|
||||
result = prepareParamCommand(commandData, commandDataLen, logSubscription);
|
||||
result = prepareParamCommand(commandData, commandDataLen, jcfgs.logSubscription);
|
||||
return result;
|
||||
}
|
||||
case (startracker::DEBUG_CAMERA): {
|
||||
DebugCamera debugCamera;
|
||||
result = prepareParamCommand(commandData, commandDataLen, debugCamera);
|
||||
result = prepareParamCommand(commandData, commandDataLen, jcfgs.debugCamera);
|
||||
return result;
|
||||
}
|
||||
case (startracker::CHECKSUM): {
|
||||
@ -746,6 +755,24 @@ void StarTrackerHandler::bootFirmware(Mode_t toMode) {
|
||||
}
|
||||
}
|
||||
|
||||
void StarTrackerHandler::setUpJsonCfgs(JsonConfigs& cfgs, const char* paramJsonFile) {
|
||||
cfgs.tracking.init(paramJsonFile);
|
||||
cfgs.logLevel.init(paramJsonFile);
|
||||
cfgs.logSubscription.init(paramJsonFile);
|
||||
cfgs.debugCamera.init(paramJsonFile);
|
||||
cfgs.algo.init(paramJsonFile);
|
||||
cfgs.validation.init(paramJsonFile);
|
||||
cfgs.matching.init(paramJsonFile);
|
||||
cfgs.lisa.init(paramJsonFile);
|
||||
cfgs.centroiding.init(paramJsonFile);
|
||||
cfgs.camera.init(paramJsonFile);
|
||||
cfgs.imageProcessor.init(paramJsonFile);
|
||||
cfgs.mounting.init(paramJsonFile);
|
||||
cfgs.limits.init(paramJsonFile);
|
||||
cfgs.subscription.init(paramJsonFile);
|
||||
JCFG_DONE = true;
|
||||
}
|
||||
|
||||
void StarTrackerHandler::bootBootloader() {
|
||||
if (internalState == InternalState::IDLE) {
|
||||
internalState = InternalState::BOOT_BOOTLOADER;
|
||||
@ -1650,6 +1677,7 @@ void StarTrackerHandler::prepareHistogramRequest() {
|
||||
ReturnValue_t StarTrackerHandler::prepareParamCommand(const uint8_t* commandData,
|
||||
size_t commandDataLen,
|
||||
ArcsecJsonParamBase& paramSet) {
|
||||
// Stopwatch watch;
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
if (commandDataLen > MAX_PATH_SIZE) {
|
||||
return FILE_PATH_TOO_LONG;
|
||||
|
@ -2,6 +2,9 @@
|
||||
#define MISSION_DEVICES_STARTRACKERHANDLER_H_
|
||||
|
||||
#include <fsfw/datapool/PoolReadGuard.h>
|
||||
#include <linux/devices/startracker/StarTrackerJsonCommands.h>
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "ArcsecDatalinkLayer.h"
|
||||
#include "ArcsecJsonParamBase.h"
|
||||
@ -35,7 +38,7 @@ class StarTrackerHandler : public DeviceHandlerBase {
|
||||
* to high to enable the device.
|
||||
*/
|
||||
StarTrackerHandler(object_id_t objectId, object_id_t comIF, CookieIF* comCookie,
|
||||
StrHelper* strHelper, power::Switch_t powerSwitch);
|
||||
const char* jsonFileStr, StrHelper* strHelper, power::Switch_t powerSwitch);
|
||||
virtual ~StarTrackerHandler();
|
||||
|
||||
ReturnValue_t initialize() override;
|
||||
@ -216,15 +219,29 @@ class StarTrackerHandler : public DeviceHandlerBase {
|
||||
// Loading firmware requires some time and the command will not trigger a reply when executed
|
||||
Countdown bootCountdown;
|
||||
|
||||
#ifdef EGSE
|
||||
std::string paramJsonFile = "/home/pi/arcsec/json/flight-config.json";
|
||||
#else
|
||||
#if OBSW_STAR_TRACKER_GROUND_CONFIG == 1
|
||||
std::string paramJsonFile = "/mnt/sd0/startracker/ground-config.json";
|
||||
#else
|
||||
std::string paramJsonFile = "/mnt/sd0/startracker/flight-config.json";
|
||||
#endif
|
||||
#endif
|
||||
struct JsonConfigs {
|
||||
Tracking tracking;
|
||||
LogLevel logLevel;
|
||||
LogSubscription logSubscription;
|
||||
DebugCamera debugCamera;
|
||||
Algo algo;
|
||||
Validation validation;
|
||||
Matching matching;
|
||||
Lisa lisa;
|
||||
Centroiding centroiding;
|
||||
Camera camera;
|
||||
ImageProcessor imageProcessor;
|
||||
Mounting mounting;
|
||||
Limits limits;
|
||||
Subscription subscription;
|
||||
};
|
||||
JsonConfigs jcfgs;
|
||||
Countdown jcfgCountdown = Countdown(250);
|
||||
bool commandExecuted = false;
|
||||
std::thread jsonCfgTask;
|
||||
static void setUpJsonCfgs(JsonConfigs& cfgs, const char* paramJsonFile);
|
||||
|
||||
std::string paramJsonFile;
|
||||
|
||||
enum class NormalState { TEMPERATURE_REQUEST, SOLUTION_REQUEST };
|
||||
|
||||
@ -262,7 +279,14 @@ class StarTrackerHandler : public DeviceHandlerBase {
|
||||
|
||||
InternalState internalState = InternalState::IDLE;
|
||||
|
||||
enum class StartupState { IDLE, CHECK_PROGRAM, WAIT_CHECK_PROGRAM, BOOT_BOOTLOADER, DONE };
|
||||
enum class StartupState {
|
||||
IDLE,
|
||||
CHECK_PROGRAM,
|
||||
WAIT_CHECK_PROGRAM,
|
||||
BOOT_BOOTLOADER,
|
||||
WAIT_JCFG,
|
||||
DONE
|
||||
};
|
||||
|
||||
StartupState startupState = StartupState::IDLE;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @brief Auto-generated event translation file. Contains 267 translations.
|
||||
* @brief Auto-generated event translation file. Contains 269 translations.
|
||||
* @details
|
||||
* Generated on: 2023-03-02 17:08:11
|
||||
* Generated on: 2023-03-08 16:44:32
|
||||
*/
|
||||
#include "translateEvents.h"
|
||||
|
||||
@ -257,6 +257,8 @@ const char *REBOOT_HW_STRING = "REBOOT_HW";
|
||||
const char *NO_SD_CARD_ACTIVE_STRING = "NO_SD_CARD_ACTIVE";
|
||||
const char *VERSION_INFO_STRING = "VERSION_INFO";
|
||||
const char *CURRENT_IMAGE_INFO_STRING = "CURRENT_IMAGE_INFO";
|
||||
const char *REBOOT_COUNTER_STRING = "REBOOT_COUNTER";
|
||||
const char *INDIVIDUAL_BOOT_COUNTS_STRING = "INDIVIDUAL_BOOT_COUNTS";
|
||||
const char *NO_VALID_SENSOR_TEMPERATURE_STRING = "NO_VALID_SENSOR_TEMPERATURE";
|
||||
const char *NO_HEALTHY_HEATER_AVAILABLE_STRING = "NO_HEALTHY_HEATER_AVAILABLE";
|
||||
const char *SYRLINKS_OVERHEATING_STRING = "SYRLINKS_OVERHEATING";
|
||||
@ -774,6 +776,10 @@ const char *translateEvents(Event event) {
|
||||
return VERSION_INFO_STRING;
|
||||
case (14006):
|
||||
return CURRENT_IMAGE_INFO_STRING;
|
||||
case (14007):
|
||||
return REBOOT_COUNTER_STRING;
|
||||
case (14008):
|
||||
return INDIVIDUAL_BOOT_COUNTS_STRING;
|
||||
case (14100):
|
||||
return NO_VALID_SENSOR_TEMPERATURE_STRING;
|
||||
case (14101):
|
||||
|
@ -1,8 +1,8 @@
|
||||
/**
|
||||
* @brief Auto-generated object translation file.
|
||||
* @details
|
||||
* Contains 162 translations.
|
||||
* Generated on: 2023-03-02 17:08:11
|
||||
* Contains 164 translations.
|
||||
* Generated on: 2023-03-08 16:44:32
|
||||
*/
|
||||
#include "translateObjects.h"
|
||||
|
||||
@ -150,6 +150,8 @@ const char *TCS_BOARD_ASS_STRING = "TCS_BOARD_ASS";
|
||||
const char *RW_ASSY_STRING = "RW_ASSY";
|
||||
const char *CAM_SWITCHER_STRING = "CAM_SWITCHER";
|
||||
const char *SYRLINKS_ASSY_STRING = "SYRLINKS_ASSY";
|
||||
const char *IMTQ_ASSY_STRING = "IMTQ_ASSY";
|
||||
const char *STR_ASSY_STRING = "STR_ASSY";
|
||||
const char *TM_FUNNEL_STRING = "TM_FUNNEL";
|
||||
const char *PUS_TM_FUNNEL_STRING = "PUS_TM_FUNNEL";
|
||||
const char *CFDP_TM_FUNNEL_STRING = "CFDP_TM_FUNNEL";
|
||||
@ -459,6 +461,10 @@ const char *translateObject(object_id_t object) {
|
||||
return CAM_SWITCHER_STRING;
|
||||
case 0x73000007:
|
||||
return SYRLINKS_ASSY_STRING;
|
||||
case 0x73000008:
|
||||
return IMTQ_ASSY_STRING;
|
||||
case 0x73000009:
|
||||
return STR_ASSY_STRING;
|
||||
case 0x73000100:
|
||||
return TM_FUNNEL_STRING;
|
||||
case 0x73000101:
|
||||
|
@ -18,6 +18,8 @@ enum AcsMode : Mode_t {
|
||||
PTG_INERTIAL = 16,
|
||||
};
|
||||
|
||||
// static constexpr uint8_t ACS_SYSTEM_DETUMBLE_SUBMODE = 1;
|
||||
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::ACS_SUBSYSTEM;
|
||||
//!< The limits for the rotation in safe mode were violated.
|
||||
static const Event SAFE_RATE_VIOLATION = MAKE_EVENT(0, severity::MEDIUM);
|
||||
|
@ -198,9 +198,9 @@ void AcsController::performSafe() {
|
||||
|
||||
updateCtrlValData(errAng);
|
||||
updateActuatorCmdData(cmdDipolMtqs);
|
||||
// commandActuators(cmdDipolMtqs[0], cmdDipolMtqs[1], cmdDipolMtqs[2],
|
||||
// acsParameters.magnetorquesParameter.torqueDuration, 0, 0, 0, 0,
|
||||
// acsParameters.rwHandlingParameters.rampTime);
|
||||
// commandActuators(cmdDipolMtqs[0], cmdDipolMtqs[1], cmdDipolMtqs[2]/*500, 500, 500*/,
|
||||
// acsParameters.magnetorquesParameter.torqueDuration, 0, 0, 0, 0,
|
||||
// acsParameters.rwHandlingParameters.rampTime);
|
||||
}
|
||||
|
||||
void AcsController::performDetumble() {
|
||||
@ -264,8 +264,9 @@ void AcsController::performPointingCtrl() {
|
||||
triggerEvent(acs::MEKF_INVALID_INFO);
|
||||
mekfInvalidFlag = true;
|
||||
}
|
||||
if (mekfInvalidCounter > 4) {
|
||||
triggerEvent(acs::MEKF_INVALID_MODE_VIOLATION);
|
||||
if (mekfInvalidCounter == 5) {
|
||||
// Trigger this so STR FDIR can set the device faulty.
|
||||
EventManagerIF::triggerEvent(objects::STAR_TRACKER, acs::MEKF_INVALID_MODE_VIOLATION, 0, 0);
|
||||
}
|
||||
mekfInvalidCounter++;
|
||||
// commandActuators(0, 0, 0, acsParameters.magnetorquesParameter.torqueDuration,
|
||||
@ -281,7 +282,7 @@ void AcsController::performPointingCtrl() {
|
||||
double rwPseudoInv[4][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
||||
result = guidance.getDistributionMatrixRw(&sensorValues, *rwPseudoInv);
|
||||
if (result == returnvalue::FAILED) {
|
||||
if (multipleRwUnavailableCounter > 4) {
|
||||
if (multipleRwUnavailableCounter == 5) {
|
||||
triggerEvent(acs::MULTIPLE_RW_INVALID);
|
||||
}
|
||||
multipleRwUnavailableCounter++;
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <eive/objects.h>
|
||||
#include <fsfw/controller/ExtendedControllerBase.h>
|
||||
#include <fsfw/globalfunctions/math/VectorOperations.h>
|
||||
#include <fsfw/health/HealthTable.h>
|
||||
#include <fsfw/parameters/ParameterHelper.h>
|
||||
#include <fsfw/parameters/ReceivesParameterMessagesIF.h>
|
||||
#include <fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h>
|
||||
|
@ -540,8 +540,10 @@ ReturnValue_t Guidance::getDistributionMatrixRw(ACS::SensorValues *sensorValues,
|
||||
}
|
||||
|
||||
void Guidance::getTargetParamsSafe(double sunTargetSafe[3], double satRateSafe[3]) {
|
||||
if (not std::filesystem::exists(SD_0_SKEWED_PTG_FILE) or
|
||||
not std::filesystem::exists(SD_1_SKEWED_PTG_FILE)) { // ToDo: if file does not exist anymore
|
||||
std::error_code e;
|
||||
if (not std::filesystem::exists(SD_0_SKEWED_PTG_FILE, e) or
|
||||
not std::filesystem::exists(SD_1_SKEWED_PTG_FILE,
|
||||
e)) { // ToDo: if file does not exist anymore
|
||||
std::memcpy(sunTargetSafe, acsParameters.safeModeControllerParameters.sunTargetDir,
|
||||
3 * sizeof(double));
|
||||
} else {
|
||||
@ -553,15 +555,16 @@ void Guidance::getTargetParamsSafe(double sunTargetSafe[3], double satRateSafe[3
|
||||
}
|
||||
|
||||
ReturnValue_t Guidance::solarArrayDeploymentComplete() {
|
||||
if (std::filesystem::exists(SD_0_SKEWED_PTG_FILE)) {
|
||||
std::error_code e;
|
||||
if (std::filesystem::exists(SD_0_SKEWED_PTG_FILE, e)) {
|
||||
std::remove(SD_0_SKEWED_PTG_FILE);
|
||||
if (std::filesystem::exists(SD_0_SKEWED_PTG_FILE)) {
|
||||
if (std::filesystem::exists(SD_0_SKEWED_PTG_FILE, e)) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
}
|
||||
if (std::filesystem::exists(SD_1_SKEWED_PTG_FILE)) {
|
||||
if (std::filesystem::exists(SD_1_SKEWED_PTG_FILE, e)) {
|
||||
std::remove(SD_1_SKEWED_PTG_FILE);
|
||||
if (std::filesystem::exists(SD_1_SKEWED_PTG_FILE)) {
|
||||
if (std::filesystem::exists(SD_1_SKEWED_PTG_FILE, e)) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ void GyrAdis1650XHandler::doShutDown() {
|
||||
updatePeriodicReply(false, adis1650x::REPLY);
|
||||
internalState = InternalState::NONE;
|
||||
commandExecuted = false;
|
||||
setMode(_MODE_POWER_DOWN);
|
||||
setMode(MODE_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,7 +90,8 @@ void GyrAdis1650XHandler::fillCommandAndReplyMap() {
|
||||
|
||||
ReturnValue_t GyrAdis1650XHandler::scanForReply(const uint8_t *start, size_t remainingSize,
|
||||
DeviceCommandId_t *foundId, size_t *foundLen) {
|
||||
if (breakCountdown.isBusy() or getMode() == _MODE_WAIT_OFF or getMode() == _MODE_WAIT_ON) {
|
||||
if (breakCountdown.isBusy() or getMode() == _MODE_WAIT_OFF or getMode() == _MODE_WAIT_ON or
|
||||
getMode() == _MODE_POWER_DOWN) {
|
||||
return IGNORE_FULL_PACKET;
|
||||
}
|
||||
if (remainingSize != sizeof(acs::Adis1650XReply)) {
|
||||
|
@ -44,7 +44,7 @@ void GyrL3gCustomHandler::doShutDown() {
|
||||
internalState = InternalState::NONE;
|
||||
updatePeriodicReply(false, l3gd20h::REPLY);
|
||||
commandExecuted = false;
|
||||
setMode(_MODE_POWER_DOWN);
|
||||
setMode(MODE_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,7 +100,7 @@ ReturnValue_t GyrL3gCustomHandler::buildCommandFromCommand(DeviceCommandId_t dev
|
||||
|
||||
ReturnValue_t GyrL3gCustomHandler::scanForReply(const uint8_t *start, size_t len,
|
||||
DeviceCommandId_t *foundId, size_t *foundLen) {
|
||||
if (getMode() == _MODE_WAIT_OFF or getMode() == _MODE_WAIT_ON) {
|
||||
if (getMode() == _MODE_WAIT_OFF or getMode() == _MODE_WAIT_ON or getMode() == _MODE_POWER_DOWN) {
|
||||
return IGNORE_FULL_PACKET;
|
||||
}
|
||||
if (len != sizeof(acs::GyroL3gReply)) {
|
||||
|
@ -53,6 +53,13 @@ ImtqHandler::ImtqHandler(object_id_t objectId, object_id_t comIF, CookieIF* comC
|
||||
|
||||
ReturnValue_t ImtqHandler::performOperation(uint8_t opCode) {
|
||||
uint8_t dhbOpCode = DeviceHandlerIF::PERFORM_OPERATION;
|
||||
auto actuateStep = [&]() {
|
||||
if (ignoreActForRestOfComSteps) {
|
||||
requestStep = imtq::RequestType::DO_NOTHING;
|
||||
} else {
|
||||
requestStep = imtq::RequestType::ACTUATE;
|
||||
}
|
||||
};
|
||||
switch (static_cast<imtq::ComStep>(opCode)) {
|
||||
case (imtq::ComStep::DHB_OP): {
|
||||
break;
|
||||
@ -78,22 +85,38 @@ ReturnValue_t ImtqHandler::performOperation(uint8_t opCode) {
|
||||
break;
|
||||
}
|
||||
case (imtq::ComStep::START_ACTUATE_SEND): {
|
||||
requestStep = imtq::RequestType::ACTUATE;
|
||||
if (manualTorqueCmdActive) {
|
||||
if (manuallyCommandedTorqueDuration.isBusy()) {
|
||||
ignoreActForRestOfComSteps = true;
|
||||
requestStep = imtq::RequestType::DO_NOTHING;
|
||||
} else {
|
||||
manualTorqueCmdActive = false;
|
||||
PoolReadGuard pg(&dipoleSet);
|
||||
dipoleSet.dipoles[0] = 0;
|
||||
dipoleSet.dipoles[1] = 0;
|
||||
dipoleSet.dipoles[2] = 0;
|
||||
dipoleSet.currentTorqueDurationMs = 0;
|
||||
requestStep = imtq::RequestType::ACTUATE;
|
||||
ignoreActForRestOfComSteps = false;
|
||||
}
|
||||
} else {
|
||||
requestStep = imtq::RequestType::ACTUATE;
|
||||
}
|
||||
dhbOpCode = DeviceHandlerIF::SEND_WRITE;
|
||||
break;
|
||||
}
|
||||
case (imtq::ComStep::START_ACTUATE_GET): {
|
||||
requestStep = imtq::RequestType::ACTUATE;
|
||||
actuateStep();
|
||||
dhbOpCode = DeviceHandlerIF::GET_WRITE;
|
||||
break;
|
||||
}
|
||||
case (imtq::ComStep::READ_ACTUATE_SEND): {
|
||||
requestStep = imtq::RequestType::ACTUATE;
|
||||
actuateStep();
|
||||
dhbOpCode = DeviceHandlerIF::SEND_READ;
|
||||
break;
|
||||
}
|
||||
case (imtq::ComStep::READ_ACTUATE_GET): {
|
||||
requestStep = imtq::RequestType::ACTUATE;
|
||||
actuateStep();
|
||||
dhbOpCode = DeviceHandlerIF::GET_READ;
|
||||
break;
|
||||
}
|
||||
@ -108,18 +131,37 @@ ReturnValue_t ImtqHandler::performOperation(uint8_t opCode) {
|
||||
ImtqHandler::~ImtqHandler() = default;
|
||||
|
||||
void ImtqHandler::doStartUp() {
|
||||
updatePeriodicReply(true, imtq::cmdIds::REPLY);
|
||||
if (goToNormalMode) {
|
||||
setMode(MODE_NORMAL);
|
||||
} else {
|
||||
setMode(_MODE_TO_ON);
|
||||
if (internalState != InternalState::STARTUP) {
|
||||
commandExecuted = false;
|
||||
updatePeriodicReply(true, imtq::cmdIds::REPLY_NO_TORQUE);
|
||||
updatePeriodicReply(true, imtq::cmdIds::REPLY_WITH_TORQUE);
|
||||
internalState = InternalState::STARTUP;
|
||||
}
|
||||
if (internalState == InternalState::STARTUP) {
|
||||
if (commandExecuted) {
|
||||
if (goToNormalMode) {
|
||||
setMode(MODE_NORMAL);
|
||||
} else {
|
||||
setMode(_MODE_TO_ON);
|
||||
}
|
||||
commandExecuted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImtqHandler::doShutDown() {
|
||||
updatePeriodicReply(false, imtq::cmdIds::REPLY);
|
||||
updatePeriodicReply(false, imtq::cmdIds::REPLY_NO_TORQUE);
|
||||
updatePeriodicReply(false, imtq::cmdIds::REPLY_WITH_TORQUE);
|
||||
specialRequestActive = false;
|
||||
firstReplyCycle = true;
|
||||
internalState = InternalState::NONE;
|
||||
commandExecuted = false;
|
||||
statusSet.setValidity(false, true);
|
||||
rawMtmNoTorque.setValidity(false, true);
|
||||
rawMtmWithTorque.setValidity(false, true);
|
||||
hkDatasetNoTorque.setValidity(false, true);
|
||||
hkDatasetWithTorque.setValidity(false, true);
|
||||
calMtmMeasurementSet.setValidity(false, true);
|
||||
setMode(_MODE_POWER_DOWN);
|
||||
}
|
||||
|
||||
@ -133,11 +175,24 @@ ReturnValue_t ImtqHandler::buildNormalDeviceCommand(DeviceCommandId_t* id) {
|
||||
*id = imtq::cmdIds::START_ACTUATION_DIPOLE;
|
||||
return buildCommandFromCommand(*id, nullptr, 0);
|
||||
}
|
||||
default: {
|
||||
*id = imtq::cmdIds::REQUEST;
|
||||
request.request = imtq::RequestType::DO_NOTHING;
|
||||
request.specialRequest = imtq::SpecialRequest::NONE;
|
||||
expectedReply = DeviceHandlerIF::NO_COMMAND_ID;
|
||||
rawPacket = reinterpret_cast<uint8_t*>(&request);
|
||||
rawPacketLen = sizeof(imtq::Request);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
}
|
||||
return NOTHING_TO_SEND;
|
||||
}
|
||||
|
||||
ReturnValue_t ImtqHandler::buildTransitionDeviceCommand(DeviceCommandId_t* id) {
|
||||
if (internalState == InternalState::STARTUP) {
|
||||
*id = imtq::cmdIds::REQUEST;
|
||||
return buildCommandFromCommand(*id, nullptr, 0);
|
||||
}
|
||||
return NOTHING_TO_SEND;
|
||||
}
|
||||
|
||||
@ -145,11 +200,12 @@ ReturnValue_t ImtqHandler::buildCommandFromCommand(DeviceCommandId_t deviceComma
|
||||
const uint8_t* commandData,
|
||||
size_t commandDataLen) {
|
||||
auto genericSpecialRequest = [&](imtq::SpecialRequest specialRequest) {
|
||||
ImtqRequest request(commandBuffer, sizeof(commandBuffer));
|
||||
request.setMeasureRequest(specialRequest);
|
||||
request.request = imtq::RequestType::MEASURE_NO_ACTUATION;
|
||||
request.specialRequest = specialRequest;
|
||||
expectedReply = imtq::cmdIds::REPLY_NO_TORQUE;
|
||||
specialRequestActive = true;
|
||||
rawPacket = commandBuffer;
|
||||
rawPacketLen = ImtqRequest::REQUEST_LEN;
|
||||
rawPacket = reinterpret_cast<uint8_t*>(&request);
|
||||
rawPacketLen = sizeof(imtq::Request);
|
||||
};
|
||||
switch (deviceCommand) {
|
||||
case (imtq::cmdIds::POS_X_SELF_TEST): {
|
||||
@ -181,45 +237,50 @@ ReturnValue_t ImtqHandler::buildCommandFromCommand(DeviceCommandId_t deviceComma
|
||||
return returnvalue::OK;
|
||||
}
|
||||
case (imtq::cmdIds::REQUEST): {
|
||||
ImtqRequest request(commandBuffer, sizeof(commandBuffer));
|
||||
request.setMeasureRequest(imtq::SpecialRequest::NONE);
|
||||
rawPacket = commandBuffer;
|
||||
rawPacketLen = ImtqRequest::REQUEST_LEN;
|
||||
request.request = imtq::RequestType::MEASURE_NO_ACTUATION;
|
||||
request.specialRequest = imtq::SpecialRequest::NONE;
|
||||
expectedReply = imtq::cmdIds::REPLY_NO_TORQUE;
|
||||
rawPacket = reinterpret_cast<uint8_t*>(&request);
|
||||
rawPacketLen = sizeof(imtq::Request);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
case (imtq::cmdIds::START_ACTUATION_DIPOLE): {
|
||||
/* IMTQ expects low byte first */
|
||||
// commandBuffer[0] = imtq::CC::START_ACTUATION_DIPOLE;
|
||||
if (commandData != nullptr && commandDataLen < 8) {
|
||||
return DeviceHandlerIF::INVALID_COMMAND_PARAMETER;
|
||||
}
|
||||
ImtqRequest request(commandBuffer, sizeof(commandBuffer));
|
||||
// Commands override anything which was set in the software
|
||||
if (commandData != nullptr) {
|
||||
// Read set dipole values from local pool
|
||||
{
|
||||
// Do this in any case to read values which might be commanded by the ACS controller.
|
||||
PoolReadGuard pg(&dipoleSet);
|
||||
|
||||
int16_t xDipole = 0, yDipole = 0, zDipole = 0;
|
||||
uint16_t torqueDuration = 0;
|
||||
dipoleSet.xDipole = xDipole;
|
||||
dipoleSet.yDipole = yDipole;
|
||||
dipoleSet.zDipole = zDipole;
|
||||
dipoleSet.currentTorqueDurationMs = torqueDuration;
|
||||
// Commands override anything which was set in the software
|
||||
if (commandData != nullptr) {
|
||||
dipoleSet.setValidityBufferGeneration(false);
|
||||
ReturnValue_t result = dipoleSet.deSerialize(&commandData, &commandDataLen,
|
||||
SerializeIF::Endianness::NETWORK);
|
||||
dipoleSet.setValidityBufferGeneration(true);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
manualTorqueCmdActive = true;
|
||||
manuallyCommandedTorqueDuration.setTimeout(dipoleSet.currentTorqueDurationMs.value);
|
||||
}
|
||||
}
|
||||
|
||||
request.setActuateRequest(dipoleSet.xDipole.value, dipoleSet.yDipole.value,
|
||||
dipoleSet.zDipole.value, dipoleSet.currentTorqueDurationMs.value);
|
||||
expectedReply = imtq::cmdIds::REPLY_WITH_TORQUE;
|
||||
request.request = imtq::RequestType::ACTUATE;
|
||||
request.specialRequest = imtq::SpecialRequest::NONE;
|
||||
std::memcpy(request.dipoles, dipoleSet.dipoles.value, sizeof(request.dipoles));
|
||||
request.torqueDuration = dipoleSet.currentTorqueDurationMs.value;
|
||||
if (ACTUATION_WIRETAPPING) {
|
||||
sif::debug << "Actuating IMTQ with parameters x = " << dipoleSet.xDipole.value
|
||||
<< ", y = " << dipoleSet.yDipole.value << ", z = " << dipoleSet.zDipole.value
|
||||
sif::debug << "Actuating IMTQ with parameters x = " << dipoleSet.dipoles[0]
|
||||
<< ", y = " << dipoleSet.dipoles[1] << ", z = " << dipoleSet.dipoles[2]
|
||||
<< ", duration = " << dipoleSet.currentTorqueDurationMs.value << std::endl;
|
||||
}
|
||||
MutexGuard mg(torquer::lazyLock(), torquer::LOCK_TYPE, torquer::LOCK_TIMEOUT,
|
||||
torquer::LOCK_CTX);
|
||||
torquer::TORQUEING = true;
|
||||
torquer::TORQUE_COUNTDOWN.setTimeout(dipoleSet.currentTorqueDurationMs.value);
|
||||
rawPacket = commandBuffer;
|
||||
rawPacketLen = ImtqRequest::REQUEST_LEN;
|
||||
rawPacket = reinterpret_cast<uint8_t*>(&request);
|
||||
rawPacketLen = sizeof(imtq::Request);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
default:
|
||||
@ -231,7 +292,8 @@ ReturnValue_t ImtqHandler::buildCommandFromCommand(DeviceCommandId_t deviceComma
|
||||
void ImtqHandler::fillCommandAndReplyMap() {
|
||||
insertInCommandMap(imtq::cmdIds::REQUEST);
|
||||
insertInCommandMap(imtq::cmdIds::START_ACTUATION_DIPOLE);
|
||||
insertInReplyMap(imtq::cmdIds::REPLY, 5, nullptr, 0, true);
|
||||
insertInReplyMap(imtq::cmdIds::REPLY_NO_TORQUE, 5, nullptr, 0, true);
|
||||
insertInReplyMap(imtq::cmdIds::REPLY_WITH_TORQUE, 20, nullptr, 0, true);
|
||||
insertInCommandMap(imtq::cmdIds::POS_X_SELF_TEST);
|
||||
insertInCommandMap(imtq::cmdIds::NEG_X_SELF_TEST);
|
||||
insertInCommandMap(imtq::cmdIds::POS_Y_SELF_TEST);
|
||||
@ -243,12 +305,12 @@ void ImtqHandler::fillCommandAndReplyMap() {
|
||||
|
||||
ReturnValue_t ImtqHandler::scanForReply(const uint8_t* start, size_t remainingSize,
|
||||
DeviceCommandId_t* foundId, size_t* foundLen) {
|
||||
if (getMode() == _MODE_WAIT_OFF or getMode() == _MODE_WAIT_ON) {
|
||||
if (getMode() == _MODE_WAIT_OFF or getMode() == _MODE_WAIT_ON or getMode() == _MODE_POWER_DOWN) {
|
||||
return IGNORE_FULL_PACKET;
|
||||
}
|
||||
if (remainingSize > 0) {
|
||||
*foundLen = remainingSize;
|
||||
*foundId = imtq::cmdIds::REPLY;
|
||||
*foundId = expectedReply;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
return returnvalue::FAILED;
|
||||
@ -258,14 +320,20 @@ ReturnValue_t ImtqHandler::interpretDeviceReply(DeviceCommandId_t id, const uint
|
||||
ReturnValue_t result;
|
||||
ReturnValue_t status = returnvalue::OK;
|
||||
if (getMode() != MODE_NORMAL) {
|
||||
// Ignore replies during transitions.
|
||||
if (expectedReply == imtq::cmdIds::REPLY_NO_TORQUE) {
|
||||
ImtqRepliesDefault replies(packet);
|
||||
if (replies.devWasConfigured() and internalState == InternalState::STARTUP) {
|
||||
commandExecuted = true;
|
||||
}
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
// arrayprinter::print(packet, ImtqReplies::BASE_LEN);
|
||||
if (requestStep == imtq::RequestType::MEASURE_NO_ACTUATION) {
|
||||
requestStep = imtq::RequestType::ACTUATE;
|
||||
if (expectedReply == imtq::cmdIds::REPLY_NO_TORQUE) {
|
||||
// sif::debug << "handle measure" << std::endl;
|
||||
ImtqRepliesDefault replies(packet);
|
||||
if (replies.devWasConfigured() and internalState == InternalState::STARTUP) {
|
||||
commandExecuted = true;
|
||||
}
|
||||
if (specialRequestActive) {
|
||||
if (replies.wasSpecialRequestRead()) {
|
||||
uint8_t* specialRequest = replies.getSpecialRequest();
|
||||
@ -308,7 +376,7 @@ ReturnValue_t ImtqHandler::interpretDeviceReply(DeviceCommandId_t id, const uint
|
||||
}
|
||||
|
||||
if (not replies.wasGetRawMgmMeasurementRead() and not firstReplyCycle) {
|
||||
sif::warning << "IMTQ: Possible timing issue, system state was not read" << std::endl;
|
||||
sif::warning << "IMTQ: Possible timing issue, raw MGM measurement was not read" << std::endl;
|
||||
}
|
||||
uint8_t* rawMgmMeasurement = replies.getRawMgmMeasurement();
|
||||
result = parseStatusByte(imtq::CC::GET_RAW_MTM_MEASUREMENT, rawMgmMeasurement);
|
||||
@ -319,7 +387,8 @@ ReturnValue_t ImtqHandler::interpretDeviceReply(DeviceCommandId_t id, const uint
|
||||
}
|
||||
|
||||
if (not replies.wasCalibMgmMeasurementRead() and not firstReplyCycle) {
|
||||
sif::warning << "IMTQ: Possible timing issue, system state was not read" << std::endl;
|
||||
sif::warning << "IMTQ: Possible timing issue, calib MGM measurement was not read"
|
||||
<< std::endl;
|
||||
}
|
||||
uint8_t* calibMgmMeasurement = replies.getCalibMgmMeasurement();
|
||||
result = parseStatusByte(imtq::CC::GET_CAL_MTM_MEASUREMENT, calibMgmMeasurement);
|
||||
@ -328,9 +397,8 @@ ReturnValue_t ImtqHandler::interpretDeviceReply(DeviceCommandId_t id, const uint
|
||||
} else {
|
||||
status = result;
|
||||
}
|
||||
} else {
|
||||
} else if (expectedReply == imtq::cmdIds::REPLY_WITH_TORQUE) {
|
||||
// sif::debug << "handle measure with torque" << std::endl;
|
||||
requestStep = imtq::RequestType::MEASURE_NO_ACTUATION;
|
||||
ImtqRepliesWithTorque replies(packet);
|
||||
if (replies.wasDipoleActuationRead()) {
|
||||
parseStatusByte(imtq::CC::START_ACTUATION_DIPOLE, replies.getDipoleActuation());
|
||||
@ -375,6 +443,8 @@ LocalPoolDataSetBase* ImtqHandler::getDataSetHandle(sid_t sid) {
|
||||
return &hkDatasetNoTorque;
|
||||
} else if (sid == dipoleSet.getSid()) {
|
||||
return &dipoleSet;
|
||||
} else if (sid == statusSet.getSid()) {
|
||||
return &statusSet;
|
||||
} else if (sid == hkDatasetWithTorque.getSid()) {
|
||||
return &hkDatasetWithTorque;
|
||||
} else if (sid == rawMtmWithTorque.getSid()) {
|
||||
@ -410,21 +480,26 @@ ReturnValue_t ImtqHandler::initializeLocalDataPool(localpool::DataPool& localDat
|
||||
localDataPoolMap.emplace(imtq::STATUS_BYTE_CONF, &statusConfig);
|
||||
localDataPoolMap.emplace(imtq::STATUS_BYTE_ERROR, &statusError);
|
||||
localDataPoolMap.emplace(imtq::STATUS_BYTE_UPTIME, &statusUptime);
|
||||
|
||||
// ENG HK No Torque
|
||||
localDataPoolMap.emplace(imtq::DIGITAL_VOLTAGE_MV, new PoolEntry<uint16_t>({0}));
|
||||
localDataPoolMap.emplace(imtq::ANALOG_VOLTAGE_MV, new PoolEntry<uint16_t>({0}));
|
||||
localDataPoolMap.emplace(imtq::DIGITAL_CURRENT, new PoolEntry<float>({0}));
|
||||
localDataPoolMap.emplace(imtq::ANALOG_CURRENT, new PoolEntry<float>({0}));
|
||||
localDataPoolMap.emplace(imtq::COIL_X_CURRENT, new PoolEntry<float>({0}));
|
||||
localDataPoolMap.emplace(imtq::COIL_Y_CURRENT, new PoolEntry<float>({0}));
|
||||
localDataPoolMap.emplace(imtq::COIL_Z_CURRENT, new PoolEntry<float>({0}));
|
||||
localDataPoolMap.emplace(imtq::COIL_X_TEMPERATURE, new PoolEntry<int16_t>({0}));
|
||||
localDataPoolMap.emplace(imtq::COIL_Y_TEMPERATURE, new PoolEntry<int16_t>({0}));
|
||||
localDataPoolMap.emplace(imtq::COIL_Z_TEMPERATURE, new PoolEntry<int16_t>({0}));
|
||||
localDataPoolMap.emplace(imtq::COIL_CURRENTS, &coilCurrentsMilliampsNoTorque);
|
||||
localDataPoolMap.emplace(imtq::COIL_TEMPERATURES, &coilTempsNoTorque);
|
||||
localDataPoolMap.emplace(imtq::MCU_TEMPERATURE, new PoolEntry<int16_t>({0}));
|
||||
|
||||
localDataPoolMap.emplace(imtq::DIPOLES_X, &dipoleXEntry);
|
||||
localDataPoolMap.emplace(imtq::DIPOLES_Y, &dipoleYEntry);
|
||||
localDataPoolMap.emplace(imtq::DIPOLES_Z, &dipoleZEntry);
|
||||
// ENG HK With Torque
|
||||
localDataPoolMap.emplace(imtq::DIGITAL_VOLTAGE_MV_WT, new PoolEntry<uint16_t>({0}));
|
||||
localDataPoolMap.emplace(imtq::ANALOG_VOLTAGE_MV_WT, new PoolEntry<uint16_t>({0}));
|
||||
localDataPoolMap.emplace(imtq::DIGITAL_CURRENT_WT, new PoolEntry<float>({0}));
|
||||
localDataPoolMap.emplace(imtq::ANALOG_CURRENT_WT, new PoolEntry<float>({0}));
|
||||
localDataPoolMap.emplace(imtq::COIL_CURRENTS_WT, &coilCurrentsMilliampsWithTorque);
|
||||
localDataPoolMap.emplace(imtq::COIL_TEMPERATURES_WT, &coilTempsWithTorque);
|
||||
localDataPoolMap.emplace(imtq::MCU_TEMPERATURE_WT, new PoolEntry<int16_t>({0}));
|
||||
|
||||
localDataPoolMap.emplace(imtq::DIPOLES_ID, &dipolesPoolEntry);
|
||||
localDataPoolMap.emplace(imtq::CURRENT_TORQUE_DURATION, &torqueDurationEntry);
|
||||
|
||||
/** Entries of calibrated MTM measurement dataset */
|
||||
@ -432,8 +507,11 @@ ReturnValue_t ImtqHandler::initializeLocalDataPool(localpool::DataPool& localDat
|
||||
localDataPoolMap.emplace(imtq::ACTUATION_CAL_STATUS, new PoolEntry<uint8_t>({0}));
|
||||
|
||||
/** Entries of raw MTM measurement dataset */
|
||||
localDataPoolMap.emplace(imtq::MTM_RAW, new PoolEntry<float>(3));
|
||||
localDataPoolMap.emplace(imtq::ACTUATION_RAW_STATUS, new PoolEntry<uint8_t>({0}));
|
||||
localDataPoolMap.emplace(imtq::MTM_RAW, &mtmRawNoTorque);
|
||||
localDataPoolMap.emplace(imtq::ACTUATION_RAW_STATUS, &actStatusNoTorque);
|
||||
|
||||
localDataPoolMap.emplace(imtq::MTM_RAW_WT, &mtmRawWithTorque);
|
||||
localDataPoolMap.emplace(imtq::ACTUATION_RAW_STATUS_WT, &actStatusWithTorque);
|
||||
|
||||
/** INIT measurements for positive X axis test */
|
||||
localDataPoolMap.emplace(imtq::INIT_POS_X_ERR, new PoolEntry<uint8_t>({0}));
|
||||
@ -709,6 +787,10 @@ ReturnValue_t ImtqHandler::initializeLocalDataPool(localpool::DataPool& localDat
|
||||
subdp::DiagnosticsHkPeriodicParams(rawMtmWithTorque.getSid(), false, 10.0));
|
||||
poolManager.subscribeForDiagPeriodicPacket(
|
||||
subdp::DiagnosticsHkPeriodicParams(calMtmMeasurementSet.getSid(), false, 10.0));
|
||||
poolManager.subscribeForRegularPeriodicPacket(
|
||||
subdp::RegularHkPeriodicParams(statusSet.getSid(), false, 10.0));
|
||||
poolManager.subscribeForDiagPeriodicPacket(
|
||||
subdp::DiagnosticsHkPeriodicParams(dipoleSet.getSid(), false, 10.0));
|
||||
return DeviceHandlerBase::initializeLocalDataPool(localDataPoolMap, poolManager);
|
||||
}
|
||||
|
||||
@ -732,7 +814,7 @@ ReturnValue_t ImtqHandler::getSelfTestCommandId(DeviceCommandId_t* id) {
|
||||
}
|
||||
|
||||
ReturnValue_t ImtqHandler::parseStatusByte(imtq::CC::CC command, const uint8_t* packet) {
|
||||
uint8_t cmdErrorField = *(packet + 1) & 0xF;
|
||||
uint8_t cmdErrorField = packet[1] & 0xF;
|
||||
if (cmdErrorField == 0) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
@ -755,16 +837,20 @@ ReturnValue_t ImtqHandler::parseStatusByte(imtq::CC::CC command, const uint8_t*
|
||||
<< " has invalid parameter" << std::endl;
|
||||
return imtq::PARAMETER_INVALID;
|
||||
case 5:
|
||||
sif::error << "IMTQ::parseStatusByte: CC 0x" << std::setw(2) << " unavailable" << std::endl;
|
||||
sif::error << "IMTQ::parseStatusByte: CC 0x" << std::setw(2) << command << " unavailable"
|
||||
<< std::endl;
|
||||
return imtq::CC_UNAVAILABLE;
|
||||
case 7:
|
||||
sif::error << "IMTQ::parseStatusByte: IMTQ replied internal processing error" << std::endl;
|
||||
sif::error << "IMTQ::parseStatusByte: Internal processing error for command 0x"
|
||||
<< std::setw(2) << command << std::endl;
|
||||
return imtq::INTERNAL_PROCESSING_ERROR;
|
||||
default:
|
||||
sif::error << "IMTQ::parseStatusByte: CMD Error field contains unknown error code 0x"
|
||||
<< static_cast<int>(cmdErrorField) << std::endl;
|
||||
sif::error << "IMTQ::parseStatusByte: CMD error field for command 0x" << std::setw(2)
|
||||
<< command << " contains unknown error code 0x" << static_cast<int>(cmdErrorField)
|
||||
<< std::endl;
|
||||
return imtq::CMD_ERR_UNKNOWN;
|
||||
}
|
||||
sif::error << std::dec;
|
||||
}
|
||||
|
||||
void ImtqHandler::fillEngHkDataset(imtq::HkDataset& hkDataset, const uint8_t* packet) {
|
||||
@ -778,20 +864,20 @@ void ImtqHandler::fillEngHkDataset(imtq::HkDataset& hkDataset, const uint8_t* pa
|
||||
offset += 2;
|
||||
hkDataset.analogCurrentmA = (*(packet + offset + 1) << 8 | *(packet + offset)) * 0.1;
|
||||
offset += 2;
|
||||
hkDataset.coilXCurrentmA =
|
||||
hkDataset.coilCurrentsMilliamps[0] =
|
||||
static_cast<int16_t>(*(packet + offset + 1) << 8 | *(packet + offset)) * 0.1;
|
||||
offset += 2;
|
||||
hkDataset.coilYCurrentmA =
|
||||
hkDataset.coilCurrentsMilliamps[1] =
|
||||
static_cast<int16_t>(*(packet + offset + 1) << 8 | *(packet + offset)) * 0.1;
|
||||
offset += 2;
|
||||
hkDataset.coilZCurrentmA =
|
||||
hkDataset.coilCurrentsMilliamps[2] =
|
||||
static_cast<int16_t>(*(packet + offset + 1) << 8 | *(packet + offset)) * 0.1;
|
||||
offset += 2;
|
||||
hkDataset.coilXTemperature = (*(packet + offset + 1) << 8 | *(packet + offset));
|
||||
hkDataset.coilTemperatures[0] = (*(packet + offset + 1) << 8 | *(packet + offset));
|
||||
offset += 2;
|
||||
hkDataset.coilYTemperature = (*(packet + offset + 1) << 8 | *(packet + offset));
|
||||
hkDataset.coilTemperatures[1] = (*(packet + offset + 1) << 8 | *(packet + offset));
|
||||
offset += 2;
|
||||
hkDataset.coilZTemperature = (*(packet + offset + 1) << 8 | *(packet + offset));
|
||||
hkDataset.coilTemperatures[2] = (*(packet + offset + 1) << 8 | *(packet + offset));
|
||||
offset += 2;
|
||||
size_t dummy = 2;
|
||||
SerializeAdapter::deSerialize(&hkDataset.mcuTemperature.value, packet + offset, &dummy,
|
||||
@ -805,12 +891,15 @@ void ImtqHandler::fillEngHkDataset(imtq::HkDataset& hkDataset, const uint8_t* pa
|
||||
sif::info << "IMTQ analog voltage: " << hkDataset.analogVoltageMv << " mV" << std::endl;
|
||||
sif::info << "IMTQ digital current: " << hkDataset.digitalCurrentmA << " mA" << std::endl;
|
||||
sif::info << "IMTQ analog current: " << hkDataset.analogCurrentmA << " mA" << std::endl;
|
||||
sif::info << "IMTQ coil X current: " << hkDataset.coilXCurrentmA << " mA" << std::endl;
|
||||
sif::info << "IMTQ coil Y current: " << hkDataset.coilYCurrentmA << " mA" << std::endl;
|
||||
sif::info << "IMTQ coil Z current: " << hkDataset.coilZCurrentmA << " mA" << std::endl;
|
||||
sif::info << "IMTQ coil X temperature: " << hkDataset.coilXTemperature << " °C" << std::endl;
|
||||
sif::info << "IMTQ coil Y temperature: " << hkDataset.coilYTemperature << " °C" << std::endl;
|
||||
sif::info << "IMTQ coil Z temperature: " << hkDataset.coilZTemperature << " °C" << std::endl;
|
||||
sif::info << "IMTQ coil X current: " << hkDataset.coilCurrentsMilliamps[0] << " mA"
|
||||
<< std::endl;
|
||||
sif::info << "IMTQ coil Y current: " << hkDataset.coilCurrentsMilliamps[1] << " mA"
|
||||
<< std::endl;
|
||||
sif::info << "IMTQ coil Z current: " << hkDataset.coilCurrentsMilliamps[2] << " mA"
|
||||
<< std::endl;
|
||||
sif::info << "IMTQ coil X temperature: " << hkDataset.coilTemperatures[0] << " °C" << std::endl;
|
||||
sif::info << "IMTQ coil Y temperature: " << hkDataset.coilTemperatures[1] << " °C" << std::endl;
|
||||
sif::info << "IMTQ coil Z temperature: " << hkDataset.coilTemperatures[2] << " °C" << std::endl;
|
||||
sif::info << "IMTQ coil MCU temperature: " << hkDataset.mcuTemperature << " °C" << std::endl;
|
||||
#endif
|
||||
}
|
||||
@ -851,7 +940,7 @@ void ImtqHandler::fillCalibratedMtmDataset(const uint8_t* packet) {
|
||||
void ImtqHandler::fillRawMtmDataset(imtq::RawMtmMeasurementSet& set, const uint8_t* packet) {
|
||||
PoolReadGuard rg(&set);
|
||||
if (rg.getReadResult() != returnvalue::OK) {
|
||||
sif::error << "ImtqHandler::fillRawMtmDataset: Lock failure" << std::endl;
|
||||
sif::error << "ImtqHandler::fillRawMtmDataset: Read failure" << std::endl;
|
||||
}
|
||||
unsigned int offset = 2;
|
||||
size_t deSerLen = 16;
|
||||
@ -887,6 +976,7 @@ void ImtqHandler::fillRawMtmDataset(imtq::RawMtmMeasurementSet& set, const uint8
|
||||
set.setValidity(true, true);
|
||||
if (debugMode) {
|
||||
#if OBSW_VERBOSE_LEVEL >= 1
|
||||
sif::info << "Set ID: " << set.getSid().ownerSetId << std::endl;
|
||||
sif::info << "IMTQ raw MTM measurement X: " << set.mtmRawNt[0] << " nT" << std::endl;
|
||||
sif::info << "IMTQ raw MTM measurement Y: " << set.mtmRawNt[1] << " nT" << std::endl;
|
||||
sif::info << "IMTQ raw MTM measurement Z: " << set.mtmRawNt[2] << " nT" << std::endl;
|
||||
|
@ -83,6 +83,11 @@ class ImtqHandler : public DeviceHandlerBase {
|
||||
//! link between IMTQ and OBC.
|
||||
static const Event INVALID_ERROR_BYTE = MAKE_EVENT(8, severity::LOW);
|
||||
|
||||
enum class InternalState { NONE, STARTUP, SHUTDOWN } internalState = InternalState::NONE;
|
||||
bool commandExecuted = false;
|
||||
|
||||
imtq::Request request{};
|
||||
|
||||
imtq::StatusDataset statusSet;
|
||||
imtq::DipoleActuationSet dipoleSet;
|
||||
imtq::RawMtmMeasurementNoTorque rawMtmNoTorque;
|
||||
@ -98,6 +103,9 @@ class ImtqHandler : public DeviceHandlerBase {
|
||||
imtq::NegYSelfTestSet negYselfTestDataset;
|
||||
imtq::PosZSelfTestSet posZselfTestDataset;
|
||||
imtq::NegZSelfTestSet negZselfTestDataset;
|
||||
bool manualTorqueCmdActive = false;
|
||||
bool ignoreActForRestOfComSteps = false;
|
||||
Countdown manuallyCommandedTorqueDuration = Countdown();
|
||||
|
||||
NormalPollingMode pollingMode = NormalPollingMode::UNCALIBRATED;
|
||||
|
||||
@ -107,13 +115,20 @@ class ImtqHandler : public DeviceHandlerBase {
|
||||
PoolEntry<uint32_t> statusUptime = PoolEntry<uint32_t>({0});
|
||||
|
||||
PoolEntry<int32_t> mgmCalEntry = PoolEntry<int32_t>(3);
|
||||
PoolEntry<int16_t> dipoleXEntry = PoolEntry<int16_t>(0, false);
|
||||
PoolEntry<int16_t> dipoleYEntry = PoolEntry<int16_t>(0, false);
|
||||
PoolEntry<int16_t> dipoleZEntry = PoolEntry<int16_t>(0, false);
|
||||
PoolEntry<uint16_t> torqueDurationEntry = PoolEntry<uint16_t>(0, false);
|
||||
PoolEntry<int16_t> dipolesPoolEntry = PoolEntry<int16_t>({0, 0, 0}, false);
|
||||
PoolEntry<uint16_t> torqueDurationEntry = PoolEntry<uint16_t>({0}, false);
|
||||
PoolEntry<float> coilCurrentsMilliampsNoTorque = PoolEntry<float>(3);
|
||||
PoolEntry<float> coilCurrentsMilliampsWithTorque = PoolEntry<float>(3);
|
||||
PoolEntry<int16_t> coilTempsNoTorque = PoolEntry<int16_t>(3);
|
||||
PoolEntry<int16_t> coilTempsWithTorque = PoolEntry<int16_t>(3);
|
||||
PoolEntry<float> mtmRawNoTorque = PoolEntry<float>(3);
|
||||
PoolEntry<uint8_t> actStatusNoTorque = PoolEntry<uint8_t>(1);
|
||||
PoolEntry<float> mtmRawWithTorque = PoolEntry<float>(3);
|
||||
PoolEntry<uint8_t> actStatusWithTorque = PoolEntry<uint8_t>(1);
|
||||
|
||||
power::Switch_t switcher = power::NO_SWITCH;
|
||||
|
||||
uint8_t commandBuffer[imtq::MAX_COMMAND_SIZE];
|
||||
DeviceCommandId_t expectedReply = DeviceHandlerIF::NO_COMMAND_ID;
|
||||
bool goToNormalMode = false;
|
||||
bool debugMode = false;
|
||||
bool specialRequestActive = false;
|
||||
|
@ -37,7 +37,7 @@ void MgmLis3CustomHandler::doShutDown() {
|
||||
updatePeriodicReply(false, REPLY);
|
||||
commandExecuted = false;
|
||||
internalState = InternalState::NONE;
|
||||
setMode(_MODE_POWER_DOWN);
|
||||
setMode(MODE_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ void MgmRm3100CustomHandler::doShutDown() {
|
||||
}
|
||||
if (internalState == InternalState::SHUTDOWN and commandExecuted) {
|
||||
updatePeriodicReply(false, REPLY);
|
||||
setMode(_MODE_POWER_DOWN);
|
||||
setMode(MODE_OFF);
|
||||
commandExecuted = false;
|
||||
}
|
||||
}
|
||||
|
@ -366,9 +366,8 @@ void RwHandler::handleGetRwStatusReply(const uint8_t* packet) {
|
||||
statusSet.setValidity(true, true);
|
||||
|
||||
if (statusSet.state == rws::STATE_ERROR) {
|
||||
// This requires the commanding of the init reaction wheel controller command to recover
|
||||
// from error state which must be handled by the FDIR instance.
|
||||
triggerEvent(rws::ERROR_STATE, statusSet.state.value, 0);
|
||||
// Trigger FDIR reaction, first recovery, then faulty if it doesnt fix the issue.
|
||||
triggerEvent(DeviceHandlerIF::DEVICE_WANTS_HARD_REBOOT, statusSet.state.value, 0);
|
||||
sif::error << "RwHandler::handleGetRwStatusReply: Reaction wheel in error state" << std::endl;
|
||||
}
|
||||
|
||||
|
@ -319,11 +319,14 @@ 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);
|
||||
|
||||
bool fileExists = std::filesystem::exists(fullFilePath, e);
|
||||
if (not fileExists) {
|
||||
std::filesystem::create_directory(fullFilePath);
|
||||
bool created = std::filesystem::create_directory(fullFilePath, e);
|
||||
if (not created) {
|
||||
sif::error << "Could not create SCEX directory: " << e << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint32_t remainingMillis = finishCountdown.getRemainingMillis();
|
||||
|
@ -43,15 +43,16 @@ ReturnValue_t SolarArrayDeploymentHandler::performOperation(uint8_t operationCod
|
||||
#endif
|
||||
if (opDivider.checkAndIncrement()) {
|
||||
auto activeSdc = sdcMan.getActiveSdCard();
|
||||
std::error_code e;
|
||||
if (activeSdc and activeSdc.value() == sd::SdCard::SLOT_0 and
|
||||
sdcMan.isSdCardUsable(activeSdc.value())) {
|
||||
if (exists(SD_0_DEPL_FILE)) {
|
||||
if (exists(SD_0_DEPL_FILE, e)) {
|
||||
// perform autonomous deployment handling
|
||||
performAutonomousDepl(sd::SdCard::SLOT_0, dryRunStringInFile(SD_0_DEPL_FILE));
|
||||
}
|
||||
} else if (activeSdc and activeSdc.value() == sd::SdCard::SLOT_1 and
|
||||
sdcMan.isSdCardUsable(activeSdc.value())) {
|
||||
if (exists(SD_1_DEPL_FILE)) {
|
||||
if (exists(SD_1_DEPL_FILE, e)) {
|
||||
// perform autonomous deployment handling
|
||||
performAutonomousDepl(sd::SdCard::SLOT_1, dryRunStringInFile(SD_1_DEPL_FILE));
|
||||
}
|
||||
@ -137,15 +138,16 @@ ReturnValue_t SolarArrayDeploymentHandler::performAutonomousDepl(sd::SdCard sdCa
|
||||
of << "phase: init\n";
|
||||
of << "secs_since_start: 0\n";
|
||||
};
|
||||
std::error_code e;
|
||||
if (sdCard == sd::SdCard::SLOT_0) {
|
||||
if (not exists(SD_0_DEPLY_INFO)) {
|
||||
if (not exists(SD_0_DEPLY_INFO, e)) {
|
||||
initFile(SD_0_DEPLY_INFO);
|
||||
}
|
||||
if (not autonomousDeplForFile(sd::SdCard::SLOT_0, SD_0_DEPLY_INFO, dryRun)) {
|
||||
initFile(SD_0_DEPLY_INFO);
|
||||
}
|
||||
} else if (sdCard == sd::SdCard::SLOT_1) {
|
||||
if (not exists(SD_1_DEPLY_INFO)) {
|
||||
if (not exists(SD_1_DEPLY_INFO, e)) {
|
||||
initFile(SD_1_DEPLY_INFO);
|
||||
}
|
||||
if (not autonomousDeplForFile(sd::SdCard::SLOT_1, SD_1_DEPLY_INFO, dryRun)) {
|
||||
|
@ -10,19 +10,7 @@ class ImtqHandler;
|
||||
|
||||
namespace imtq {
|
||||
|
||||
enum ComStep : uint8_t {
|
||||
DHB_OP = 0,
|
||||
START_MEASURE_SEND = 1,
|
||||
START_MEASURE_GET = 2,
|
||||
READ_MEASURE_SEND = 3,
|
||||
READ_MEASURE_GET = 4,
|
||||
START_ACTUATE_SEND = 5,
|
||||
START_ACTUATE_GET = 6,
|
||||
READ_ACTUATE_SEND = 7,
|
||||
READ_ACTUATE_GET = 8,
|
||||
};
|
||||
|
||||
enum class RequestType : uint8_t { MEASURE_NO_ACTUATION, ACTUATE };
|
||||
enum class RequestType : uint8_t { MEASURE_NO_ACTUATION, ACTUATE, DO_NOTHING };
|
||||
|
||||
enum class SpecialRequest : uint8_t {
|
||||
NONE = 0,
|
||||
@ -35,6 +23,26 @@ enum class SpecialRequest : uint8_t {
|
||||
GET_SELF_TEST_RESULT = 7
|
||||
};
|
||||
|
||||
struct Request {
|
||||
imtq::RequestType request = imtq::RequestType::MEASURE_NO_ACTUATION;
|
||||
imtq::SpecialRequest specialRequest = imtq::SpecialRequest::NONE;
|
||||
uint8_t integrationTimeSel = 3;
|
||||
int16_t dipoles[3]{};
|
||||
uint16_t torqueDuration = 0;
|
||||
};
|
||||
|
||||
enum ComStep : uint8_t {
|
||||
DHB_OP = 0,
|
||||
START_MEASURE_SEND = 1,
|
||||
START_MEASURE_GET = 2,
|
||||
READ_MEASURE_SEND = 3,
|
||||
READ_MEASURE_GET = 4,
|
||||
START_ACTUATE_SEND = 5,
|
||||
START_ACTUATE_GET = 6,
|
||||
READ_ACTUATE_SEND = 7,
|
||||
READ_ACTUATE_GET = 8,
|
||||
};
|
||||
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::IMTQ_HANDLER;
|
||||
|
||||
static constexpr ReturnValue_t INVALID_COMMAND_CODE = MAKE_RETURN_CODE(0);
|
||||
@ -53,7 +61,8 @@ static const ReturnValue_t UNEXPECTED_SELF_TEST_REPLY = MAKE_RETURN_CODE(0xA7);
|
||||
namespace cmdIds {
|
||||
|
||||
static constexpr DeviceCommandId_t REQUEST = 0x70;
|
||||
static constexpr DeviceCommandId_t REPLY = 0x71;
|
||||
static constexpr DeviceCommandId_t REPLY_NO_TORQUE = 0x71;
|
||||
static constexpr DeviceCommandId_t REPLY_WITH_TORQUE = 0x72;
|
||||
static const DeviceCommandId_t START_ACTUATION_DIPOLE = 0x2;
|
||||
static const DeviceCommandId_t POS_X_SELF_TEST = 0x7;
|
||||
static const DeviceCommandId_t NEG_X_SELF_TEST = 0x8;
|
||||
@ -195,20 +204,28 @@ enum PoolIds : lp_id_t {
|
||||
ANALOG_VOLTAGE_MV,
|
||||
DIGITAL_CURRENT,
|
||||
ANALOG_CURRENT,
|
||||
COIL_X_CURRENT,
|
||||
COIL_Y_CURRENT,
|
||||
COIL_Z_CURRENT,
|
||||
COIL_X_TEMPERATURE,
|
||||
COIL_Y_TEMPERATURE,
|
||||
COIL_Z_TEMPERATURE,
|
||||
COIL_CURRENTS,
|
||||
COIL_TEMPERATURES,
|
||||
MCU_TEMPERATURE,
|
||||
|
||||
DIGITAL_VOLTAGE_MV_WT,
|
||||
ANALOG_VOLTAGE_MV_WT,
|
||||
DIGITAL_CURRENT_WT,
|
||||
ANALOG_CURRENT_WT,
|
||||
COIL_CURRENTS_WT,
|
||||
COIL_TEMPERATURES_WT,
|
||||
MCU_TEMPERATURE_WT,
|
||||
|
||||
MGM_CAL_NT,
|
||||
ACTUATION_CAL_STATUS,
|
||||
|
||||
MTM_RAW,
|
||||
ACTUATION_RAW_STATUS,
|
||||
DIPOLES_X,
|
||||
DIPOLES_Y,
|
||||
DIPOLES_Z,
|
||||
|
||||
MTM_RAW_WT,
|
||||
ACTUATION_RAW_STATUS_WT,
|
||||
|
||||
DIPOLES_ID,
|
||||
CURRENT_TORQUE_DURATION,
|
||||
|
||||
INIT_POS_X_ERR,
|
||||
@ -476,34 +493,56 @@ class StatusDataset : public StaticLocalDataSet<4> {
|
||||
|
||||
class HkDataset : public StaticLocalDataSet<HK_SET_POOL_ENTRIES> {
|
||||
public:
|
||||
HkDataset(HasLocalDataPoolIF* owner, uint32_t setId) : StaticLocalDataSet(owner, setId) {}
|
||||
HkDataset(HasLocalDataPoolIF* owner, uint32_t setId, std::array<lp_id_t, 7> pids)
|
||||
: StaticLocalDataSet(owner, setId),
|
||||
digitalVoltageMv(sid.objectId, pids[0], this),
|
||||
analogVoltageMv(sid.objectId, pids[1], this),
|
||||
digitalCurrentmA(sid.objectId, pids[2], this),
|
||||
analogCurrentmA(sid.objectId, pids[3], this),
|
||||
coilCurrentsMilliamps(sid.objectId, pids[4], this),
|
||||
/** All temperatures in [C] for X, Y, Z */
|
||||
coilTemperatures(sid.objectId, pids[5], this),
|
||||
mcuTemperature(sid.objectId, pids[6], this) {}
|
||||
|
||||
HkDataset(object_id_t objectId, uint32_t setId) : StaticLocalDataSet(sid_t(objectId, setId)) {}
|
||||
HkDataset(object_id_t objectId, uint32_t setId, std::array<lp_id_t, 7> pids)
|
||||
: StaticLocalDataSet(sid_t(objectId, setId)),
|
||||
digitalVoltageMv(sid.objectId, pids[0], this),
|
||||
analogVoltageMv(sid.objectId, pids[1], this),
|
||||
digitalCurrentmA(sid.objectId, pids[2], this),
|
||||
analogCurrentmA(sid.objectId, pids[3], this),
|
||||
coilCurrentsMilliamps(sid.objectId, pids[4], this),
|
||||
/** All temperatures in [C] for X, Y, Z */
|
||||
coilTemperatures(sid.objectId, pids[5], this),
|
||||
mcuTemperature(sid.objectId, pids[6], this) {}
|
||||
|
||||
// Engineering HK variables
|
||||
lp_var_t<uint16_t> digitalVoltageMv = lp_var_t<uint16_t>(sid.objectId, DIGITAL_VOLTAGE_MV, this);
|
||||
lp_var_t<uint16_t> analogVoltageMv = lp_var_t<uint16_t>(sid.objectId, ANALOG_VOLTAGE_MV, this);
|
||||
lp_var_t<float> digitalCurrentmA = lp_var_t<float>(sid.objectId, DIGITAL_CURRENT, this);
|
||||
lp_var_t<float> analogCurrentmA = lp_var_t<float>(sid.objectId, ANALOG_CURRENT, this);
|
||||
lp_var_t<float> coilXCurrentmA = lp_var_t<float>(sid.objectId, COIL_X_CURRENT, this);
|
||||
lp_var_t<float> coilYCurrentmA = lp_var_t<float>(sid.objectId, COIL_Y_CURRENT, this);
|
||||
lp_var_t<float> coilZCurrentmA = lp_var_t<float>(sid.objectId, COIL_Z_CURRENT, this);
|
||||
/** All temperatures in [<5B>C] */
|
||||
lp_var_t<int16_t> coilXTemperature = lp_var_t<int16_t>(sid.objectId, COIL_X_TEMPERATURE, this);
|
||||
lp_var_t<int16_t> coilYTemperature = lp_var_t<int16_t>(sid.objectId, COIL_Y_TEMPERATURE, this);
|
||||
lp_var_t<int16_t> coilZTemperature = lp_var_t<int16_t>(sid.objectId, COIL_Z_TEMPERATURE, this);
|
||||
lp_var_t<int16_t> mcuTemperature = lp_var_t<int16_t>(sid.objectId, MCU_TEMPERATURE, this);
|
||||
lp_var_t<uint16_t> digitalVoltageMv;
|
||||
lp_var_t<uint16_t> analogVoltageMv;
|
||||
lp_var_t<float> digitalCurrentmA;
|
||||
lp_var_t<float> analogCurrentmA;
|
||||
lp_vec_t<float, 3> coilCurrentsMilliamps;
|
||||
/** All temperatures in [C] for X, Y, Z */
|
||||
lp_vec_t<int16_t, 3> coilTemperatures;
|
||||
lp_var_t<int16_t> mcuTemperature;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class HkDatasetNoTorque : public HkDataset {
|
||||
public:
|
||||
HkDatasetNoTorque(HasLocalDataPoolIF* owner) : HkDataset(owner, imtq::SetIds::ENG_HK_NO_TORQUE) {}
|
||||
HkDatasetNoTorque(HasLocalDataPoolIF* owner)
|
||||
: HkDataset(owner, imtq::SetIds::ENG_HK_NO_TORQUE,
|
||||
{DIGITAL_VOLTAGE_MV, ANALOG_VOLTAGE_MV, DIGITAL_CURRENT, ANALOG_CURRENT,
|
||||
COIL_CURRENTS, COIL_TEMPERATURES, MCU_TEMPERATURE}) {}
|
||||
};
|
||||
|
||||
class HkDatasetWithTorque : public HkDataset {
|
||||
public:
|
||||
HkDatasetWithTorque(HasLocalDataPoolIF* owner)
|
||||
: HkDataset(owner, imtq::SetIds::ENG_HK_SET_WITH_TORQUE) {}
|
||||
: HkDataset(owner, imtq::SetIds::ENG_HK_SET_WITH_TORQUE,
|
||||
{DIGITAL_VOLTAGE_MV_WT, ANALOG_VOLTAGE_MV_WT, DIGITAL_CURRENT_WT,
|
||||
ANALOG_CURRENT_WT, COIL_CURRENTS_WT, COIL_TEMPERATURES_WT, MCU_TEMPERATURE_WT}) {
|
||||
}
|
||||
};
|
||||
/**
|
||||
*
|
||||
@ -529,32 +568,39 @@ class CalibratedMtmMeasurementSet : public StaticLocalDataSet<CAL_MTM_POOL_ENTRI
|
||||
*/
|
||||
class RawMtmMeasurementSet : public StaticLocalDataSet<CAL_MTM_POOL_ENTRIES> {
|
||||
public:
|
||||
RawMtmMeasurementSet(HasLocalDataPoolIF* owner, uint32_t setId)
|
||||
: StaticLocalDataSet(owner, setId) {}
|
||||
RawMtmMeasurementSet(object_id_t objectId, uint32_t setId, std::array<lp_id_t, 2> pids)
|
||||
: StaticLocalDataSet(sid_t(objectId, setId)),
|
||||
mtmRawNt(sid.objectId, pids.at(0), this),
|
||||
coilActuationStatus(sid.objectId, pids.at(1), this) {}
|
||||
|
||||
RawMtmMeasurementSet(object_id_t objectId, uint32_t setId)
|
||||
: StaticLocalDataSet(sid_t(objectId, setId)) {}
|
||||
RawMtmMeasurementSet(HasLocalDataPoolIF* owner, uint32_t setId, std::array<lp_id_t, 2> pids)
|
||||
: StaticLocalDataSet(owner, setId),
|
||||
mtmRawNt(sid.objectId, pids.at(0), this),
|
||||
coilActuationStatus(sid.objectId, pids.at(1), this) {}
|
||||
|
||||
/** The unit of all measurements is nT */
|
||||
lp_vec_t<float, 3> mtmRawNt = lp_vec_t<float, 3>(sid.objectId, MTM_RAW, this);
|
||||
lp_vec_t<float, 3> mtmRawNt;
|
||||
/** 1 if coils were actuating during measurement otherwise 0 */
|
||||
lp_var_t<uint8_t> coilActuationStatus =
|
||||
lp_var_t<uint8_t>(sid.objectId, ACTUATION_RAW_STATUS, this);
|
||||
lp_var_t<uint8_t> coilActuationStatus;
|
||||
};
|
||||
|
||||
class RawMtmMeasurementNoTorque : public RawMtmMeasurementSet {
|
||||
public:
|
||||
RawMtmMeasurementNoTorque(HasLocalDataPoolIF* owner)
|
||||
: RawMtmMeasurementSet(owner, imtq::SetIds::RAW_MTM_NO_TORQUE) {}
|
||||
: RawMtmMeasurementSet(owner, imtq::SetIds::RAW_MTM_NO_TORQUE,
|
||||
{PoolIds::MTM_RAW, PoolIds::ACTUATION_RAW_STATUS}) {}
|
||||
RawMtmMeasurementNoTorque(object_id_t objectId)
|
||||
: RawMtmMeasurementSet(objectId, imtq::SetIds::RAW_MTM_NO_TORQUE) {}
|
||||
: RawMtmMeasurementSet(objectId, imtq::SetIds::RAW_MTM_NO_TORQUE,
|
||||
{PoolIds::MTM_RAW, PoolIds::ACTUATION_RAW_STATUS}) {}
|
||||
};
|
||||
class RawMtmMeasurementWithTorque : public RawMtmMeasurementSet {
|
||||
public:
|
||||
RawMtmMeasurementWithTorque(HasLocalDataPoolIF* owner)
|
||||
: RawMtmMeasurementSet(owner, imtq::SetIds::RAW_MTM_WITH_TORQUE) {}
|
||||
: RawMtmMeasurementSet(owner, imtq::SetIds::RAW_MTM_WITH_TORQUE,
|
||||
{PoolIds::MTM_RAW_WT, PoolIds::ACTUATION_RAW_STATUS_WT}) {}
|
||||
RawMtmMeasurementWithTorque(object_id_t objectId)
|
||||
: RawMtmMeasurementSet(objectId, imtq::SetIds::RAW_MTM_WITH_TORQUE) {}
|
||||
: RawMtmMeasurementSet(objectId, imtq::SetIds::RAW_MTM_WITH_TORQUE,
|
||||
{PoolIds::MTM_RAW_WT, PoolIds::ACTUATION_RAW_STATUS_WT}) {}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -608,28 +654,16 @@ class DipoleActuationSet : public StaticLocalDataSet<4> {
|
||||
|
||||
void setDipoles(int16_t xDipole_, int16_t yDipole_, int16_t zDipole_,
|
||||
uint16_t currentTorqueDurationMs_) {
|
||||
if (xDipole.value != xDipole_) {
|
||||
xDipole = xDipole_;
|
||||
}
|
||||
if (yDipole.value != yDipole_) {
|
||||
yDipole = yDipole_;
|
||||
}
|
||||
if (zDipole.value != zDipole_) {
|
||||
zDipole = zDipole_;
|
||||
}
|
||||
dipoles[0] = xDipole_;
|
||||
dipoles[1] = yDipole_;
|
||||
dipoles[2] = zDipole_;
|
||||
currentTorqueDurationMs = currentTorqueDurationMs_;
|
||||
}
|
||||
|
||||
void getDipoles(int16_t& xDipole_, int16_t& yDipole_, int16_t& zDipole_) {
|
||||
xDipole_ = xDipole.value;
|
||||
yDipole_ = yDipole.value;
|
||||
zDipole_ = zDipole.value;
|
||||
}
|
||||
const int16_t* getDipoles() const { return dipoles.value; }
|
||||
|
||||
private:
|
||||
lp_var_t<int16_t> xDipole = lp_var_t<int16_t>(sid.objectId, DIPOLES_X, this);
|
||||
lp_var_t<int16_t> yDipole = lp_var_t<int16_t>(sid.objectId, DIPOLES_Y, this);
|
||||
lp_var_t<int16_t> zDipole = lp_var_t<int16_t>(sid.objectId, DIPOLES_Z, this);
|
||||
lp_vec_t<int16_t, 3> dipoles = lp_vec_t<int16_t, 3>(sid.objectId, DIPOLES_ID, this);
|
||||
lp_var_t<uint16_t> currentTorqueDurationMs =
|
||||
lp_var_t<uint16_t>(sid.objectId, CURRENT_TORQUE_DURATION, this);
|
||||
};
|
||||
@ -1098,80 +1132,21 @@ class NegZSelfTestSet : public StaticLocalDataSet<SELF_TEST_DATASET_ENTRIES> {
|
||||
|
||||
} // namespace imtq
|
||||
|
||||
struct ImtqRequest {
|
||||
friend class ImtqHandler;
|
||||
|
||||
public:
|
||||
static constexpr size_t REQUEST_LEN = 10;
|
||||
|
||||
ImtqRequest(const uint8_t* data, size_t maxSize)
|
||||
: rawData(const_cast<uint8_t*>(data)), maxSize(maxSize) {}
|
||||
|
||||
imtq::RequestType getRequestType() const { return static_cast<imtq::RequestType>(rawData[0]); }
|
||||
|
||||
void setMeasureRequest(imtq::SpecialRequest specialRequest) {
|
||||
rawData[0] = static_cast<uint8_t>(imtq::RequestType::MEASURE_NO_ACTUATION);
|
||||
rawData[1] = static_cast<uint8_t>(specialRequest);
|
||||
}
|
||||
|
||||
void setActuateRequest(int16_t dipoleX, int16_t dipoleY, int16_t dipoleZ,
|
||||
uint16_t torqueDuration) {
|
||||
size_t dummy = 0;
|
||||
rawData[0] = static_cast<uint8_t>(imtq::RequestType::ACTUATE);
|
||||
rawData[1] = static_cast<uint8_t>(imtq::SpecialRequest::NONE);
|
||||
uint8_t* serPtr = rawData + 2;
|
||||
SerializeAdapter::serialize(&dipoleX, &serPtr, &dummy, maxSize,
|
||||
SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&dipoleY, &serPtr, &dummy, maxSize,
|
||||
SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&dipoleZ, &serPtr, &dummy, maxSize,
|
||||
SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&torqueDuration, &serPtr, &dummy, maxSize,
|
||||
SerializeIF::Endianness::MACHINE);
|
||||
}
|
||||
|
||||
uint8_t* startOfActuateDataPtr() { return rawData + 2; }
|
||||
|
||||
int16_t* getDipoles() { return reinterpret_cast<int16_t*>(rawData + 2); }
|
||||
|
||||
uint16_t getTorqueDuration() {
|
||||
uint8_t* data = rawData + 2 + 6;
|
||||
uint16_t value = 0;
|
||||
size_t dummy = 0;
|
||||
SerializeAdapter::deSerialize(&value, data, &dummy, SerializeIF::Endianness::MACHINE);
|
||||
return value;
|
||||
}
|
||||
|
||||
void setSpecialRequest(imtq::SpecialRequest specialRequest) {
|
||||
rawData[1] = static_cast<uint8_t>(specialRequest);
|
||||
}
|
||||
|
||||
imtq::SpecialRequest getSpecialRequest() const {
|
||||
return static_cast<imtq::SpecialRequest>(rawData[1]);
|
||||
}
|
||||
|
||||
private:
|
||||
ImtqRequest(uint8_t* rawData, size_t maxLen) : rawData(rawData) {
|
||||
if (rawData != nullptr) {
|
||||
rawData[0] = static_cast<uint8_t>(imtq::RequestType::MEASURE_NO_ACTUATION);
|
||||
}
|
||||
}
|
||||
uint8_t* rawData;
|
||||
size_t maxSize = 0;
|
||||
};
|
||||
|
||||
struct ImtqRepliesDefault {
|
||||
friend class ImtqPollingTask;
|
||||
|
||||
public:
|
||||
static constexpr size_t BASE_LEN =
|
||||
imtq::replySize::DEFAULT_MIN_LEN + 1 + imtq::replySize::SYSTEM_STATE + 1 +
|
||||
1 + imtq::replySize::DEFAULT_MIN_LEN + 1 + imtq::replySize::SYSTEM_STATE + 1 +
|
||||
+imtq::replySize::DEFAULT_MIN_LEN + 1 + imtq::replySize::RAW_MTM_MEASUREMENT + 1 +
|
||||
imtq::replySize::ENG_HK_DATA_REPLY + 1 + imtq::replySize::CAL_MTM_MEASUREMENT + 1;
|
||||
ImtqRepliesDefault(const uint8_t* rawData) : rawData(const_cast<uint8_t*>(rawData)) {
|
||||
initPointers();
|
||||
}
|
||||
|
||||
void setConfigured() { rawData[0] = true; }
|
||||
bool devWasConfigured() const { return rawData[0]; }
|
||||
|
||||
uint8_t* getCalibMgmMeasurement() const { return calibMgmMeasurement + 1; }
|
||||
bool wasCalibMgmMeasurementRead() const { return calibMgmMeasurement[0]; };
|
||||
|
||||
@ -1193,7 +1168,7 @@ struct ImtqRepliesDefault {
|
||||
|
||||
private:
|
||||
void initPointers() {
|
||||
swReset = rawData;
|
||||
swReset = rawData + 1;
|
||||
systemState = swReset + imtq::replySize::DEFAULT_MIN_LEN + 1;
|
||||
startMtmMeasurement = systemState + imtq::replySize::SYSTEM_STATE + 1;
|
||||
rawMgmMeasurement = startMtmMeasurement + imtq::replySize::DEFAULT_MIN_LEN + 1;
|
||||
@ -1201,6 +1176,7 @@ struct ImtqRepliesDefault {
|
||||
calibMgmMeasurement = engHk + imtq::replySize::ENG_HK_DATA_REPLY + 1;
|
||||
specialRequestReply = calibMgmMeasurement + imtq::replySize::CAL_MTM_MEASUREMENT + 1;
|
||||
}
|
||||
|
||||
uint8_t* rawData;
|
||||
uint8_t* swReset;
|
||||
uint8_t* systemState;
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <fsfw/datapoollocal/StaticLocalDataSet.h>
|
||||
#include <fsfw/devicehandlers/DeviceHandlerIF.h>
|
||||
#include <mission/memory/NvmParameterBase.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <filesystem>
|
||||
@ -10,7 +11,6 @@
|
||||
|
||||
#include "OBSWConfig.h"
|
||||
#include "mission/devices/max1227.h"
|
||||
#include "mission/memory/NVMParameterBase.h"
|
||||
|
||||
namespace plpcdu {
|
||||
|
||||
|
@ -1 +1 @@
|
||||
target_sources(${LIB_EIVE_MISSION} PRIVATE NVMParameterBase.cpp)
|
||||
target_sources(${LIB_EIVE_MISSION} PRIVATE NvmParameterBase.cpp)
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include "NVMParameterBase.h"
|
||||
#include <mission/memory/NvmParameterBase.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
@ -10,13 +10,14 @@ NVMParameterBase::NVMParameterBase(std::string fullName) : fullName(fullName) {}
|
||||
NVMParameterBase::NVMParameterBase() {}
|
||||
|
||||
ReturnValue_t NVMParameterBase::readJsonFile() {
|
||||
if (std::filesystem::exists(fullName)) {
|
||||
std::error_code e;
|
||||
if (std::filesystem::exists(fullName, e)) {
|
||||
// Read JSON file content into object
|
||||
std::ifstream i(fullName);
|
||||
try {
|
||||
i >> json;
|
||||
} catch (nlohmann::json::exception& e) {
|
||||
sif::warning << "Reading JSON file failed with error " << e.what() << std::endl;
|
||||
} catch (nlohmann::json::exception& nlohmannE) {
|
||||
sif::warning << "Reading JSON file failed with error " << nlohmannE.what() << std::endl;
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
return returnvalue::OK;
|
||||
@ -39,7 +40,10 @@ void NVMParameterBase::setFullName(std::string fullName) { this->fullName = full
|
||||
|
||||
std::string NVMParameterBase::getFullName() const { return fullName; }
|
||||
|
||||
bool NVMParameterBase::getJsonFileExists() { return std::filesystem::exists(fullName); }
|
||||
bool NVMParameterBase::getJsonFileExists() {
|
||||
std::error_code e;
|
||||
return std::filesystem::exists(fullName, e);
|
||||
}
|
||||
|
||||
void NVMParameterBase::printKeys() const {
|
||||
sif::info << "Printing keys for JSON file " << fullName << std::endl;
|
@ -1,3 +1,4 @@
|
||||
target_sources(
|
||||
${LIB_EIVE_MISSION} PRIVATE AcsBoardFdir.cpp RtdFdir.cpp SusFdir.cpp
|
||||
SyrlinksFdir.cpp GomspacePowerFdir.cpp)
|
||||
${LIB_EIVE_MISSION}
|
||||
PRIVATE AcsBoardFdir.cpp RtdFdir.cpp StrFdir.cpp SusFdir.cpp SyrlinksFdir.cpp
|
||||
GomspacePowerFdir.cpp)
|
||||
|
14
mission/system/fdir/StrFdir.cpp
Normal file
14
mission/system/fdir/StrFdir.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
#include "StrFdir.h"
|
||||
|
||||
#include "mission/acsDefs.h"
|
||||
|
||||
StrFdir::StrFdir(object_id_t strObject)
|
||||
: DeviceHandlerFailureIsolation(strObject, objects::NO_OBJECT) {}
|
||||
|
||||
ReturnValue_t StrFdir::eventReceived(EventMessage* event) {
|
||||
if (event->getEvent() == acs::MEKF_INVALID_MODE_VIOLATION) {
|
||||
setFaulty(event->getEvent());
|
||||
return returnvalue::OK;
|
||||
}
|
||||
return DeviceHandlerFailureIsolation::eventReceived(event);
|
||||
}
|
12
mission/system/fdir/StrFdir.h
Normal file
12
mission/system/fdir/StrFdir.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef MISSION_SYSTEM_FDIR_STRFDIR_H_
|
||||
#define MISSION_SYSTEM_FDIR_STRFDIR_H_
|
||||
|
||||
#include <fsfw/devicehandlers/DeviceHandlerFailureIsolation.h>
|
||||
|
||||
class StrFdir : public DeviceHandlerFailureIsolation {
|
||||
public:
|
||||
StrFdir(object_id_t strObject);
|
||||
ReturnValue_t eventReceived(EventMessage* event) override;
|
||||
};
|
||||
|
||||
#endif /* MISSION_SYSTEM_FDIR_STRFDIR_H_ */
|
@ -55,6 +55,12 @@ ReturnValue_t AcsBoardAssembly::commandChildren(Mode_t mode, Submode_t submode)
|
||||
modeTable[ModeTableIdx::MGM_3_B].setSubmode(SUBMODE_NONE);
|
||||
modeTable[ModeTableIdx::GPS].setMode(MODE_OFF);
|
||||
modeTable[ModeTableIdx::GPS].setSubmode(SUBMODE_NONE);
|
||||
if (recoveryState == RecoveryState::RECOVERY_IDLE) {
|
||||
result = checkAndHandleHealthStates(mode, submode);
|
||||
if (result == NEED_TO_CHANGE_HEALTH) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
}
|
||||
if (recoveryState != RecoveryState::RECOVERY_STARTED) {
|
||||
if (mode == DeviceHandlerIF::MODE_NORMAL or mode == MODE_ON) {
|
||||
result = handleNormalOrOnModeCmd(mode, submode);
|
||||
@ -280,3 +286,30 @@ ReturnValue_t AcsBoardAssembly::initialize() {
|
||||
}
|
||||
return AssemblyBase::initialize();
|
||||
}
|
||||
|
||||
ReturnValue_t AcsBoardAssembly::checkAndHandleHealthStates(Mode_t deviceMode,
|
||||
Submode_t deviceSubmode) {
|
||||
using namespace returnvalue;
|
||||
ReturnValue_t status = returnvalue::OK;
|
||||
auto overwriteHealthForOneDev = [&](object_id_t dev) {
|
||||
HealthState health = healthHelper.healthTable->getHealth(dev);
|
||||
if (health == FAULTY or health == PERMANENT_FAULTY) {
|
||||
overwriteDeviceHealth(dev, health);
|
||||
status = NEED_TO_CHANGE_HEALTH;
|
||||
} else if (health == EXTERNAL_CONTROL) {
|
||||
modeHelper.setForced(true);
|
||||
}
|
||||
};
|
||||
if (deviceSubmode == duallane::DUAL_MODE) {
|
||||
overwriteHealthForOneDev(helper.mgm0Lis3IdSideA);
|
||||
overwriteHealthForOneDev(helper.mgm1Rm3100IdSideA);
|
||||
overwriteHealthForOneDev(helper.mgm2Lis3IdSideB);
|
||||
overwriteHealthForOneDev(helper.mgm3Rm3100IdSideB);
|
||||
overwriteHealthForOneDev(helper.gyro0AdisIdSideA);
|
||||
overwriteHealthForOneDev(helper.gyro1L3gIdSideA);
|
||||
overwriteHealthForOneDev(helper.gyro2AdisIdSideB);
|
||||
overwriteHealthForOneDev(helper.gyro3L3gIdSideB);
|
||||
overwriteHealthForOneDev(helper.gpsId);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
@ -121,6 +121,7 @@ class AcsBoardAssembly : public DualLaneAssemblyBase {
|
||||
ReturnValue_t checkChildrenStateOn(Mode_t wantedMode, Submode_t wantedSubmode) override;
|
||||
|
||||
ReturnValue_t handleNormalOrOnModeCmd(Mode_t mode, Submode_t submode);
|
||||
ReturnValue_t checkAndHandleHealthStates(Mode_t deviceMode, Submode_t deviceSubmode);
|
||||
void refreshHelperModes();
|
||||
};
|
||||
|
||||
|
@ -75,9 +75,7 @@ void AcsSubsystem::handleEventMessages() {
|
||||
sif::error << "AcsSubsystem: sending DETUMBLE mode cmd to self has failed" << std::endl;
|
||||
}
|
||||
}
|
||||
if (event.getEvent() == acs::SAFE_RATE_RECOVERY ||
|
||||
event.getEvent() == acs::MULTIPLE_RW_INVALID ||
|
||||
event.getEvent() == acs::MEKF_INVALID_MODE_VIOLATION) {
|
||||
if (event.getEvent() == acs::SAFE_RATE_RECOVERY) {
|
||||
CommandMessage msg;
|
||||
ModeMessage::setCmdModeMessage(msg, acs::AcsMode::SAFE, 0);
|
||||
status = commandQueue->sendMessage(commandQueue->getId(), &msg);
|
||||
|
@ -7,11 +7,13 @@ target_sources(
|
||||
TcsSubsystem.cpp
|
||||
PayloadSubsystem.cpp
|
||||
AcsBoardAssembly.cpp
|
||||
ImtqAssembly.cpp
|
||||
SyrlinksAssembly.cpp
|
||||
Stack5VHandler.cpp
|
||||
SusAssembly.cpp
|
||||
RwAssembly.cpp
|
||||
DualLanePowerStateMachine.cpp
|
||||
StrAssembly.cpp
|
||||
PowerStateMachineBase.cpp
|
||||
DualLaneAssemblyBase.cpp
|
||||
TcsBoardAssembly.cpp)
|
||||
|
@ -235,8 +235,3 @@ void DualLaneAssemblyBase::setPreferredSide(duallane::Submodes submode) {
|
||||
}
|
||||
this->defaultSubmode = submode;
|
||||
}
|
||||
|
||||
ReturnValue_t DualLaneAssemblyBase::checkAndHandleHealthState(Mode_t deviceMode,
|
||||
Submode_t deviceSubmode) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
@ -70,11 +70,11 @@ class DualLaneAssemblyBase : public AssemblyBase, public ConfirmsFailuresIF {
|
||||
virtual void handleChildrenLostMode(ReturnValue_t result) override;
|
||||
virtual void handleModeTransitionFailed(ReturnValue_t result) override;
|
||||
virtual void handleModeReached() override;
|
||||
ReturnValue_t checkAndHandleHealthState(Mode_t deviceMode, Submode_t deviceSubmode);
|
||||
|
||||
MessageQueueId_t getEventReceptionQueue() override;
|
||||
|
||||
bool sideSwitchTransition(Mode_t mode, Submode_t submode);
|
||||
ReturnValue_t checkAndHandleHealthState(Mode_t deviceMode, Submode_t deviceSubmode);
|
||||
|
||||
/**
|
||||
* Implemented by user. Will be called if a full mode operation has finished.
|
||||
@ -96,7 +96,6 @@ inline void DualLaneAssemblyBase::initModeTableEntry(
|
||||
entry.setObject(id);
|
||||
entry.setMode(MODE_OFF);
|
||||
entry.setSubmode(SUBMODE_NONE);
|
||||
entry.setInheritSubmode(false);
|
||||
modeTable.insert(entry);
|
||||
}
|
||||
|
||||
|
54
mission/system/objects/ImtqAssembly.cpp
Normal file
54
mission/system/objects/ImtqAssembly.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include "ImtqAssembly.h"
|
||||
|
||||
#include <eive/objects.h>
|
||||
|
||||
using namespace returnvalue;
|
||||
|
||||
ImtqAssembly::ImtqAssembly(object_id_t objectId) : AssemblyBase(objectId) {
|
||||
ModeListEntry entry;
|
||||
entry.setObject(objects::IMTQ_HANDLER);
|
||||
entry.setMode(MODE_OFF);
|
||||
entry.setSubmode(SUBMODE_NONE);
|
||||
commandTable.insert(entry);
|
||||
}
|
||||
|
||||
ReturnValue_t ImtqAssembly::commandChildren(Mode_t mode, Submode_t submode) {
|
||||
commandTable[0].setMode(mode);
|
||||
commandTable[0].setSubmode(submode);
|
||||
if (recoveryState == RECOVERY_IDLE) {
|
||||
ReturnValue_t result = checkAndHandleHealthState(mode, submode);
|
||||
if (result == NEED_TO_CHANGE_HEALTH) {
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
HybridIterator<ModeListEntry> iter(commandTable.begin(), commandTable.end());
|
||||
executeTable(iter);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t ImtqAssembly::checkChildrenStateOn(Mode_t wantedMode, Submode_t wantedSubmode) {
|
||||
if (childrenMap[objects::IMTQ_HANDLER].mode != wantedMode) {
|
||||
return NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE;
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t ImtqAssembly::isModeCombinationValid(Mode_t mode, Submode_t submode) {
|
||||
if (mode == MODE_ON or mode == DeviceHandlerIF::MODE_NORMAL or mode == MODE_OFF) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
ReturnValue_t ImtqAssembly::checkAndHandleHealthState(Mode_t deviceMode, Submode_t deviceSubmode) {
|
||||
HealthState health = healthHelper.healthTable->getHealth(objects::IMTQ_HANDLER);
|
||||
if (health == FAULTY or health == PERMANENT_FAULTY) {
|
||||
overwriteDeviceHealth(objects::IMTQ_HANDLER, health);
|
||||
return NEED_TO_CHANGE_HEALTH;
|
||||
} else if (health == EXTERNAL_CONTROL) {
|
||||
modeHelper.setForced(true);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
void ImtqAssembly::handleChildrenLostMode(ReturnValue_t result) { startTransition(mode, submode); }
|
18
mission/system/objects/ImtqAssembly.h
Normal file
18
mission/system/objects/ImtqAssembly.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <fsfw/devicehandlers/AssemblyBase.h>
|
||||
|
||||
class ImtqAssembly : public AssemblyBase {
|
||||
public:
|
||||
ImtqAssembly(object_id_t objectId);
|
||||
|
||||
private:
|
||||
FixedArrayList<ModeListEntry, 1> commandTable;
|
||||
|
||||
ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) override;
|
||||
ReturnValue_t checkChildrenStateOn(Mode_t wantedMode, Submode_t wantedSubmode) override;
|
||||
ReturnValue_t isModeCombinationValid(Mode_t mode, Submode_t submode) override;
|
||||
void handleChildrenLostMode(ReturnValue_t result) override;
|
||||
|
||||
ReturnValue_t checkAndHandleHealthState(Mode_t deviceMode, Submode_t deviceSubmode);
|
||||
};
|
@ -8,7 +8,6 @@ RwAssembly::RwAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitcher, power::
|
||||
entry.setObject(helper.rwIds[idx]);
|
||||
entry.setMode(MODE_OFF);
|
||||
entry.setSubmode(SUBMODE_NONE);
|
||||
entry.setInheritSubmode(false);
|
||||
modeTable.insert(entry);
|
||||
}
|
||||
}
|
||||
|
30
mission/system/objects/StrAssembly.cpp
Normal file
30
mission/system/objects/StrAssembly.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
#include "StrAssembly.h"
|
||||
|
||||
#include <eive/objects.h>
|
||||
|
||||
StrAssembly::StrAssembly(object_id_t objectId) : AssemblyBase(objectId) {
|
||||
ModeListEntry entry;
|
||||
entry.setObject(objects::STAR_TRACKER);
|
||||
entry.setMode(MODE_OFF);
|
||||
entry.setSubmode(SUBMODE_NONE);
|
||||
commandTable.insert(entry);
|
||||
}
|
||||
|
||||
ReturnValue_t StrAssembly::commandChildren(Mode_t mode, Submode_t submode) {
|
||||
commandTable[0].setMode(mode);
|
||||
commandTable[0].setSubmode(submode);
|
||||
HybridIterator<ModeListEntry> iter(commandTable.begin(), commandTable.end());
|
||||
executeTable(iter);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t StrAssembly::checkChildrenStateOn(Mode_t wantedMode, Submode_t wantedSubmode) {
|
||||
if (childrenMap[objects::STAR_TRACKER].mode != wantedMode) {
|
||||
return NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE;
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t StrAssembly::isModeCombinationValid(Mode_t mode, Submode_t submode) {
|
||||
return returnvalue::OK;
|
||||
}
|
18
mission/system/objects/StrAssembly.h
Normal file
18
mission/system/objects/StrAssembly.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef MISSION_SYSTEM_OBJECTS_STRASSEMBLY_H_
|
||||
#define MISSION_SYSTEM_OBJECTS_STRASSEMBLY_H_
|
||||
|
||||
#include "fsfw/devicehandlers/AssemblyBase.h"
|
||||
|
||||
class StrAssembly : public AssemblyBase {
|
||||
public:
|
||||
StrAssembly(object_id_t objectId);
|
||||
|
||||
private:
|
||||
FixedArrayList<ModeListEntry, 1> commandTable;
|
||||
|
||||
ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) override;
|
||||
ReturnValue_t checkChildrenStateOn(Mode_t wantedMode, Submode_t wantedSubmode) override;
|
||||
ReturnValue_t isModeCombinationValid(Mode_t mode, Submode_t submode) override;
|
||||
};
|
||||
|
||||
#endif /* MISSION_SYSTEM_OBJECTS_STRASSEMBLY_H_ */
|
@ -12,7 +12,6 @@ TcsBoardAssembly::TcsBoardAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitc
|
||||
entry.setObject(helper.rtdInfos[idx].first);
|
||||
entry.setMode(MODE_OFF);
|
||||
entry.setSubmode(SUBMODE_NONE);
|
||||
entry.setInheritSubmode(false);
|
||||
modeTable.insert(entry);
|
||||
}
|
||||
}
|
||||
@ -41,6 +40,12 @@ ReturnValue_t TcsBoardAssembly::commandChildren(Mode_t mode, Submode_t submode)
|
||||
modeTable[idx].setMode(MODE_OFF);
|
||||
modeTable[idx].setSubmode(SUBMODE_NONE);
|
||||
}
|
||||
if (recoveryState == RecoveryState::RECOVERY_IDLE) {
|
||||
result = checkAndHandleHealthStates(mode, submode);
|
||||
if (result == NEED_TO_CHANGE_HEALTH) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
}
|
||||
if (recoveryState != RecoveryState::RECOVERY_STARTED) {
|
||||
if (mode == DeviceHandlerIF::MODE_NORMAL or mode == MODE_ON) {
|
||||
result = handleNormalOrOnModeCmd(mode, submode);
|
||||
@ -62,10 +67,10 @@ ReturnValue_t TcsBoardAssembly::checkChildrenStateOn(Mode_t wantedMode, Submode_
|
||||
} catch (const std::out_of_range& e) {
|
||||
sif::error << "TcsBoardAssembly: Invalid children map: " << e.what() << std::endl;
|
||||
}
|
||||
if (devsInWrongMode >= 3) {
|
||||
if (devsInWrongMode == NUMBER_RTDS) {
|
||||
if (warningSwitch) {
|
||||
sif::warning << "TcsBoardAssembly::checkChildrenStateOn: " << devsInWrongMode << " devices in"
|
||||
<< " wrong mode" << std::endl;
|
||||
sif::warning << "TcsBoardAssembly::checkChildrenStateOn: All devices in wrong mode"
|
||||
<< std::endl;
|
||||
warningSwitch = false;
|
||||
}
|
||||
return NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE;
|
||||
@ -180,9 +185,29 @@ void TcsBoardAssembly::handleModeReached() {
|
||||
}
|
||||
|
||||
void TcsBoardAssembly::handleChildrenLostMode(ReturnValue_t result) {
|
||||
// TODO: Maybe try a reboot once here?
|
||||
triggerEvent(CHILDREN_LOST_MODE, result);
|
||||
return;
|
||||
startTransition(mode, submode);
|
||||
}
|
||||
|
||||
ReturnValue_t TcsBoardAssembly::checkAndHandleHealthStates(Mode_t deviceMode,
|
||||
Submode_t deviceSubmode) {
|
||||
ReturnValue_t status = returnvalue::OK;
|
||||
for (const auto& dev : helper.rtdInfos) {
|
||||
HealthState health = healthHelper.healthTable->getHealth(dev.first);
|
||||
if (health == HealthState::HEALTHY) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& dev : helper.rtdInfos) {
|
||||
HealthState health = healthHelper.healthTable->getHealth(dev.first);
|
||||
if (health == FAULTY or health == PERMANENT_FAULTY) {
|
||||
status = NEED_TO_CHANGE_HEALTH;
|
||||
} else if (health == EXTERNAL_CONTROL) {
|
||||
modeHelper.setForced(true);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void TcsBoardAssembly::handleModeTransitionFailed(ReturnValue_t result) {
|
||||
|
@ -52,6 +52,7 @@ class TcsBoardAssembly : public AssemblyBase, public ConfirmsFailuresIF {
|
||||
ReturnValue_t isModeCombinationValid(Mode_t mode, Submode_t submode) override;
|
||||
void startTransition(Mode_t mode, Submode_t submode) override;
|
||||
void handleModeReached() override;
|
||||
ReturnValue_t checkAndHandleHealthStates(Mode_t deviceMode, Submode_t deviceSubmode);
|
||||
|
||||
// These two overrides prevent a transition of the whole assembly back to off just because
|
||||
// some devices are not working
|
||||
|
@ -6,8 +6,11 @@
|
||||
#include <fsfw/subsystem/Subsystem.h>
|
||||
#include <fsfw/subsystem/modes/ModeDefinitions.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "eive/objects.h"
|
||||
#include "mission/acsDefs.h"
|
||||
#include "mission/system/objects/definitions.h"
|
||||
#include "util.h"
|
||||
|
||||
AcsSubsystem satsystem::acs::ACS_SUBSYSTEM(objects::ACS_SUBSYSTEM, 12, 24);
|
||||
@ -100,24 +103,28 @@ Subsystem& satsystem::acs::init() {
|
||||
ModeListEntry entry;
|
||||
const char* ctxc = "satsystem::acs::init: generic target";
|
||||
// Insert Helper Table
|
||||
auto iht = [&](object_id_t obj, Mode_t mode, Submode_t submode, ArrayList<ModeListEntry>& table) {
|
||||
auto iht = [&](object_id_t obj, Mode_t mode, Submode_t submode, ArrayList<ModeListEntry>& table,
|
||||
bool allowAllSubmodes = false) {
|
||||
entry.setObject(obj);
|
||||
entry.setMode(mode);
|
||||
entry.setSubmode(submode);
|
||||
if (allowAllSubmodes) {
|
||||
entry.allowAllSubmodes();
|
||||
}
|
||||
check(table.insert(entry), "satsystem::acs::init: generic target");
|
||||
};
|
||||
// Build TARGET PT transition 0
|
||||
iht(objects::IMTQ_HANDLER, NML, 0, ACS_TABLE_PTG_TRANS_0.second);
|
||||
iht(objects::SUS_BOARD_ASS, NML, 0, ACS_TABLE_PTG_TRANS_0.second);
|
||||
iht(objects::ACS_BOARD_ASS, NML, 0, ACS_TABLE_PTG_TRANS_0.second);
|
||||
iht(objects::IMTQ_ASSY, NML, 0, ACS_TABLE_PTG_TRANS_0.second);
|
||||
iht(objects::SUS_BOARD_ASS, NML, duallane::A_SIDE, ACS_TABLE_PTG_TRANS_0.second, true);
|
||||
iht(objects::ACS_BOARD_ASS, NML, duallane::A_SIDE, ACS_TABLE_PTG_TRANS_0.second, true);
|
||||
iht(objects::RW_ASSY, NML, 0, ACS_TABLE_PTG_TRANS_0.second);
|
||||
iht(objects::STAR_TRACKER, NML, 0, ACS_TABLE_PTG_TRANS_0.second);
|
||||
iht(objects::STR_ASSY, NML, 0, ACS_TABLE_PTG_TRANS_0.second);
|
||||
check(ACS_SUBSYSTEM.addTable(
|
||||
TableEntry(ACS_TABLE_PTG_TRANS_0.first, &ACS_TABLE_PTG_TRANS_0.second)),
|
||||
ctxc);
|
||||
|
||||
// Build SUS board transition
|
||||
iht(objects::SUS_BOARD_ASS, NML, 0, SUS_BOARD_NML_TRANS.second);
|
||||
iht(objects::SUS_BOARD_ASS, NML, duallane::A_SIDE, SUS_BOARD_NML_TRANS.second, true);
|
||||
check(ACS_SUBSYSTEM.addTable(TableEntry(SUS_BOARD_NML_TRANS.first, &SUS_BOARD_NML_TRANS.second)),
|
||||
ctxc);
|
||||
|
||||
@ -162,8 +169,8 @@ void buildOffSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
check(ss.addTable(TableEntry(ACS_TABLE_OFF_TRANS_0.first, &ACS_TABLE_OFF_TRANS_0.second)), ctxc);
|
||||
|
||||
// Build OFF transition 1
|
||||
iht(objects::IMTQ_HANDLER, OFF, 0, ACS_TABLE_OFF_TRANS_1.second);
|
||||
iht(objects::STAR_TRACKER, OFF, 0, ACS_TABLE_OFF_TRANS_1.second);
|
||||
iht(objects::IMTQ_ASSY, OFF, 0, ACS_TABLE_OFF_TRANS_1.second);
|
||||
iht(objects::STR_ASSY, OFF, 0, ACS_TABLE_OFF_TRANS_1.second);
|
||||
iht(objects::ACS_BOARD_ASS, OFF, 0, ACS_TABLE_OFF_TRANS_1.second);
|
||||
iht(objects::RW_ASSY, OFF, 0, ACS_TABLE_OFF_TRANS_1.second);
|
||||
check(ss.addTable(TableEntry(ACS_TABLE_OFF_TRANS_1.first, &ACS_TABLE_OFF_TRANS_1.second)), ctxc);
|
||||
@ -182,10 +189,13 @@ void buildSafeSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
auto ctxc = context.c_str();
|
||||
// Insert Helper Table
|
||||
auto iht = [&](object_id_t obj, Mode_t mode, Submode_t submode,
|
||||
ArrayList<ModeListEntry>& sequence) {
|
||||
ArrayList<ModeListEntry>& sequence, bool allowAllSubmodes = false) {
|
||||
eh.setObject(obj);
|
||||
eh.setMode(mode);
|
||||
eh.setSubmode(submode);
|
||||
if (allowAllSubmodes) {
|
||||
eh.allowAllSubmodes();
|
||||
}
|
||||
check(sequence.insert(eh), ctxc);
|
||||
};
|
||||
// Insert Helper Sequence
|
||||
@ -198,15 +208,16 @@ void buildSafeSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
};
|
||||
// Build SAFE target
|
||||
iht(objects::ACS_CONTROLLER, NML, acs::AcsMode::SAFE, ACS_TABLE_SAFE_TGT.second);
|
||||
iht(objects::IMTQ_HANDLER, NML, 0, ACS_TABLE_SAFE_TGT.second);
|
||||
iht(objects::SUS_BOARD_ASS, NML, 0, ACS_TABLE_SAFE_TGT.second);
|
||||
iht(objects::ACS_BOARD_ASS, NML, 0, ACS_TABLE_SAFE_TGT.second);
|
||||
iht(objects::IMTQ_ASSY, NML, 0, ACS_TABLE_SAFE_TGT.second);
|
||||
iht(objects::SUS_BOARD_ASS, NML, 0, ACS_TABLE_SAFE_TGT.second, true);
|
||||
iht(objects::ACS_BOARD_ASS, NML, 0, ACS_TABLE_SAFE_TGT.second, true);
|
||||
check(ss.addTable(&ACS_TABLE_SAFE_TGT.second, ACS_TABLE_SAFE_TGT.first, false, true), ctxc);
|
||||
|
||||
// Build SAFE transition 0
|
||||
iht(objects::IMTQ_HANDLER, NML, 0, ACS_TABLE_SAFE_TRANS_0.second);
|
||||
iht(objects::ACS_BOARD_ASS, NML, 0, ACS_TABLE_SAFE_TRANS_0.second);
|
||||
iht(objects::STAR_TRACKER, OFF, 0, ACS_TABLE_SAFE_TRANS_0.second);
|
||||
iht(objects::IMTQ_ASSY, NML, 0, ACS_TABLE_SAFE_TRANS_0.second);
|
||||
iht(objects::ACS_BOARD_ASS, NML, duallane::A_SIDE, ACS_TABLE_SAFE_TRANS_0.second, true);
|
||||
iht(objects::SUS_BOARD_ASS, NML, duallane::A_SIDE, ACS_TABLE_SAFE_TRANS_0.second, true);
|
||||
iht(objects::STR_ASSY, OFF, 0, ACS_TABLE_SAFE_TRANS_0.second);
|
||||
iht(objects::RW_ASSY, OFF, 0, ACS_TABLE_SAFE_TRANS_0.second);
|
||||
check(ss.addTable(&ACS_TABLE_SAFE_TRANS_0.second, ACS_TABLE_SAFE_TRANS_0.first, false, true),
|
||||
ctxc);
|
||||
@ -220,7 +231,6 @@ void buildSafeSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
|
||||
// Build SAFE sequence
|
||||
ihs(ACS_SEQUENCE_SAFE.second, ACS_TABLE_SAFE_TGT.first, 0, true);
|
||||
ihs(ACS_SEQUENCE_SAFE.second, SUS_BOARD_NML_TRANS.first, 0, false);
|
||||
ihs(ACS_SEQUENCE_SAFE.second, ACS_TABLE_SAFE_TRANS_0.first, 0, false);
|
||||
ihs(ACS_SEQUENCE_SAFE.second, ACS_TABLE_SAFE_TRANS_1.first, 0, false);
|
||||
check(ss.addSequence(&ACS_SEQUENCE_SAFE.second, ACS_SEQUENCE_SAFE.first, ACS_SEQUENCE_SAFE.first,
|
||||
@ -233,10 +243,13 @@ void buildDetumbleSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
auto ctxc = context.c_str();
|
||||
// Insert Helper Table
|
||||
auto iht = [&](object_id_t obj, Mode_t mode, Submode_t submode,
|
||||
ArrayList<ModeListEntry>& sequence) {
|
||||
ArrayList<ModeListEntry>& sequence, bool allowAllSubmodes = false) {
|
||||
eh.setObject(obj);
|
||||
eh.setMode(mode);
|
||||
eh.setSubmode(submode);
|
||||
if (allowAllSubmodes) {
|
||||
eh.allowAllSubmodes();
|
||||
}
|
||||
check(sequence.insert(eh), ctxc);
|
||||
};
|
||||
// Insert Helper Sequence
|
||||
@ -249,19 +262,17 @@ void buildDetumbleSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
};
|
||||
// Build DETUMBLE target
|
||||
iht(objects::ACS_CONTROLLER, NML, acs::AcsMode::DETUMBLE, ACS_TABLE_DETUMBLE_TGT.second);
|
||||
iht(objects::IMTQ_HANDLER, NML, 0, ACS_TABLE_DETUMBLE_TGT.second);
|
||||
iht(objects::SUS_BOARD_ASS, NML, 0, ACS_TABLE_DETUMBLE_TGT.second);
|
||||
iht(objects::ACS_BOARD_ASS, NML, 0, ACS_TABLE_DETUMBLE_TGT.second);
|
||||
iht(objects::IMTQ_ASSY, NML, 0, ACS_TABLE_DETUMBLE_TGT.second);
|
||||
iht(objects::SUS_BOARD_ASS, NML, 0, ACS_TABLE_DETUMBLE_TGT.second, true);
|
||||
iht(objects::ACS_BOARD_ASS, NML, 0, ACS_TABLE_DETUMBLE_TGT.second, true);
|
||||
check(ss.addTable(&ACS_TABLE_DETUMBLE_TGT.second, ACS_TABLE_DETUMBLE_TGT.first, false, true),
|
||||
ctxc);
|
||||
|
||||
// SUS board transition table is defined above
|
||||
|
||||
// Build DETUMBLE transition 0
|
||||
iht(objects::IMTQ_HANDLER, NML, 0, ACS_TABLE_DETUMBLE_TRANS_0.second);
|
||||
iht(objects::ACS_BOARD_ASS, NML, 0, ACS_TABLE_DETUMBLE_TRANS_0.second);
|
||||
iht(objects::SUS_BOARD_ASS, NML, 0, ACS_TABLE_DETUMBLE_TRANS_0.second);
|
||||
iht(objects::STAR_TRACKER, OFF, 0, ACS_TABLE_DETUMBLE_TRANS_0.second);
|
||||
iht(objects::IMTQ_ASSY, NML, 0, ACS_TABLE_DETUMBLE_TRANS_0.second);
|
||||
iht(objects::ACS_BOARD_ASS, NML, duallane::A_SIDE, ACS_TABLE_DETUMBLE_TRANS_0.second, true);
|
||||
iht(objects::SUS_BOARD_ASS, NML, duallane::A_SIDE, ACS_TABLE_DETUMBLE_TRANS_0.second, true);
|
||||
iht(objects::STR_ASSY, OFF, 0, ACS_TABLE_DETUMBLE_TRANS_0.second);
|
||||
iht(objects::RW_ASSY, OFF, 0, ACS_TABLE_DETUMBLE_TRANS_0.second);
|
||||
check(ss.addTable(&ACS_TABLE_DETUMBLE_TRANS_0.second, ACS_TABLE_DETUMBLE_TRANS_0.first, false,
|
||||
true),
|
||||
@ -275,7 +286,6 @@ void buildDetumbleSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
|
||||
// Build DETUMBLE sequence
|
||||
ihs(ACS_SEQUENCE_DETUMBLE.second, ACS_TABLE_DETUMBLE_TGT.first, 0, true);
|
||||
ihs(ACS_SEQUENCE_DETUMBLE.second, SUS_BOARD_NML_TRANS.first, 0, false);
|
||||
ihs(ACS_SEQUENCE_DETUMBLE.second, ACS_TABLE_DETUMBLE_TRANS_0.first, 0, false);
|
||||
ihs(ACS_SEQUENCE_DETUMBLE.second, ACS_TABLE_DETUMBLE_TRANS_1.first, 0, false);
|
||||
check(ss.addSequence(&ACS_SEQUENCE_DETUMBLE.second, ACS_SEQUENCE_DETUMBLE.first,
|
||||
@ -288,10 +298,13 @@ void buildIdleSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
auto ctxc = context.c_str();
|
||||
// Insert Helper Table
|
||||
auto iht = [&](object_id_t obj, Mode_t mode, Submode_t submode,
|
||||
ArrayList<ModeListEntry>& sequence) {
|
||||
ArrayList<ModeListEntry>& sequence, bool allowAllSubmodes = false) {
|
||||
eh.setObject(obj);
|
||||
eh.setMode(mode);
|
||||
eh.setSubmode(submode);
|
||||
if (allowAllSubmodes) {
|
||||
eh.allowAllSubmodes();
|
||||
}
|
||||
check(sequence.insert(eh), ctxc);
|
||||
};
|
||||
// Insert Helper Sequence
|
||||
@ -304,20 +317,19 @@ void buildIdleSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
};
|
||||
// Build IDLE target
|
||||
iht(objects::ACS_CONTROLLER, NML, acs::AcsMode::PTG_IDLE, ACS_TABLE_IDLE_TGT.second);
|
||||
iht(objects::IMTQ_HANDLER, NML, 0, ACS_TABLE_IDLE_TGT.second);
|
||||
iht(objects::IMTQ_ASSY, NML, 0, ACS_TABLE_IDLE_TGT.second);
|
||||
iht(objects::RW_ASSY, NML, 0, ACS_TABLE_IDLE_TGT.second);
|
||||
iht(objects::SUS_BOARD_ASS, NML, 0, ACS_TABLE_IDLE_TGT.second);
|
||||
iht(objects::ACS_BOARD_ASS, NML, 0, ACS_TABLE_IDLE_TGT.second);
|
||||
iht(objects::STR_ASSY, NML, 0, ACS_TABLE_IDLE_TGT.second);
|
||||
iht(objects::SUS_BOARD_ASS, NML, 0, ACS_TABLE_IDLE_TGT.second, true);
|
||||
iht(objects::ACS_BOARD_ASS, NML, 0, ACS_TABLE_IDLE_TGT.second, true);
|
||||
ss.addTable(&ACS_TABLE_IDLE_TGT.second, ACS_TABLE_IDLE_TGT.first, false, true);
|
||||
|
||||
// SUS board transition table is built above
|
||||
|
||||
// Build IDLE transition 0
|
||||
iht(objects::IMTQ_HANDLER, NML, 0, ACS_TABLE_IDLE_TRANS_0.second);
|
||||
iht(objects::ACS_BOARD_ASS, NML, 0, ACS_TABLE_IDLE_TRANS_0.second);
|
||||
iht(objects::SUS_BOARD_ASS, NML, 0, ACS_TABLE_IDLE_TRANS_0.second);
|
||||
iht(objects::IMTQ_ASSY, NML, 0, ACS_TABLE_IDLE_TRANS_0.second);
|
||||
iht(objects::ACS_BOARD_ASS, NML, duallane::A_SIDE, ACS_TABLE_IDLE_TRANS_0.second, true);
|
||||
iht(objects::SUS_BOARD_ASS, NML, duallane::A_SIDE, ACS_TABLE_IDLE_TRANS_0.second, true);
|
||||
iht(objects::RW_ASSY, NML, 0, ACS_TABLE_IDLE_TRANS_0.second);
|
||||
iht(objects::STAR_TRACKER, NML, 0, ACS_TABLE_IDLE_TRANS_0.second);
|
||||
iht(objects::STR_ASSY, NML, 0, ACS_TABLE_IDLE_TRANS_0.second);
|
||||
ss.addTable(&ACS_TABLE_IDLE_TRANS_0.second, ACS_TABLE_IDLE_TRANS_0.first, false, true);
|
||||
|
||||
// Build IDLE transition 1
|
||||
@ -326,7 +338,6 @@ void buildIdleSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
|
||||
// Build IDLE sequence
|
||||
ihs(ACS_SEQUENCE_IDLE.second, ACS_TABLE_IDLE_TGT.first, 0, true);
|
||||
ihs(ACS_SEQUENCE_IDLE.second, SUS_BOARD_NML_TRANS.first, 0, true);
|
||||
ihs(ACS_SEQUENCE_IDLE.second, ACS_TABLE_IDLE_TRANS_0.first, 0, true);
|
||||
ihs(ACS_SEQUENCE_IDLE.second, ACS_TABLE_IDLE_TRANS_1.first, 0, true);
|
||||
ss.addSequence(&ACS_SEQUENCE_IDLE.second, ACS_SEQUENCE_IDLE.first, ACS_SEQUENCE_SAFE.first, false,
|
||||
@ -338,10 +349,13 @@ void buildTargetPtSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
auto ctxc = context.c_str();
|
||||
// Insert Helper Table
|
||||
auto iht = [&](object_id_t obj, Mode_t mode, Submode_t submode,
|
||||
ArrayList<ModeListEntry>& sequence) {
|
||||
ArrayList<ModeListEntry>& sequence, bool allowAllSubmodes = false) {
|
||||
eh.setObject(obj);
|
||||
eh.setMode(mode);
|
||||
eh.setSubmode(submode);
|
||||
if (allowAllSubmodes) {
|
||||
eh.allowAllSubmodes();
|
||||
}
|
||||
check(sequence.insert(eh), ctxc);
|
||||
};
|
||||
// Insert Helper Sequence
|
||||
@ -355,15 +369,14 @@ void buildTargetPtSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
|
||||
// Build TARGET PT table
|
||||
iht(objects::ACS_CONTROLLER, NML, acs::AcsMode::PTG_TARGET, ACS_TABLE_PTG_TARGET_TGT.second);
|
||||
iht(objects::IMTQ_HANDLER, NML, 0, ACS_TABLE_PTG_TARGET_TGT.second);
|
||||
iht(objects::SUS_BOARD_ASS, NML, 0, ACS_TABLE_PTG_TARGET_TGT.second);
|
||||
iht(objects::ACS_BOARD_ASS, NML, 0, ACS_TABLE_PTG_TARGET_TGT.second);
|
||||
iht(objects::IMTQ_ASSY, NML, 0, ACS_TABLE_PTG_TARGET_TGT.second);
|
||||
iht(objects::SUS_BOARD_ASS, NML, 0, ACS_TABLE_PTG_TARGET_TGT.second, true);
|
||||
iht(objects::ACS_BOARD_ASS, NML, 0, ACS_TABLE_PTG_TARGET_TGT.second, true);
|
||||
iht(objects::RW_ASSY, NML, 0, ACS_TABLE_PTG_TARGET_TGT.second);
|
||||
iht(objects::STAR_TRACKER, NML, 0, ACS_TABLE_PTG_TARGET_TGT.second);
|
||||
iht(objects::STR_ASSY, NML, 0, ACS_TABLE_PTG_TARGET_TGT.second);
|
||||
check(ss.addTable(&ACS_TABLE_PTG_TARGET_TGT.second, ACS_TABLE_PTG_TARGET_TGT.first, false, true),
|
||||
ctxc);
|
||||
|
||||
// SUS board transition table is built above
|
||||
// Transition 0 already built
|
||||
// Build TARGET PT transition 1
|
||||
iht(objects::ACS_CONTROLLER, NML, acs::AcsMode::PTG_TARGET, ACS_TABLE_PTG_TARGET_TRANS_1.second);
|
||||
@ -373,7 +386,6 @@ void buildTargetPtSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
|
||||
// Build IDLE sequence
|
||||
ihs(ACS_SEQUENCE_PTG_TARGET.second, ACS_TABLE_PTG_TARGET_TGT.first, 0, true);
|
||||
ihs(ACS_SEQUENCE_PTG_TARGET.second, SUS_BOARD_NML_TRANS.first, 0, true);
|
||||
ihs(ACS_SEQUENCE_PTG_TARGET.second, ACS_TABLE_PTG_TRANS_0.first, 0, true);
|
||||
ihs(ACS_SEQUENCE_PTG_TARGET.second, ACS_TABLE_PTG_TARGET_TRANS_1.first, 0, true);
|
||||
check(ss.addSequence(&ACS_SEQUENCE_PTG_TARGET.second, ACS_SEQUENCE_PTG_TARGET.first,
|
||||
@ -386,10 +398,13 @@ void buildTargetPtNadirSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
auto ctxc = context.c_str();
|
||||
// Insert Helper Table
|
||||
auto iht = [&](object_id_t obj, Mode_t mode, Submode_t submode,
|
||||
ArrayList<ModeListEntry>& sequence) {
|
||||
ArrayList<ModeListEntry>& sequence, bool allowAllSubmodes = false) {
|
||||
eh.setObject(obj);
|
||||
eh.setMode(mode);
|
||||
eh.setSubmode(submode);
|
||||
if (allowAllSubmodes) {
|
||||
eh.allowAllSubmodes();
|
||||
}
|
||||
check(sequence.insert(eh), ctxc);
|
||||
};
|
||||
// Insert Helper Sequence
|
||||
@ -404,11 +419,11 @@ void buildTargetPtNadirSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
// Build TARGET PT table
|
||||
iht(objects::ACS_CONTROLLER, NML, acs::AcsMode::PTG_TARGET,
|
||||
ACS_TABLE_PTG_TARGET_NADIR_TGT.second);
|
||||
iht(objects::IMTQ_HANDLER, NML, 0, ACS_TABLE_PTG_TARGET_NADIR_TGT.second);
|
||||
iht(objects::SUS_BOARD_ASS, NML, 0, ACS_TABLE_PTG_TARGET_NADIR_TGT.second);
|
||||
iht(objects::ACS_BOARD_ASS, NML, 0, ACS_TABLE_PTG_TARGET_NADIR_TGT.second);
|
||||
iht(objects::IMTQ_ASSY, NML, 0, ACS_TABLE_PTG_TARGET_NADIR_TGT.second);
|
||||
iht(objects::SUS_BOARD_ASS, NML, 0, ACS_TABLE_PTG_TARGET_NADIR_TGT.second, true);
|
||||
iht(objects::ACS_BOARD_ASS, NML, 0, ACS_TABLE_PTG_TARGET_NADIR_TGT.second, true);
|
||||
iht(objects::RW_ASSY, NML, 0, ACS_TABLE_PTG_TARGET_NADIR_TGT.second);
|
||||
iht(objects::STAR_TRACKER, NML, 0, ACS_TABLE_PTG_TARGET_NADIR_TGT.second);
|
||||
iht(objects::STR_ASSY, NML, 0, ACS_TABLE_PTG_TARGET_NADIR_TGT.second);
|
||||
check(ss.addTable(TableEntry(ACS_TABLE_PTG_TARGET_NADIR_TGT.first,
|
||||
&ACS_TABLE_PTG_TARGET_NADIR_TGT.second)),
|
||||
ctxc);
|
||||
@ -437,10 +452,13 @@ void buildTargetPtGsSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
auto ctxc = context.c_str();
|
||||
// Insert Helper Table
|
||||
auto iht = [&](object_id_t obj, Mode_t mode, Submode_t submode,
|
||||
ArrayList<ModeListEntry>& sequence) {
|
||||
ArrayList<ModeListEntry>& sequence, bool allowAllSubmodes = false) {
|
||||
eh.setObject(obj);
|
||||
eh.setMode(mode);
|
||||
eh.setSubmode(submode);
|
||||
if (allowAllSubmodes) {
|
||||
eh.allowAllSubmodes();
|
||||
}
|
||||
check(sequence.insert(eh), ctxc);
|
||||
};
|
||||
// Insert Helper Sequence
|
||||
@ -455,11 +473,11 @@ void buildTargetPtGsSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
// Build TARGET PT table
|
||||
iht(objects::ACS_CONTROLLER, NML, acs::AcsMode::PTG_TARGET_GS,
|
||||
ACS_TABLE_PTG_TARGET_GS_TGT.second);
|
||||
iht(objects::IMTQ_HANDLER, NML, 0, ACS_TABLE_PTG_TARGET_GS_TGT.second);
|
||||
iht(objects::SUS_BOARD_ASS, NML, 0, ACS_TABLE_PTG_TARGET_GS_TGT.second);
|
||||
iht(objects::ACS_BOARD_ASS, NML, 0, ACS_TABLE_PTG_TARGET_GS_TGT.second);
|
||||
iht(objects::IMTQ_ASSY, NML, 0, ACS_TABLE_PTG_TARGET_GS_TGT.second);
|
||||
iht(objects::SUS_BOARD_ASS, NML, 0, ACS_TABLE_PTG_TARGET_GS_TGT.second, true);
|
||||
iht(objects::ACS_BOARD_ASS, NML, 0, ACS_TABLE_PTG_TARGET_GS_TGT.second, true);
|
||||
iht(objects::RW_ASSY, NML, 0, ACS_TABLE_PTG_TARGET_GS_TGT.second);
|
||||
iht(objects::STAR_TRACKER, NML, 0, ACS_TABLE_PTG_TARGET_GS_TGT.second);
|
||||
iht(objects::STR_ASSY, NML, 0, ACS_TABLE_PTG_TARGET_GS_TGT.second);
|
||||
check(ss.addTable(
|
||||
TableEntry(ACS_TABLE_PTG_TARGET_GS_TGT.first, &ACS_TABLE_PTG_TARGET_GS_TGT.second)),
|
||||
ctxc);
|
||||
@ -487,10 +505,13 @@ void buildTargetPtInertialSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
auto ctxc = context.c_str();
|
||||
// Insert Helper Table
|
||||
auto iht = [&](object_id_t obj, Mode_t mode, Submode_t submode,
|
||||
ArrayList<ModeListEntry>& sequence) {
|
||||
ArrayList<ModeListEntry>& sequence, bool allowAllSubmodes = false) {
|
||||
eh.setObject(obj);
|
||||
eh.setMode(mode);
|
||||
eh.setSubmode(submode);
|
||||
if (allowAllSubmodes) {
|
||||
eh.allowAllSubmodes();
|
||||
}
|
||||
check(sequence.insert(eh), ctxc);
|
||||
};
|
||||
// Insert Helper Sequence
|
||||
@ -505,11 +526,11 @@ void buildTargetPtInertialSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
// Build TARGET PT table
|
||||
iht(objects::ACS_CONTROLLER, NML, acs::AcsMode::PTG_INERTIAL,
|
||||
ACS_TABLE_PTG_TARGET_INERTIAL_TGT.second);
|
||||
iht(objects::IMTQ_HANDLER, NML, 0, ACS_TABLE_PTG_TARGET_INERTIAL_TGT.second);
|
||||
iht(objects::SUS_BOARD_ASS, NML, 0, ACS_TABLE_PTG_TARGET_INERTIAL_TGT.second);
|
||||
iht(objects::ACS_BOARD_ASS, NML, 0, ACS_TABLE_PTG_TARGET_INERTIAL_TGT.second);
|
||||
iht(objects::IMTQ_ASSY, NML, 0, ACS_TABLE_PTG_TARGET_INERTIAL_TGT.second);
|
||||
iht(objects::SUS_BOARD_ASS, NML, 0, ACS_TABLE_PTG_TARGET_INERTIAL_TGT.second, true);
|
||||
iht(objects::ACS_BOARD_ASS, NML, 0, ACS_TABLE_PTG_TARGET_INERTIAL_TGT.second, true);
|
||||
iht(objects::RW_ASSY, NML, 0, ACS_TABLE_PTG_TARGET_INERTIAL_TGT.second);
|
||||
iht(objects::STAR_TRACKER, NML, 0, ACS_TABLE_PTG_TARGET_INERTIAL_TGT.second);
|
||||
iht(objects::STR_ASSY, NML, 0, ACS_TABLE_PTG_TARGET_INERTIAL_TGT.second);
|
||||
check(ss.addTable(TableEntry(ACS_TABLE_PTG_TARGET_INERTIAL_TGT.first,
|
||||
&ACS_TABLE_PTG_TARGET_INERTIAL_TGT.second)),
|
||||
ctxc);
|
||||
|
@ -11,8 +11,9 @@ extern ComSubsystem SUBSYSTEM;
|
||||
|
||||
// The syrlinks must not transmitting longer then 15 minutes otherwise the
|
||||
// transceiver might be damaged due to overheating
|
||||
// 15 minutes in milliseconds
|
||||
static const uint32_t TRANSMITTER_TIMEOUT = 900000;
|
||||
// This is the initial timeout of 2 minutes. The timeout needs to be incremented
|
||||
// before each overpass
|
||||
static const uint32_t TRANSMITTER_TIMEOUT = 120000;
|
||||
|
||||
Subsystem& init();
|
||||
} // namespace com
|
||||
|
@ -62,10 +62,14 @@ void buildSafeSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
std::string context = "satsystem::buildSafeSequence";
|
||||
auto ctxc = context.c_str();
|
||||
// Insert Helper Table
|
||||
auto iht = [&](object_id_t obj, Mode_t mode, Submode_t submode, ArrayList<ModeListEntry>& table) {
|
||||
auto iht = [&](object_id_t obj, Mode_t mode, Submode_t submode, ArrayList<ModeListEntry>& table,
|
||||
bool allowAllSubmodes = false) {
|
||||
eh.setObject(obj);
|
||||
eh.setMode(mode);
|
||||
eh.setSubmode(submode);
|
||||
if (allowAllSubmodes) {
|
||||
eh.allowAllSubmodes();
|
||||
}
|
||||
check(table.insert(eh), ctxc);
|
||||
};
|
||||
// Insert Helper Sequence
|
||||
@ -79,7 +83,9 @@ void buildSafeSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
|
||||
// Do no track ACS for now because it might jump to detumble mode and back to safe as part of
|
||||
// normal operations.
|
||||
// iht(objects::ACS_SUBSYSTEM, acs::AcsMode::SAFE, 0, EIVE_TABLE_SAFE_TGT.second);
|
||||
// UPDATE: This could be re-enabled as soon as the detumble mode is a submode of
|
||||
// ACS CTRL safe mode.
|
||||
// iht(objects::ACS_SUBSYSTEM, acs::AcsMode::SAFE, 0, EIVE_TABLE_SAFE_TGT.second, true);
|
||||
iht(objects::PL_SUBSYSTEM, OFF, 0, EIVE_TABLE_SAFE_TGT.second);
|
||||
check(ss.addTable(TableEntry(EIVE_TABLE_SAFE_TGT.first, &EIVE_TABLE_SAFE_TGT.second)), ctxc);
|
||||
|
||||
@ -88,18 +94,13 @@ void buildSafeSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
iht(objects::TCS_SUBSYSTEM, NML, 0, EIVE_TABLE_SAFE_TRANS_0.second);
|
||||
iht(objects::COM_SUBSYSTEM, com::RX_ONLY, 0, EIVE_TABLE_SAFE_TRANS_0.second);
|
||||
iht(objects::PL_SUBSYSTEM, OFF, 0, EIVE_TABLE_SAFE_TRANS_0.second);
|
||||
iht(objects::ACS_SUBSYSTEM, acs::AcsMode::SAFE, 0, EIVE_TABLE_SAFE_TRANS_0.second);
|
||||
iht(objects::ACS_SUBSYSTEM, acs::AcsMode::SAFE, 0, EIVE_TABLE_SAFE_TRANS_0.second, true);
|
||||
check(ss.addTable(TableEntry(EIVE_TABLE_SAFE_TRANS_0.first, &EIVE_TABLE_SAFE_TRANS_0.second)),
|
||||
ctxc);
|
||||
|
||||
// Build SAFE transition 1
|
||||
// check(ss.addTable(TableEntry(EIVE_TABLE_SAFE_TRANS_1.first, &EIVE_TABLE_SAFE_TRANS_1.second)),
|
||||
// ctxc);
|
||||
|
||||
// Build Safe sequence
|
||||
ihs(EIVE_SEQUENCE_SAFE.second, EIVE_TABLE_SAFE_TGT.first, 0, false);
|
||||
ihs(EIVE_SEQUENCE_SAFE.second, EIVE_TABLE_SAFE_TRANS_0.first, 0, false);
|
||||
// ihs(EIVE_SEQUENCE_SAFE.second, EIVE_TABLE_SAFE_TRANS_1.first, 0, false);
|
||||
check(ss.addSequence(SequenceEntry(EIVE_SEQUENCE_SAFE.first, &EIVE_SEQUENCE_SAFE.second,
|
||||
EIVE_SEQUENCE_SAFE.first)),
|
||||
ctxc);
|
||||
@ -127,21 +128,16 @@ void buildIdleSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
iht(objects::ACS_SUBSYSTEM, acs::AcsMode::PTG_IDLE, 0, EIVE_TABLE_IDLE_TGT.second);
|
||||
check(ss.addTable(TableEntry(EIVE_TABLE_IDLE_TGT.first, &EIVE_TABLE_IDLE_TGT.second)), ctxc);
|
||||
|
||||
// Build SAFE transition 0
|
||||
// Build IDLE transition 0
|
||||
iht(objects::TCS_SUBSYSTEM, NML, 0, EIVE_TABLE_IDLE_TRANS_0.second);
|
||||
iht(objects::PL_SUBSYSTEM, OFF, 0, EIVE_TABLE_IDLE_TRANS_1.second);
|
||||
iht(objects::ACS_SUBSYSTEM, acs::AcsMode::PTG_IDLE, 0, EIVE_TABLE_IDLE_TRANS_1.second);
|
||||
iht(objects::PL_SUBSYSTEM, OFF, 0, EIVE_TABLE_IDLE_TRANS_0.second);
|
||||
iht(objects::ACS_SUBSYSTEM, acs::AcsMode::PTG_IDLE, 0, EIVE_TABLE_IDLE_TRANS_0.second);
|
||||
check(ss.addTable(TableEntry(EIVE_TABLE_IDLE_TRANS_0.first, &EIVE_TABLE_IDLE_TRANS_0.second)),
|
||||
ctxc);
|
||||
|
||||
// Build SAFE transition 1
|
||||
// check(ss.addTable(TableEntry(EIVE_TABLE_IDLE_TRANS_1.first, &EIVE_TABLE_IDLE_TRANS_1.second)),
|
||||
// ctxc);
|
||||
|
||||
// Build Safe sequence
|
||||
// Build IDLE sequence
|
||||
ihs(EIVE_SEQUENCE_IDLE.second, EIVE_TABLE_IDLE_TGT.first, 0, false);
|
||||
ihs(EIVE_SEQUENCE_IDLE.second, EIVE_TABLE_IDLE_TRANS_0.first, 0, false);
|
||||
// ihs(EIVE_SEQUENCE_IDLE.second, EIVE_TABLE_IDLE_TRANS_1.first, 0, false);
|
||||
check(ss.addSequence(SequenceEntry(EIVE_SEQUENCE_IDLE.first, &EIVE_SEQUENCE_IDLE.second,
|
||||
EIVE_SEQUENCE_SAFE.first)),
|
||||
ctxc);
|
||||
|
@ -19,8 +19,8 @@ static const auto NML = DeviceHandlerIF::MODE_NORMAL;
|
||||
|
||||
auto TCS_SEQUENCE_OFF = std::make_pair(OFF, FixedArrayList<ModeListEntry, 3>());
|
||||
auto TCS_TABLE_OFF_TGT = std::make_pair((OFF << 24) | 1, FixedArrayList<ModeListEntry, 2>());
|
||||
auto TCS_TABLE_OFF_TRANS_0 = std::make_pair((OFF << 24) | 2, FixedArrayList<ModeListEntry, 7>());
|
||||
auto TCS_TABLE_OFF_TRANS_1 = std::make_pair((OFF << 24) | 3, FixedArrayList<ModeListEntry, 2>());
|
||||
auto TCS_TABLE_OFF_TRANS_0 = std::make_pair((OFF << 24) | 2, FixedArrayList<ModeListEntry, 2>());
|
||||
auto TCS_TABLE_OFF_TRANS_1 = std::make_pair((OFF << 24) | 3, FixedArrayList<ModeListEntry, 7>());
|
||||
|
||||
auto TCS_SEQUENCE_NORMAL = std::make_pair(NML, FixedArrayList<ModeListEntry, 3>());
|
||||
auto TCS_TABLE_NORMAL_TGT = std::make_pair((NML << 24) | 1, FixedArrayList<ModeListEntry, 2>());
|
||||
@ -59,16 +59,16 @@ void buildOffSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
// OFF target table is empty
|
||||
check(ss.addTable(TableEntry(TCS_TABLE_OFF_TGT.first, &TCS_TABLE_OFF_TGT.second)), ctxc);
|
||||
|
||||
iht(objects::TCS_BOARD_ASS, OFF, 0, TCS_TABLE_OFF_TRANS_0.second);
|
||||
iht(objects::TMP1075_HANDLER_TCS_0, OFF, 0, TCS_TABLE_OFF_TRANS_0.second);
|
||||
iht(objects::TMP1075_HANDLER_TCS_1, OFF, 0, TCS_TABLE_OFF_TRANS_0.second);
|
||||
iht(objects::TMP1075_HANDLER_PLPCDU_0, OFF, 0, TCS_TABLE_OFF_TRANS_0.second);
|
||||
// damaged
|
||||
// iht(objects::TMP1075_HANDLER_PLPCDU_1, OFF, 0, TCS_TABLE_OFF_TRANS_0.second);
|
||||
iht(objects::TMP1075_HANDLER_IF_BOARD, OFF, 0, TCS_TABLE_OFF_TRANS_0.second);
|
||||
// Transition 1
|
||||
iht(objects::THERMAL_CONTROLLER, OFF, 0, TCS_TABLE_OFF_TRANS_0.second);
|
||||
check(ss.addTable(TableEntry(TCS_TABLE_OFF_TRANS_0.first, &TCS_TABLE_OFF_TRANS_0.second)), ctxc);
|
||||
|
||||
iht(objects::THERMAL_CONTROLLER, OFF, 0, TCS_TABLE_OFF_TRANS_0.second);
|
||||
iht(objects::TCS_BOARD_ASS, OFF, 0, TCS_TABLE_OFF_TRANS_1.second);
|
||||
iht(objects::TMP1075_HANDLER_TCS_0, OFF, 0, TCS_TABLE_OFF_TRANS_1.second);
|
||||
iht(objects::TMP1075_HANDLER_TCS_1, OFF, 0, TCS_TABLE_OFF_TRANS_1.second);
|
||||
iht(objects::TMP1075_HANDLER_PLPCDU_0, OFF, 0, TCS_TABLE_OFF_TRANS_1.second);
|
||||
// TMP PL PCDU 1 is damaged
|
||||
iht(objects::TMP1075_HANDLER_IF_BOARD, OFF, 0, TCS_TABLE_OFF_TRANS_1.second);
|
||||
check(ss.addTable(TableEntry(TCS_TABLE_OFF_TRANS_1.first, &TCS_TABLE_OFF_TRANS_1.second)), ctxc);
|
||||
|
||||
ihs(TCS_SEQUENCE_OFF.second, TCS_TABLE_OFF_TGT.first, 0, false);
|
||||
@ -98,20 +98,20 @@ void buildNormalSequence(Subsystem& ss, ModeListEntry& eh) {
|
||||
check(sequence.insert(eh), ctxc);
|
||||
};
|
||||
|
||||
// OFF target table is empty
|
||||
// Normal target table is empty
|
||||
check(ss.addTable(TableEntry(TCS_TABLE_NORMAL_TGT.first, &TCS_TABLE_NORMAL_TGT.second)), ctxc);
|
||||
|
||||
iht(objects::TCS_BOARD_ASS, NML, 0, TCS_TABLE_NORMAL_TRANS_0.second);
|
||||
iht(objects::TMP1075_HANDLER_TCS_0, NML, 0, TCS_TABLE_NORMAL_TRANS_0.second);
|
||||
iht(objects::TMP1075_HANDLER_TCS_1, NML, 0, TCS_TABLE_NORMAL_TRANS_0.second);
|
||||
iht(objects::TMP1075_HANDLER_PLPCDU_0, NML, 0, TCS_TABLE_NORMAL_TRANS_0.second);
|
||||
// damaged
|
||||
// iht(objects::TMP1075_HANDLER_PLPCDU_1, NML, 0, TCS_TABLE_NORMAL_TRANS_0.second);
|
||||
// TMP PL PCDU 1 is damaged
|
||||
iht(objects::TMP1075_HANDLER_IF_BOARD, NML, 0, TCS_TABLE_NORMAL_TRANS_0.second);
|
||||
check(ss.addTable(TableEntry(TCS_TABLE_NORMAL_TRANS_0.first, &TCS_TABLE_NORMAL_TRANS_0.second)),
|
||||
ctxc);
|
||||
|
||||
iht(objects::THERMAL_CONTROLLER, NML, 0, TCS_TABLE_NORMAL_TRANS_0.second);
|
||||
// Transition 1
|
||||
iht(objects::THERMAL_CONTROLLER, NML, 0, TCS_TABLE_NORMAL_TRANS_1.second);
|
||||
check(ss.addTable(TableEntry(TCS_TABLE_NORMAL_TRANS_1.first, &TCS_TABLE_NORMAL_TRANS_1.second)),
|
||||
ctxc);
|
||||
|
||||
|
@ -28,35 +28,6 @@ PersistentTmStore::PersistentTmStore(object_id_t objectId, const char* baseDir,
|
||||
}
|
||||
|
||||
ReturnValue_t PersistentTmStore::assignAndOrCreateMostRecentFile() {
|
||||
using namespace std::filesystem;
|
||||
for (auto const& file : directory_iterator(basePath)) {
|
||||
if (file.is_directory()) {
|
||||
continue;
|
||||
}
|
||||
auto pathStr = file.path().string();
|
||||
if (pathStr.find(baseName) == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
unsigned int underscorePos = pathStr.find_last_of('_');
|
||||
std::string stampStr = pathStr.substr(underscorePos + 1);
|
||||
struct tm time {};
|
||||
if (nullptr == strptime(stampStr.c_str(), FILE_DATE_FORMAT, &time)) {
|
||||
sif::error << "PersistentTmStore::assignOrCreateMostRecentFile: Error reading timestamp"
|
||||
<< std::endl;
|
||||
// Delete the file and re-create it.
|
||||
activeFile = std::nullopt;
|
||||
std::filesystem::remove(file.path());
|
||||
break;
|
||||
}
|
||||
time_t fileEpoch = timegm(&time);
|
||||
// There is still a file within the active time window, so re-use that file for new TMs to
|
||||
// store.
|
||||
if (fileEpoch + static_cast<time_t>(rolloverDiffSeconds) > currentTv.tv_sec) {
|
||||
activeFileTv.tv_sec = fileEpoch;
|
||||
activeFile = file.path();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (not activeFile.has_value()) {
|
||||
return createMostRecentFile(std::nullopt);
|
||||
}
|
||||
@ -203,7 +174,8 @@ bool PersistentTmStore::updateBaseDir() {
|
||||
return false;
|
||||
}
|
||||
basePath = path(currentPrefix) / baseDir / baseName;
|
||||
if (not exists(basePath)) {
|
||||
std::error_code e;
|
||||
if (not exists(basePath, e)) {
|
||||
create_directories(basePath);
|
||||
}
|
||||
baseDirUninitialized = false;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <fsfw/serviceinterface/ServiceInterfaceStream.h>
|
||||
#include <fsfw/storagemanager/StorageManagerIF.h>
|
||||
#include <fsfw/tasks/ExecutableObjectIF.h>
|
||||
#include <mission/memory/NvmParameterBase.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
@ -22,7 +23,6 @@
|
||||
#include "OBSWConfig.h"
|
||||
#include "fsfw/parameters/HasParametersIF.h"
|
||||
#include "fsfw/parameters/ParameterHelper.h"
|
||||
#include "mission/memory/NVMParameterBase.h"
|
||||
|
||||
static std::map<ParamIds, std::string> PARAM_KEY_MAP = {
|
||||
{PARAM0, "Parameter0"},
|
||||
|
@ -4,6 +4,7 @@ if [[ ! -f README.md ]]; then
|
||||
fi
|
||||
|
||||
folder_list=(
|
||||
"./watchdog"
|
||||
"./mission"
|
||||
"./linux"
|
||||
"./bsp_q7s"
|
||||
|
@ -1,11 +1,11 @@
|
||||
#ifndef BSP_Q7S_CORE_NVMPARAMS_PARAMETERDEFINITIONS_H_
|
||||
#define BSP_Q7S_CORE_NVMPARAMS_PARAMETERDEFINITIONS_H_
|
||||
|
||||
#include <mission/memory/NvmParameterBase.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include "mission/memory/NVMParameterBase.h"
|
||||
|
||||
class DummyParameter : public NVMParameterBase {
|
||||
public:
|
||||
static constexpr char DUMMY_KEY_PARAM_1[] = "dummy1";
|
||||
|
2
thirdparty/arcsec_star_tracker
vendored
2
thirdparty/arcsec_star_tracker
vendored
Submodule thirdparty/arcsec_star_tracker updated: 93e93965e2...42907c36c5
2
tmtc
2
tmtc
Submodule tmtc updated: 94ae2d16e2...a3e03350fa
@ -1,10 +1,5 @@
|
||||
target_sources(${WATCHDOG_NAME} PRIVATE
|
||||
main.cpp
|
||||
Watchdog.cpp
|
||||
)
|
||||
target_sources(${WATCHDOG_NAME} PRIVATE main.cpp Watchdog.cpp)
|
||||
|
||||
target_include_directories(${WATCHDOG_NAME} PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
target_include_directories(${WATCHDOG_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
install(TARGETS ${WATCHDOG_NAME} RUNTIME DESTINATION bin)
|
||||
|
@ -1,258 +1,304 @@
|
||||
#include "Watchdog.h"
|
||||
#include "definitions.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <thread>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
#include "definitions.h"
|
||||
|
||||
WatchdogTask::WatchdogTask (): fd(0) {
|
||||
int result = 0;
|
||||
// Only create the FIFO if it does not exist yet
|
||||
if(not std::filesystem::exists(watchdog::FIFO_NAME)) {
|
||||
// Permission 666 or rw-rw-rw-
|
||||
mode_t mode = DEFFILEMODE;
|
||||
result = mkfifo(watchdog::FIFO_NAME.c_str(), mode);
|
||||
if(result != 0) {
|
||||
std::cerr << "eive-watchdog: Could not created named pipe at " <<
|
||||
watchdog::FIFO_NAME << ", error " << errno << ": " << strerror(errno) <<
|
||||
std::endl;
|
||||
throw std::runtime_error("eive-watchdog: FIFO creation failed");
|
||||
}
|
||||
#if WATCHDOG_VERBOSE_LEVEL >= 1
|
||||
std::cout << "eive-watchdog: Pipe at " << watchdog::FIFO_NAME <<
|
||||
" created successfully" << std::endl;
|
||||
#endif
|
||||
WatchdogTask::WatchdogTask() : fd(0) {
|
||||
int result = 0;
|
||||
std::error_code e;
|
||||
// Only create the FIFO if it does not exist yet
|
||||
if (not std::filesystem::exists(watchdog::FIFO_NAME, e)) {
|
||||
// Permission 666 or rw-rw-rw-
|
||||
mode_t mode = DEFFILEMODE;
|
||||
result = mkfifo(watchdog::FIFO_NAME.c_str(), mode);
|
||||
if (result != 0) {
|
||||
std::cerr << "Could not created named pipe at " << watchdog::FIFO_NAME << ", error " << errno
|
||||
<< ": " << strerror(errno) << std::endl;
|
||||
throw std::runtime_error("eive-watchdog: FIFO creation failed");
|
||||
}
|
||||
#if WATCHDOG_VERBOSE_LEVEL >= 1
|
||||
std::cout << "Pipe at " << watchdog::FIFO_NAME << " created successfully" << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
WatchdogTask::~WatchdogTask() {
|
||||
|
||||
}
|
||||
WatchdogTask::~WatchdogTask() {}
|
||||
|
||||
int WatchdogTask::performOperation() {
|
||||
// Open FIFO read only and non-blocking
|
||||
fd = open(watchdog::FIFO_NAME.c_str(), O_RDONLY | O_NONBLOCK);
|
||||
if(fd < 0) {
|
||||
std::cerr << "eive-watchdog: Opening pipe " << watchdog::FIFO_NAME <<
|
||||
"read-only failed with " << errno << ": " << strerror(errno) << std::endl;
|
||||
return -1;
|
||||
// Open FIFO read only and non-blocking
|
||||
fd = open(watchdog::FIFO_NAME.c_str(), O_RDONLY | O_NONBLOCK);
|
||||
if (fd < 0) {
|
||||
std::cerr << "Opening pipe " << watchdog::FIFO_NAME << "read-only failed with " << errno << ": "
|
||||
<< strerror(errno) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
// Clear FIFO by reading until it is empty.
|
||||
while (true) {
|
||||
ssize_t readBytes = read(fd, buf.data(), buf.size());
|
||||
if (readBytes < 0) {
|
||||
std::cerr << "Read error of FIFO: " << strerror(errno) << std::endl;
|
||||
} else if (readBytes == 0) {
|
||||
break;
|
||||
}
|
||||
state = States::RUNNING;
|
||||
}
|
||||
state = States::NOT_STARTED;
|
||||
|
||||
while(true) {
|
||||
WatchdogTask::LoopResult loopResult = watchdogLoop();
|
||||
switch(loopResult) {
|
||||
case(LoopResult::OK): {
|
||||
performRunningOperation();
|
||||
break;
|
||||
}
|
||||
case(LoopResult::CANCEL_RQ): {
|
||||
std::cout << "eive-watchdog: Received cancel request, closing watchdog.." << std::endl;
|
||||
return 0;
|
||||
}
|
||||
case(LoopResult::SUSPEND_RQ): {
|
||||
performSuspendOperation();
|
||||
break;
|
||||
}
|
||||
case(LoopResult::TIMEOUT): {
|
||||
performNotRunningOperation(loopResult);
|
||||
break;
|
||||
}
|
||||
case(LoopResult::HUNG_UP): {
|
||||
performNotRunningOperation(loopResult);
|
||||
break;
|
||||
}
|
||||
case(LoopResult::RESTART_RQ): {
|
||||
if(state == States::SUSPENDED or state == States::FAULTY) {
|
||||
performRunningOperation();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case(LoopResult::FAULT): {
|
||||
using namespace std::chrono_literals;
|
||||
// Configuration error
|
||||
std::cerr << "Fault has occured in watchdog loop" << std::endl;
|
||||
// Prevent spam
|
||||
std::this_thread::sleep_for(2000ms);
|
||||
|
||||
}
|
||||
}
|
||||
bool breakOuter = false;
|
||||
while (true) {
|
||||
watchdogLoop();
|
||||
while (not resultQueue.empty()) {
|
||||
auto nextRequest = resultQueue.front();
|
||||
if (not stateMachine(nextRequest)) {
|
||||
breakOuter = true;
|
||||
resultQueue.pop();
|
||||
break;
|
||||
}
|
||||
resultQueue.pop();
|
||||
}
|
||||
if (close(fd) < 0) {
|
||||
std::cerr << "eive-watchdog: Closing named pipe at " << watchdog::FIFO_NAME <<
|
||||
"failed, error " << errno << ": " << strerror(errno) << std::endl;
|
||||
if (breakOuter) {
|
||||
break;
|
||||
}
|
||||
std::cout << "eive-watchdog: Finished" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
if (close(fd) < 0) {
|
||||
std::cerr << "Closing named pipe at " << watchdog::FIFO_NAME << "failed, error " << errno
|
||||
<< ": " << strerror(errno) << std::endl;
|
||||
}
|
||||
std::cout << "Closing" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
WatchdogTask::LoopResult WatchdogTask::watchdogLoop() {
|
||||
using namespace std::chrono_literals;
|
||||
struct pollfd waiter = {};
|
||||
waiter.fd = fd;
|
||||
waiter.events = POLLIN;
|
||||
void WatchdogTask::watchdogLoop() {
|
||||
using namespace std::chrono_literals;
|
||||
struct pollfd waiter = {};
|
||||
waiter.fd = fd;
|
||||
waiter.events = POLLIN;
|
||||
|
||||
switch(state) {
|
||||
case(States::SUSPENDED): {
|
||||
// Sleep, then check whether a restart request was received
|
||||
std::this_thread::sleep_for(1000ms);
|
||||
break;
|
||||
// Only poll one file descriptor with timeout
|
||||
switch (poll(&waiter, 1, watchdog::TIMEOUT_MS)) {
|
||||
case (0): {
|
||||
resultQueue.push(LoopResult::TIMEOUT);
|
||||
return;
|
||||
}
|
||||
case(States::RUNNING): {
|
||||
// Continue as usual
|
||||
break;
|
||||
}
|
||||
case(States::NOT_STARTED): {
|
||||
// This should not happen
|
||||
std::cerr << "eive-watchdog: State is NOT_STARTED, configuration error" << std::endl;
|
||||
break;
|
||||
}
|
||||
case(States::FAULTY): {
|
||||
// TODO: Not sure what to do yet. Continue for now
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 10 seconds timeout, only poll one file descriptor
|
||||
switch(poll(&waiter, 1, watchdog::TIMEOUT_MS)) {
|
||||
case(0): {
|
||||
return LoopResult::TIMEOUT;
|
||||
}
|
||||
case(1): {
|
||||
return pollEvent(waiter);
|
||||
case (1): {
|
||||
pollEvent(waiter);
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
std::cerr << "eive-watchdog: Unknown poll error at " << watchdog::FIFO_NAME << ", error " <<
|
||||
errno << ": " << strerror(errno) << std::endl;
|
||||
break;
|
||||
std::cerr << "Unknown poll error at " << watchdog::FIFO_NAME << ", error " << errno << ": "
|
||||
<< strerror(errno) << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return LoopResult::OK;
|
||||
}
|
||||
}
|
||||
|
||||
WatchdogTask::LoopResult WatchdogTask::pollEvent(struct pollfd& waiter) {
|
||||
if (waiter.revents & POLLIN) {
|
||||
ssize_t readLen = read(fd, buf.data(), buf.size());
|
||||
if (readLen < 0) {
|
||||
std::cerr << "eive-watchdog: Read error on pipe " << watchdog::FIFO_NAME <<
|
||||
", error " << errno << ": " << strerror(errno) << std::endl;
|
||||
return LoopResult::OK;
|
||||
}
|
||||
void WatchdogTask::pollEvent(struct pollfd& waiter) {
|
||||
if (waiter.revents & POLLIN) {
|
||||
ssize_t readLen = read(fd, buf.data(), buf.size());
|
||||
#if WATCHDOG_VERBOSE_LEVEL == 2
|
||||
std::cout << "Read " << readLen << " byte(s) on the pipe " << FIFO_NAME
|
||||
<< std::endl;
|
||||
std::cout << "Read " << readLen << " byte(s) on the pipe " << watchdog::FIFO_NAME << std::endl;
|
||||
#endif
|
||||
else if(readLen >= 1) {
|
||||
return parseCommandByte(readLen);
|
||||
}
|
||||
if (readLen < 0) {
|
||||
std::cerr << "Read error on pipe " << watchdog::FIFO_NAME << ", error " << errno << ": "
|
||||
<< strerror(errno) << std::endl;
|
||||
resultQueue.push(LoopResult::OK);
|
||||
} else if (readLen >= 1) {
|
||||
parseCommands(readLen);
|
||||
}
|
||||
|
||||
}
|
||||
else if(waiter.revents & POLLERR) {
|
||||
std::cerr << "eive-watchdog: Poll error error on pipe " << watchdog::FIFO_NAME <<
|
||||
std::endl;
|
||||
return LoopResult::FAULT;
|
||||
}
|
||||
else if (waiter.revents & POLLHUP) {
|
||||
// Writer closed its end
|
||||
return LoopResult::HUNG_UP;
|
||||
}
|
||||
return LoopResult::FAULT;
|
||||
} else if (waiter.revents & POLLERR) {
|
||||
std::cerr << "Poll error error on pipe " << watchdog::FIFO_NAME << std::endl;
|
||||
resultQueue.push(LoopResult::FAULT);
|
||||
} else if (waiter.revents & POLLHUP) {
|
||||
// Writer closed its end
|
||||
resultQueue.push(LoopResult::HUNG_UP);
|
||||
}
|
||||
}
|
||||
|
||||
WatchdogTask::LoopResult WatchdogTask::parseCommandByte(ssize_t readLen) {
|
||||
for(ssize_t idx = 0; idx < readLen; idx++) {
|
||||
char readChar = buf[idx];
|
||||
// Cancel request
|
||||
if(readChar == watchdog::CANCEL_CHAR) {
|
||||
return LoopResult::CANCEL_RQ;
|
||||
}
|
||||
// Begin request. Does not work if the operation was not suspended before
|
||||
else if(readChar == watchdog::RESTART_CHAR) {
|
||||
return LoopResult::RESTART_RQ;
|
||||
}
|
||||
// Suspend request
|
||||
else if(readChar == watchdog::SUSPEND_CHAR) {
|
||||
return LoopResult::SUSPEND_RQ;
|
||||
}
|
||||
// Everything else: All working as expected
|
||||
void WatchdogTask::parseCommands(ssize_t readLen) {
|
||||
for (ssize_t idx = 0; idx < readLen; idx++) {
|
||||
char nextChar = buf[idx];
|
||||
// Cancel request
|
||||
if (nextChar == watchdog::first::CANCEL_CHAR) {
|
||||
resultQueue.push(LoopResult::CANCEL_REQ);
|
||||
} else if (nextChar == watchdog::first::SUSPEND_CHAR) {
|
||||
// Suspend request
|
||||
resultQueue.push(LoopResult::SUSPEND_REQ);
|
||||
} else if (nextChar == watchdog::first::START_CHAR) {
|
||||
if (idx < readLen - 1 and static_cast<char>(buf[idx + 1]) == watchdog::second::WATCH_FLAG) {
|
||||
resultQueue.push(LoopResult::START_WITH_WATCH_REQ);
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
resultQueue.push(LoopResult::START_REQ);
|
||||
} else if (nextChar == watchdog::first::IDLE_CHAR) {
|
||||
resultQueue.push(LoopResult::OK);
|
||||
}
|
||||
return LoopResult::OK;
|
||||
}
|
||||
// Everything else: All working as expected
|
||||
}
|
||||
|
||||
int WatchdogTask::performRunningOperation() {
|
||||
if(state != States::RUNNING) {
|
||||
state = States::RUNNING;
|
||||
if (state != States::RUNNING) {
|
||||
state = States::RUNNING;
|
||||
}
|
||||
if (notRunningStart.has_value()) {
|
||||
notRunningStart = std::nullopt;
|
||||
}
|
||||
|
||||
if (not obswRunning) {
|
||||
if (printNotRunningLatch) {
|
||||
// Reset latch so user can see timeouts
|
||||
printNotRunningLatch = false;
|
||||
}
|
||||
|
||||
if(not obswRunning) {
|
||||
if(printNotRunningLatch) {
|
||||
// Reset latch so user can see timeouts
|
||||
printNotRunningLatch = false;
|
||||
}
|
||||
|
||||
obswRunning = true;
|
||||
std::cout << "eive-watchdog: Running OBSW detected.." << std::endl;
|
||||
obswRunning = true;
|
||||
std::cout << "OBSW is running" << std::endl;
|
||||
#if WATCHDOG_CREATE_FILE_IF_RUNNING == 1
|
||||
std::cout << "eive-watchdog: Creating " << watchdog::RUNNING_FILE_NAME << std::endl;
|
||||
if (not std::filesystem::exists(watchdog::RUNNING_FILE_NAME)) {
|
||||
std::ofstream obswRunningFile(watchdog::RUNNING_FILE_NAME);
|
||||
if(not obswRunningFile.good()) {
|
||||
std::cerr << "Creating file " << watchdog::RUNNING_FILE_NAME << " failed"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
std::cout << "Creating " << watchdog::RUNNING_FILE_NAME << std::endl;
|
||||
std::error_code e;
|
||||
if (not std::filesystem::exists(watchdog::RUNNING_FILE_NAME, e)) {
|
||||
std::ofstream obswRunningFile(watchdog::RUNNING_FILE_NAME);
|
||||
if (not obswRunningFile.good()) {
|
||||
std::cerr << "Creating file " << watchdog::RUNNING_FILE_NAME << " failed" << std::endl;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WatchdogTask::performNotRunningOperation(LoopResult type) {
|
||||
// Latch prevents spam on console
|
||||
if(not printNotRunningLatch) {
|
||||
if(type == LoopResult::HUNG_UP) {
|
||||
std::cout << "eive-watchdog: FIFO writer hung up!" << std::endl;
|
||||
}
|
||||
else {
|
||||
std::cout << "eive-watchdog: The FIFO timed out!" << std::endl;
|
||||
}
|
||||
printNotRunningLatch = true;
|
||||
// Latch prevents spam on console
|
||||
if (not printNotRunningLatch) {
|
||||
if (type == LoopResult::HUNG_UP) {
|
||||
std::cout << "OBSW hung up" << std::endl;
|
||||
} else {
|
||||
std::cout << "The FIFO timed out, OBSW might not be running" << std::endl;
|
||||
}
|
||||
printNotRunningLatch = true;
|
||||
}
|
||||
|
||||
if(obswRunning) {
|
||||
if (not notRunningStart.has_value()) {
|
||||
notRunningStart = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
if (obswRunning) {
|
||||
#if WATCHDOG_CREATE_FILE_IF_RUNNING == 1
|
||||
if (std::filesystem::exists(watchdog::RUNNING_FILE_NAME)) {
|
||||
int result = std::remove(watchdog::RUNNING_FILE_NAME.c_str());
|
||||
if(result != 0) {
|
||||
std::cerr << "Removing " << watchdog::RUNNING_FILE_NAME << " failed with code " <<
|
||||
errno << ": " << strerror(errno) << std::endl;
|
||||
}
|
||||
}
|
||||
std::cout << "Removing " << watchdog::RUNNING_FILE_NAME << std::endl;
|
||||
std::error_code e;
|
||||
if (std::filesystem::exists(watchdog::RUNNING_FILE_NAME, e)) {
|
||||
int result = std::remove(watchdog::RUNNING_FILE_NAME.c_str());
|
||||
if (result != 0) {
|
||||
std::cerr << "Removing " << watchdog::RUNNING_FILE_NAME << " failed with code " << errno
|
||||
<< ": " << strerror(errno) << std::endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
obswRunning = false;
|
||||
obswRunning = false;
|
||||
}
|
||||
|
||||
if (watchingObsw) {
|
||||
auto timeNotRunning = std::chrono::steady_clock::now() - notRunningStart.value();
|
||||
if (std::chrono::duration_cast<std::chrono::milliseconds>(timeNotRunning).count() >
|
||||
watchdog::MAX_NOT_RUNNING_MS) {
|
||||
std::cout << "Restarting OBSW with systemctl" << std::endl;
|
||||
std::system("systemctl restart obsw");
|
||||
}
|
||||
if(type == LoopResult::HUNG_UP) {
|
||||
using namespace std::chrono_literals;
|
||||
// Prevent spam
|
||||
std::this_thread::sleep_for(2000ms);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (type == LoopResult::HUNG_UP) {
|
||||
using namespace std::chrono_literals;
|
||||
// Prevent spam
|
||||
std::this_thread::sleep_for(2000ms);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WatchdogTask::performSuspendOperation() {
|
||||
if(state == States::RUNNING or state == States::FAULTY) {
|
||||
std::cout << "eive-watchdog: Suspending watchdog operations" << std::endl;
|
||||
watchdogRunning = false;
|
||||
state = States::SUSPENDED;
|
||||
bool WatchdogTask::stateMachine(LoopResult loopResult) {
|
||||
using namespace std::chrono_literals;
|
||||
bool sleep = false;
|
||||
switch (state) {
|
||||
case (States::RUNNING): {
|
||||
switch (loopResult) {
|
||||
case (LoopResult::TIMEOUT):
|
||||
case (LoopResult::HUNG_UP): {
|
||||
performNotRunningOperation(loopResult);
|
||||
break;
|
||||
}
|
||||
case (LoopResult::OK): {
|
||||
performRunningOperation();
|
||||
break;
|
||||
}
|
||||
case (LoopResult::SUSPEND_REQ): {
|
||||
if (state == States::RUNNING or state == States::FAULTY) {
|
||||
std::cout << "Received suspend request, suspending watchdog operations" << std::endl;
|
||||
state = States::SUSPENDED;
|
||||
}
|
||||
performSuspendOperation();
|
||||
sleep = true;
|
||||
break;
|
||||
}
|
||||
case (LoopResult::CANCEL_REQ): {
|
||||
std::cout << "Received cancel request, closing watchdog.." << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
case (States::FAULTY):
|
||||
case (States::SUSPENDED):
|
||||
case (States::NOT_STARTED): {
|
||||
switch (loopResult) {
|
||||
case (LoopResult::SUSPEND_REQ): {
|
||||
// Ignore and also delay
|
||||
sleep = true;
|
||||
break;
|
||||
}
|
||||
case (LoopResult::START_REQ):
|
||||
case (LoopResult::START_WITH_WATCH_REQ): {
|
||||
if (state == States::NOT_STARTED or state == States::FAULTY) {
|
||||
state = States::RUNNING;
|
||||
}
|
||||
if (loopResult == LoopResult::START_REQ) {
|
||||
std::cout << "Start request without watch request received" << std::endl;
|
||||
watchingObsw = false;
|
||||
} else if (loopResult == LoopResult::START_WITH_WATCH_REQ) {
|
||||
std::cout << "Start request with watch request received. Restarting OBSW if not "
|
||||
"running for "
|
||||
<< watchdog::MAX_NOT_RUNNING_MS / 1000 << " seconds" << std::endl;
|
||||
watchingObsw = true;
|
||||
}
|
||||
performRunningOperation();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
sleep = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (loopResult == LoopResult::FAULT) {
|
||||
// Configuration error
|
||||
std::cerr << "Fault has occured in watchdog loop" << std::endl;
|
||||
// Prevent spam
|
||||
sleep = true;
|
||||
}
|
||||
if (sleep) {
|
||||
std::this_thread::sleep_for(500ms);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int WatchdogTask::performSuspendOperation() { return 0; }
|
||||
|
@ -2,49 +2,55 @@
|
||||
#define WATCHDOG_WATCHDOG_H_
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
|
||||
class WatchdogTask {
|
||||
public:
|
||||
enum class States {
|
||||
NOT_STARTED,
|
||||
RUNNING,
|
||||
SUSPENDED,
|
||||
FAULTY
|
||||
};
|
||||
public:
|
||||
enum class States { NOT_STARTED, RUNNING, SUSPENDED, FAULTY };
|
||||
|
||||
enum class LoopResult {
|
||||
OK,
|
||||
SUSPEND_RQ,
|
||||
CANCEL_RQ,
|
||||
RESTART_RQ,
|
||||
TIMEOUT,
|
||||
HUNG_UP,
|
||||
FAULT
|
||||
};
|
||||
enum class LoopResult {
|
||||
OK,
|
||||
START_REQ,
|
||||
START_WITH_WATCH_REQ,
|
||||
SUSPEND_REQ,
|
||||
CANCEL_REQ,
|
||||
TIMEOUT,
|
||||
HUNG_UP,
|
||||
FAULT
|
||||
};
|
||||
|
||||
WatchdogTask();
|
||||
WatchdogTask();
|
||||
|
||||
virtual ~WatchdogTask();
|
||||
virtual ~WatchdogTask();
|
||||
|
||||
int performOperation();
|
||||
private:
|
||||
int fd = 0;
|
||||
int performOperation();
|
||||
|
||||
bool obswRunning = false;
|
||||
bool watchdogRunning = false;
|
||||
bool printNotRunningLatch = false;
|
||||
std::array<uint8_t, 64> buf;
|
||||
States state = States::NOT_STARTED;
|
||||
private:
|
||||
int fd = 0;
|
||||
|
||||
LoopResult watchdogLoop();
|
||||
LoopResult pollEvent(struct pollfd& waiter);
|
||||
LoopResult parseCommandByte(ssize_t readLen);
|
||||
bool obswRunning = false;
|
||||
bool watchingObsw = false;
|
||||
bool printNotRunningLatch = false;
|
||||
std::array<uint8_t, 64> buf;
|
||||
std::queue<LoopResult> resultQueue;
|
||||
|
||||
int performRunningOperation();
|
||||
int performNotRunningOperation(LoopResult type);
|
||||
int performSuspendOperation();
|
||||
std::optional<std::chrono::time_point<std::chrono::steady_clock>> notRunningStart;
|
||||
States state = States::NOT_STARTED;
|
||||
|
||||
// Primary loop. Takes care of delaying, and reading from the communication pipe and translating
|
||||
// messages to loop results.
|
||||
void watchdogLoop();
|
||||
bool stateMachine(LoopResult result);
|
||||
void pollEvent(struct pollfd& waiter);
|
||||
void parseCommands(ssize_t readLen);
|
||||
|
||||
int performRunningOperation();
|
||||
int performNotRunningOperation(LoopResult type);
|
||||
int performSuspendOperation();
|
||||
};
|
||||
|
||||
#endif /* WATCHDOG_WATCHDOG_H_ */
|
||||
|
@ -5,17 +5,31 @@
|
||||
|
||||
namespace watchdog {
|
||||
|
||||
namespace first {
|
||||
|
||||
// Start or restart character
|
||||
static constexpr char START_CHAR = 'b';
|
||||
// Suspend watchdog operations temporarily
|
||||
static constexpr char SUSPEND_CHAR = 's';
|
||||
// Resume watchdog operations
|
||||
static constexpr char RESTART_CHAR = 'b';
|
||||
// Causes the watchdog to close down
|
||||
static constexpr char CANCEL_CHAR = 'c';
|
||||
static constexpr char IDLE_CHAR = 'i';
|
||||
|
||||
} // namespace first
|
||||
|
||||
namespace second {
|
||||
|
||||
// Supplied with the start character. This will instruct the watchdog to actually watch
|
||||
// the OBSW is runnng all the time.
|
||||
static constexpr char WATCH_FLAG = 'w';
|
||||
} // namespace second
|
||||
|
||||
static constexpr int TIMEOUT_MS = 5 * 1000;
|
||||
// 2 minutes
|
||||
static constexpr unsigned MAX_NOT_RUNNING_MS = 2 * 60 * 1000;
|
||||
const std::string FIFO_NAME = "/tmp/watchdog-pipe";
|
||||
const std::string RUNNING_FILE_NAME = "/tmp/obsw-running";
|
||||
|
||||
}
|
||||
} // namespace watchdog
|
||||
|
||||
#endif /* WATCHDOG_DEFINITIONS_H_ */
|
||||
|
@ -1,24 +1,34 @@
|
||||
#include "Watchdog.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "Watchdog.h"
|
||||
#include "definitions.h"
|
||||
|
||||
/**
|
||||
* @brief This watchdog application uses a FIFO to check whether the OBSW is still running.
|
||||
* It checks whether the OBSW writes to the the FIFO regularly.
|
||||
*/
|
||||
int main() {
|
||||
std::cout << "eive-watchdog: Starting OBSW watchdog.." << std::endl;
|
||||
try {
|
||||
WatchdogTask watchdogTask;
|
||||
int result = watchdogTask.performOperation();
|
||||
if(result != 0) {
|
||||
return result;
|
||||
}
|
||||
std::cout << "Starting OBSW watchdog" << std::endl;
|
||||
std::error_code e;
|
||||
if (std::filesystem::exists(watchdog::RUNNING_FILE_NAME, e)) {
|
||||
std::cout << "Removing " << watchdog::RUNNING_FILE_NAME << std::endl;
|
||||
int result = std::remove(watchdog::RUNNING_FILE_NAME.c_str());
|
||||
if (result != 0) {
|
||||
std::cerr << "file removal failure" << std::endl;
|
||||
}
|
||||
catch(const std::runtime_error& e) {
|
||||
std::cerr << "eive-watchdog: Run time exception " << e.what() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
try {
|
||||
WatchdogTask watchdogTask;
|
||||
int result = watchdogTask.performOperation();
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
return 0;
|
||||
} catch (const std::runtime_error& e) {
|
||||
std::cerr << "Run time exception " << e.what() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user