diff --git a/.gitignore b/.gitignore index 5419ca42..eb6a49fa 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,7 @@ __pycache__ !/.idea/cmake.xml generators/*.db + +# Clangd LSP +/compile_commands.json +/.cache diff --git a/CHANGELOG.md b/CHANGELOG.md index a71a5863..c6ff7e56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,30 @@ will consitute of a breaking change warranting a new major release: A filesystem change via `prefSD` on bootup, can lead to the TLE not being read, even though it is there. +## Changed + +- Rewrote the PLOC Supervisor Handler, which is now based on a new device handler base class. + Added ADC and Logging Counters telemetry set support. + +## Fixed + +- Increase allowed time for PTME writers to finish partial transfers. A duration of 200 ms was + not sufficient for cases where 3 writers write concurrently. +- Fixed state issue for PTME writer object where the writer was not reset properly after a timeout + of a partial transfer. This was a major bug blocking the whole VC if it occured. +- STR config path was previously hardcoded to `/mnt/sd0/startracker/flight-config.json`. + A new abstraction was introduces which now uses the active SD card to build the correct + config path when initializing the star tracker. + +## Added + +- PL PCDU: Add command to enable and disable channel order checks. +- Added new PUS 15 subservice `DELETE_BY_TIME_RANGE` which allows to also specify a deletion + start time when deleting packets from the persistent TM store. +- Introduced a new `RELOAD_JSON_CFG_FILE` command for the STR to reload the JSON configuration + data based on the current output of the config file path getter function. A reboot of the + device is still necessary to load the configuration to the STR. + # [v7.3.0] 2023-11-07 ## Changed @@ -30,6 +54,7 @@ will consitute of a breaking change warranting a new major release: - Changed PDEC addresses depending on which firmware version is used. It is suspected that the previous addresses were invalid and not properly covered by the Linux memory protection. The OBSW will use the old addresses for older FW versions. +- Reverted some STR ComIF behaviour back to an older software version. ## Added @@ -703,7 +728,7 @@ This is the version which will fly on the satellite for the initial launch phase This gives other tasks some time to register the SD cards being unusable, and therefore provides a way for them to perform any re-initialization tasks necessary after SD card switches. - TCS controller now only has an OFF mode and an ON mode -- The TCS controller pauses operations related to the TCS board assembly (reading sensors and +- The TCS controller pauses operations related to the TCS board assembly (reading sensors and the primary control loop) while a TCS board recovery is on-going. - Allow specifying custom OBSW update filename. This allowed keeping a cleaner file structure where each update has a name including the version @@ -1768,8 +1793,8 @@ Syrlinks PR: PR: https://egit.irs.uni-stuttgart.de/eive/eive-obsw/pulls/353 - Syrlinks Handler: Read RX frequency shift as 24 bit signed number now. Also include validity handling for datasets. PR: https://egit.irs.uni-stuttgart.de/eive/eive-obsw/pulls/350 -- `GyroADIS1650XHandler`: Changed calculation of angular rate to be sensitivity based instead of - max. range based, as previous fix still left an margin of error between ADIS16505 sensors +- `GyroADIS1650XHandler`: Changed calculation of angular rate to be sensitivity based instead of + max. range based, as previous fix still left an margin of error between ADIS16505 sensors and L3GD20 sensors. PR: https://egit.irs.uni-stuttgart.de/eive/eive-obsw/pulls/346 diff --git a/linux/payload/PlocSupervisorHandler.cpp b/archive/PlocSupervisorHandler.cpp similarity index 91% rename from linux/payload/PlocSupervisorHandler.cpp rename to archive/PlocSupervisorHandler.cpp index 3863caea..67ec707f 100644 --- a/linux/payload/PlocSupervisorHandler.cpp +++ b/archive/PlocSupervisorHandler.cpp @@ -19,8 +19,6 @@ using namespace supv; using namespace returnvalue; -std::atomic_bool supv::SUPV_ON = false; - PlocSupervisorHandler::PlocSupervisorHandler(object_id_t objectId, CookieIF* comCookie, Gpio uartIsolatorSwitch, power::Switch_t powerSwitch, PlocSupvUartManager& supvHelper) @@ -29,7 +27,7 @@ PlocSupervisorHandler::PlocSupervisorHandler(object_id_t objectId, CookieIF* com hkset(this), bootStatusReport(this), latchupStatusReport(this), - loggingReport(this), + countersReport(this), adcReport(this), powerSwitch(powerSwitch), uartManager(supvHelper) { @@ -61,6 +59,19 @@ ReturnValue_t PlocSupervisorHandler::initialize() { } void PlocSupervisorHandler::performOperationHook() { + if (normalCommandIsPending and normalCmdCd.hasTimedOut()) { + // Event, FDIR, printout? Leads to spam though and normally should not happen.. + normalCommandIsPending = false; + } + if (commandIsPending and cmdCd.hasTimedOut()) { + // Event, FDIR, printout? Leads to spam though and normally should not happen.. + commandIsPending = false; + + // if(iter->second.sendReplyTo != NO_COMMANDER) { + // actionHelper.finish(true, iter->second.sendReplyTo, iter->first, returnvalue::OK); + // } + disableAllReplies(); + } EventMessage event; for (ReturnValue_t result = eventQueue->receiveMessage(&event); result == returnvalue::OK; result = eventQueue->receiveMessage(&event)) { @@ -172,13 +183,16 @@ void PlocSupervisorHandler::doShutDown() { nextReplyId = supv::NONE; uartManager.stop(); uartIsolatorSwitch.pullLow(); + disableAllReplies(); supv::SUPV_ON = false; startupState = StartupState::OFF; } ReturnValue_t PlocSupervisorHandler::buildNormalDeviceCommand(DeviceCommandId_t* id) { - if (not commandIsExecuting(GET_HK_REPORT)) { + if (not normalCommandIsPending) { *id = GET_HK_REPORT; + normalCommandIsPending = true; + normalCmdCd.resetTimer(); return buildCommandFromCommand(*id, nullptr, 0); } return NOTHING_TO_SEND; @@ -274,8 +288,7 @@ ReturnValue_t PlocSupervisorHandler::buildCommandFromCommand(DeviceCommandId_t d break; } case SET_GPIO: { - prepareSetGpioCmd(commandData); - result = returnvalue::OK; + result = prepareSetGpioCmd(commandData, commandDataLen); break; } case FACTORY_RESET: { @@ -283,8 +296,7 @@ ReturnValue_t PlocSupervisorHandler::buildCommandFromCommand(DeviceCommandId_t d break; } case READ_GPIO: { - prepareReadGpioCmd(commandData); - result = returnvalue::OK; + result = prepareReadGpioCmd(commandData, commandDataLen); break; } case SET_SHUTDOWN_TIMEOUT: { @@ -321,12 +333,25 @@ ReturnValue_t PlocSupervisorHandler::buildCommandFromCommand(DeviceCommandId_t d result = prepareWipeMramCmd(commandData); break; } + case REQUEST_ADC_REPORT: { + prepareEmptyCmd(Apid::ADC_MON, static_cast(tc::AdcMonId::REQUEST_ADC_SAMPLE)); + result = returnvalue::OK; + break; + } + case REQUEST_LOGGING_COUNTERS: { + prepareEmptyCmd(Apid::DATA_LOGGER, + static_cast(tc::DataLoggerServiceId::REQUEST_COUNTERS)); + result = returnvalue::OK; + break; + } default: sif::debug << "PlocSupervisorHandler::buildCommandFromCommand: Command not implemented" << std::endl; result = DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; break; } + commandIsPending = true; + cmdCd.resetTimer(); return result; } @@ -358,6 +383,8 @@ void PlocSupervisorHandler::fillCommandAndReplyMap() { insertInCommandMap(SET_ADC_THRESHOLD); insertInCommandMap(SET_ADC_WINDOW_AND_STRIDE); insertInCommandMap(RESET_PL); + insertInCommandMap(REQUEST_ADC_REPORT); + insertInCommandMap(REQUEST_LOGGING_COUNTERS); // ACK replies, use countdown for them insertInReplyMap(ACK_REPORT, 0, nullptr, SIZE_ACK_REPORT, false, &acknowledgementReportTimeout); @@ -368,7 +395,7 @@ void PlocSupervisorHandler::fillCommandAndReplyMap() { insertInReplyMap(HK_REPORT, 3, &hkset); insertInReplyMap(BOOT_STATUS_REPORT, 3, &bootStatusReport, SIZE_BOOT_STATUS_REPORT); insertInReplyMap(LATCHUP_REPORT, 3, &latchupStatusReport, SIZE_LATCHUP_STATUS_REPORT); - insertInReplyMap(LOGGING_REPORT, 3, &loggingReport, SIZE_LOGGING_REPORT); + insertInReplyMap(COUNTERS_REPORT, 3, &countersReport, SIZE_COUNTERS_REPORT); insertInReplyMap(ADC_REPORT, 3, &adcReport, SIZE_ADC_REPORT); } @@ -410,13 +437,13 @@ ReturnValue_t PlocSupervisorHandler::enableReplyInReplyMap(DeviceCommandMap::ite } break; } - case LOGGING_REQUEST_COUNTERS: { + case REQUEST_LOGGING_COUNTERS: { enabledReplies = 3; result = - DeviceHandlerBase::enableReplyInReplyMap(command, enabledReplies, true, LOGGING_REPORT); + DeviceHandlerBase::enableReplyInReplyMap(command, enabledReplies, true, COUNTERS_REPORT); if (result != returnvalue::OK) { sif::debug << "PlocSupervisorHandler::enableReplyInReplyMap: Reply with id " - << LOGGING_REPORT << " not in replyMap" << std::endl; + << COUNTERS_REPORT << " not in replyMap" << std::endl; } break; } @@ -541,6 +568,9 @@ ReturnValue_t PlocSupervisorHandler::scanForReply(const uint8_t* start, size_t r } case (Apid::HK): { if (tmReader.getServiceId() == static_cast(supv::tm::HkId::REPORT)) { + normalCommandIsPending = false; + // Yeah apparently this is needed?? + disableCommand(GET_HK_REPORT); *foundLen = tmReader.getFullPacketLen(); *foundId = ReplyId::HK_REPORT; return OK; @@ -559,6 +589,14 @@ ReturnValue_t PlocSupervisorHandler::scanForReply(const uint8_t* start, size_t r } break; } + case (Apid::ADC_MON): { + if (tmReader.getServiceId() == static_cast(supv::tm::AdcMonId::ADC_REPORT)) { + *foundLen = tmReader.getFullPacketLen(); + *foundId = ReplyId::ADC_REPORT; + return OK; + } + break; + } case (Apid::MEM_MAN): { if (tmReader.getServiceId() == static_cast(supv::tm::MemManId::UPDATE_STATUS_REPORT)) { @@ -566,6 +604,15 @@ ReturnValue_t PlocSupervisorHandler::scanForReply(const uint8_t* start, size_t r *foundId = ReplyId::UPDATE_STATUS_REPORT; return OK; } + break; + } + case (Apid::DATA_LOGGER): { + if (tmReader.getServiceId() == + static_cast(supv::tm::DataLoggerId::COUNTERS_REPORT)) { + *foundLen = tmReader.getFullPacketLen(); + *foundId = ReplyId::COUNTERS_REPORT; + return OK; + } } } handleBadApidServiceCombination(SUPV_UNKNOWN_TM, apid, tmReader.getServiceId()); @@ -578,6 +625,14 @@ void PlocSupervisorHandler::handlePacketPrint() { if ((tmReader.getServiceId() == static_cast(supv::tm::TmtcId::ACK)) or (tmReader.getServiceId() == static_cast(supv::tm::TmtcId::NAK))) { AcknowledgmentReport ack(tmReader); + ReturnValue_t result = ack.parse(); + if (result != returnvalue::OK) { + sif::warning << "PlocSupervisorHandler: Parsing ACK failed" << std::endl; + } + if (REDUCE_NORMAL_MODE_PRINTOUT and ack.getRefModuleApid() == (uint8_t)supv::Apid::HK and + ack.getRefServiceId() == (uint8_t)supv::tc::HkId::GET_REPORT) { + return; + } const char* printStr = "???"; if (tmReader.getServiceId() == static_cast(supv::tm::TmtcId::ACK)) { printStr = "ACK"; @@ -592,7 +647,15 @@ void PlocSupervisorHandler::handlePacketPrint() { } else if ((tmReader.getServiceId() == static_cast(supv::tm::TmtcId::EXEC_ACK)) or (tmReader.getServiceId() == static_cast(supv::tm::TmtcId::EXEC_NAK))) { ExecutionReport exe(tmReader); + ReturnValue_t result = exe.parse(); + if (result != returnvalue::OK) { + sif::warning << "PlocSupervisorHandler: Parsing EXE failed" << std::endl; + } const char* printStr = "???"; + if (REDUCE_NORMAL_MODE_PRINTOUT and exe.getRefModuleApid() == (uint8_t)supv::Apid::HK and + exe.getRefServiceId() == (uint8_t)supv::tc::HkId::GET_REPORT) { + return; + } if (tmReader.getServiceId() == static_cast(supv::tm::TmtcId::EXEC_ACK)) { printStr = "ACK EXE"; @@ -627,12 +690,22 @@ ReturnValue_t PlocSupervisorHandler::interpretDeviceReply(DeviceCommandId_t id, result = handleBootStatusReport(packet); break; } + case (COUNTERS_REPORT): { + result = genericHandleTm("COUNTERS", packet, countersReport); +#if OBSW_VERBOSE_LEVEL >= 1 && OBSW_DEBUG_PLOC_SUPERVISOR == 1 + countersReport.printSet(); +#endif + break; + } case (LATCHUP_REPORT): { result = handleLatchupStatusReport(packet); break; } case (ADC_REPORT): { - result = handleAdcReport(packet); + result = genericHandleTm("ADC", packet, adcReport); +#if OBSW_VERBOSE_LEVEL >= 1 && OBSW_DEBUG_PLOC_SUPERVISOR == 1 + adcReport.printSet(); +#endif break; } case (EXE_REPORT): { @@ -697,13 +770,8 @@ ReturnValue_t PlocSupervisorHandler::initializeLocalDataPool(localpool::DataPool localDataPoolMap.emplace(supv::LATCHUP_RPT_TIME_YEAR, new PoolEntry({0})); localDataPoolMap.emplace(supv::LATCHUP_RPT_IS_SET, new PoolEntry({0})); - localDataPoolMap.emplace(supv::LATCHUP_HAPPENED_CNT_0, new PoolEntry({0})); - localDataPoolMap.emplace(supv::LATCHUP_HAPPENED_CNT_1, new PoolEntry({0})); - localDataPoolMap.emplace(supv::LATCHUP_HAPPENED_CNT_2, new PoolEntry({0})); - localDataPoolMap.emplace(supv::LATCHUP_HAPPENED_CNT_3, new PoolEntry({0})); - localDataPoolMap.emplace(supv::LATCHUP_HAPPENED_CNT_4, new PoolEntry({0})); - localDataPoolMap.emplace(supv::LATCHUP_HAPPENED_CNT_5, new PoolEntry({0})); - localDataPoolMap.emplace(supv::LATCHUP_HAPPENED_CNT_6, new PoolEntry({0})); + localDataPoolMap.emplace(supv::SIGNATURE, new PoolEntry()); + localDataPoolMap.emplace(supv::LATCHUP_HAPPENED_CNTS, &latchupCounters); localDataPoolMap.emplace(supv::ADC_DEVIATION_TRIGGERS_CNT, new PoolEntry({0})); localDataPoolMap.emplace(supv::TC_RECEIVED_CNT, new PoolEntry({0})); localDataPoolMap.emplace(supv::TM_AVAILABLE_CNT, new PoolEntry({0})); @@ -712,41 +780,22 @@ ReturnValue_t PlocSupervisorHandler::initializeLocalDataPool(localpool::DataPool localDataPoolMap.emplace(supv::MPSOC_BOOT_FAILED_ATTEMPTS, new PoolEntry({0})); localDataPoolMap.emplace(supv::MPSOC_POWER_UP, new PoolEntry({0})); localDataPoolMap.emplace(supv::MPSOC_UPDATES, new PoolEntry({0})); - localDataPoolMap.emplace(supv::LAST_RECVD_TC, new PoolEntry({0})); + localDataPoolMap.emplace(supv::MPSOC_HEARTBEAT_RESETS, new PoolEntry({0})); + localDataPoolMap.emplace(supv::CPU_WDT_RESETS, new PoolEntry({0})); + localDataPoolMap.emplace(supv::PS_HEARTBEATS_LOST, new PoolEntry({0})); + localDataPoolMap.emplace(supv::PL_HEARTBEATS_LOST, new PoolEntry({0})); + localDataPoolMap.emplace(supv::EB_TASK_LOST, new PoolEntry({0})); + localDataPoolMap.emplace(supv::BM_TASK_LOST, new PoolEntry({0})); + localDataPoolMap.emplace(supv::LM_TASK_LOST, new PoolEntry({0})); + localDataPoolMap.emplace(supv::AM_TASK_LOST, new PoolEntry({0})); + localDataPoolMap.emplace(supv::TCTMM_TASK_LOST, new PoolEntry({0})); + localDataPoolMap.emplace(supv::MM_TASK_LOST, new PoolEntry({0})); + localDataPoolMap.emplace(supv::HK_TASK_LOST, new PoolEntry({0})); + localDataPoolMap.emplace(supv::DL_TASK_LOST, new PoolEntry({0})); + localDataPoolMap.emplace(supv::RWS_TASKS_LOST, new PoolEntry(3)); - localDataPoolMap.emplace(supv::ADC_RAW_0, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_RAW_1, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_RAW_2, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_RAW_3, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_RAW_4, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_RAW_5, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_RAW_6, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_RAW_7, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_RAW_8, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_RAW_9, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_RAW_10, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_RAW_11, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_RAW_12, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_RAW_13, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_RAW_14, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_RAW_15, new PoolEntry({0})); - - localDataPoolMap.emplace(supv::ADC_ENG_0, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_ENG_1, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_ENG_2, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_ENG_3, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_ENG_4, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_ENG_5, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_ENG_6, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_ENG_7, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_ENG_8, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_ENG_9, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_ENG_10, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_ENG_11, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_ENG_12, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_ENG_13, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_ENG_14, new PoolEntry({0})); - localDataPoolMap.emplace(supv::ADC_ENG_15, new PoolEntry({0})); + localDataPoolMap.emplace(supv::ADC_RAW, &adcRawEntry); + localDataPoolMap.emplace(supv::ADC_ENG, &adcEngEntry); poolManager.subscribeForRegularPeriodicPacket( subdp::RegularHkPeriodicParams(hkset.getSid(), false, 10.0)); @@ -871,6 +920,7 @@ ReturnValue_t PlocSupervisorHandler::handleExecutionReport(const uint8_t* data) } else if (tmReader.getServiceId() == static_cast(supv::tm::TmtcId::EXEC_NAK)) { handleExecutionFailureReport(report); } + commandIsPending = false; nextReplyId = supv::NONE; return result; } @@ -1105,37 +1155,31 @@ ReturnValue_t PlocSupervisorHandler::handleLatchupStatusReport(const uint8_t* da return result; } -ReturnValue_t PlocSupervisorHandler::handleAdcReport(const uint8_t* data) { +ReturnValue_t PlocSupervisorHandler::genericHandleTm(const char* contextString, const uint8_t* data, + LocalPoolDataSetBase& set) { ReturnValue_t result = returnvalue::OK; - result = verifyPacket(data, supv::SIZE_ADC_REPORT); + result = verifyPacket(data, tmReader.getFullPacketLen()); if (result == result::CRC_FAILURE) { - sif::error << "PlocSupervisorHandler::handleAdcReport: ADC report has " - << "invalid crc" << std::endl; + sif::warning << "PlocSupervisorHandler: " << contextString << " report has " + << "invalid CRC" << std::endl; return result; } const uint8_t* dataField = data + supv::PAYLOAD_OFFSET; - result = adcReport.read(); - if (result != returnvalue::OK) { + PoolReadGuard pg(&set); + if (pg.getReadResult() != returnvalue::OK) { return result; } - adcReport.setValidityBufferGeneration(false); - size_t size = adcReport.getSerializedSize(); - result = adcReport.deSerialize(&dataField, &size, SerializeIF::Endianness::BIG); + set.setValidityBufferGeneration(false); + size_t size = set.getSerializedSize(); + result = set.deSerialize(&dataField, &size, SerializeIF::Endianness::BIG); if (result != returnvalue::OK) { - sif::warning << "PlocSupervisorHandler::handleAdcReport: Deserialization failed" << std::endl; + sif::warning << "PlocSupervisorHandler: Deserialization failed" << std::endl; } - adcReport.setValidityBufferGeneration(true); - adcReport.setValidity(true, true); - result = adcReport.commit(); - if (result != returnvalue::OK) { - return result; - } -#if OBSW_VERBOSE_LEVEL >= 1 && OBSW_DEBUG_PLOC_SUPERVISOR == 1 - adcReport.printSet(); -#endif + set.setValidityBufferGeneration(true); + set.setValidity(true, true); nextReplyId = supv::EXE_REPORT; return result; } @@ -1157,8 +1201,8 @@ void PlocSupervisorHandler::setNextReplyId() { case supv::CONSECUTIVE_MRAM_DUMP: nextReplyId = supv::CONSECUTIVE_MRAM_DUMP; break; - case supv::LOGGING_REQUEST_COUNTERS: - nextReplyId = supv::LOGGING_REPORT; + case supv::REQUEST_LOGGING_COUNTERS: + nextReplyId = supv::COUNTERS_REPORT; break; case supv::REQUEST_ADC_REPORT: nextReplyId = supv::ADC_REPORT; @@ -1407,7 +1451,11 @@ ReturnValue_t PlocSupervisorHandler::prepareRunAutoEmTest(const uint8_t* command return returnvalue::OK; } -ReturnValue_t PlocSupervisorHandler::prepareSetGpioCmd(const uint8_t* commandData) { +ReturnValue_t PlocSupervisorHandler::prepareSetGpioCmd(const uint8_t* commandData, + size_t commandDataLen) { + if (commandDataLen < 3) { + return HasActionsIF::INVALID_PARAMETERS; + } uint8_t port = *commandData; uint8_t pin = *(commandData + 1); uint8_t val = *(commandData + 2); @@ -1420,7 +1468,11 @@ ReturnValue_t PlocSupervisorHandler::prepareSetGpioCmd(const uint8_t* commandDat return returnvalue::OK; } -ReturnValue_t PlocSupervisorHandler::prepareReadGpioCmd(const uint8_t* commandData) { +ReturnValue_t PlocSupervisorHandler::prepareReadGpioCmd(const uint8_t* commandData, + size_t commandDataLen) { + if (commandDataLen < 2) { + return HasActionsIF::INVALID_PARAMETERS; + } uint8_t port = *commandData; uint8_t pin = *(commandData + 1); supv::ReadGpio packet(spParams); @@ -1466,6 +1518,7 @@ ReturnValue_t PlocSupervisorHandler::prepareSetShutdownTimeoutCmd(const uint8_t* sif::warning << "PlocSupervisorHandler::prepareSetShutdownTimeoutCmd: Failed to deserialize timeout" << std::endl; + return result; } supv::SetShutdownTimeout packet(spParams); result = packet.buildPacket(timeout); @@ -1517,8 +1570,8 @@ void PlocSupervisorHandler::disableAllReplies() { disableReply(LATCHUP_REPORT); break; } - case LOGGING_REQUEST_COUNTERS: { - disableReply(LOGGING_REPORT); + case REQUEST_LOGGING_COUNTERS: { + disableReply(COUNTERS_REPORT); break; } default: { @@ -1532,6 +1585,9 @@ void PlocSupervisorHandler::disableAllReplies() { void PlocSupervisorHandler::disableReply(DeviceCommandId_t replyId) { DeviceReplyMap::iterator iter = deviceReplyMap.find(replyId); + if (iter == deviceReplyMap.end()) { + return; + } DeviceReplyInfo* info = &(iter->second); info->delayCycles = 0; info->active = false; @@ -1562,6 +1618,9 @@ void PlocSupervisorHandler::sendFailureReport(DeviceCommandId_t replyId, ReturnV void PlocSupervisorHandler::disableExeReportReply() { DeviceReplyIter iter = deviceReplyMap.find(supv::EXE_REPORT); + if (iter == deviceReplyMap.end()) { + return; + } DeviceReplyInfo* info = &(iter->second); info->delayCycles = 0; info->command = deviceCommandMap.end(); @@ -1584,7 +1643,9 @@ ReturnValue_t PlocSupervisorHandler::handleMramDumpPacket(DeviceCommandId_t id) result = handleMramDumpFile(id); if (result != returnvalue::OK) { DeviceCommandMap::iterator iter = deviceCommandMap.find(id); - actionHelper.finish(false, iter->second.sendReplyTo, id, result); + if (iter != deviceCommandMap.end()) { + actionHelper.finish(false, iter->second.sendReplyTo, id, result); + } disableAllReplies(); nextReplyId = supv::NONE; return result; @@ -1851,7 +1912,12 @@ ReturnValue_t PlocSupervisorHandler::eventSubscription() { ReturnValue_t PlocSupervisorHandler::handleExecutionSuccessReport(ExecutionReport& report) { DeviceCommandId_t commandId = getPendingCommand(); - ReturnValue_t result = OK; + DeviceCommandMap::iterator iter = deviceCommandMap.find(commandId); + if (iter != deviceCommandMap.end() and iter->second.sendReplyTo != NO_COMMANDER) { + actionHelper.finish(true, iter->second.sendReplyTo, iter->first, returnvalue::OK); + iter->second.isExecuting = false; + } + commandIsPending = false; switch (commandId) { case supv::READ_GPIO: { // TODO: Fix @@ -1859,14 +1925,13 @@ ReturnValue_t PlocSupervisorHandler::handleExecutionSuccessReport(ExecutionRepor #if OBSW_DEBUG_PLOC_SUPERVISOR == 1 sif::info << "PlocSupervisorHandler: Read GPIO TM, State: " << gpioState << std::endl; #endif /* OBSW_DEBUG_PLOC_SUPERVISOR == 1 */ - DeviceCommandMap::iterator iter = deviceCommandMap.find(commandId); - if (iter->second.sendReplyTo == NO_COMMAND_ID) { + if (iter != deviceCommandMap.end() and iter->second.sendReplyTo == NO_COMMAND_ID) { return returnvalue::OK; } uint8_t data[sizeof(gpioState)]; size_t size = 0; - result = SerializeAdapter::serialize(&gpioState, data, &size, sizeof(gpioState), - SerializeIF::Endianness::BIG); + ReturnValue_t result = SerializeAdapter::serialize(&gpioState, data, &size, sizeof(gpioState), + SerializeIF::Endianness::BIG); if (result != returnvalue::OK) { sif::debug << "PlocSupervisorHandler: Failed to deserialize GPIO state" << std::endl; } @@ -1942,6 +2007,11 @@ uint32_t PlocSupervisorHandler::getTransitionDelayMs(Mode_t modeFrom, Mode_t mod return 7000; } +void PlocSupervisorHandler::disableCommand(DeviceCommandId_t cmd) { + auto commandIter = deviceCommandMap.find(GET_HK_REPORT); + commandIter->second.isExecuting = false; +} + ReturnValue_t PlocSupervisorHandler::checkModeCommand(Mode_t commandedMode, Submode_t commandedSubmode, uint32_t* msToReachTheMode) { diff --git a/linux/payload/PlocSupervisorHandler.h b/archive/PlocSupervisorHandler.h similarity index 89% rename from linux/payload/PlocSupervisorHandler.h rename to archive/PlocSupervisorHandler.h index 4514e69f..85c3d94e 100644 --- a/linux/payload/PlocSupervisorHandler.h +++ b/archive/PlocSupervisorHandler.h @@ -20,7 +20,8 @@ using supv::ExecutionReport; using supv::TcBase; -static constexpr bool DEBUG_PLOC_SUPV = false; +static constexpr bool DEBUG_PLOC_SUPV = true; +static constexpr bool REDUCE_NORMAL_MODE_PRINTOUT = true; /** * @brief This is the device handler for the supervisor of the PLOC which is programmed by @@ -67,26 +68,6 @@ class PlocSupervisorHandler : public DeviceHandlerBase { void doOffActivity() override; private: - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PLOC_SUPERVISOR_HANDLER; - - //! [EXPORT] : [COMMENT] PLOC supervisor crc failure in telemetry packet - static const Event SUPV_MEMORY_READ_RPT_CRC_FAILURE = MAKE_EVENT(1, severity::LOW); - //! [EXPORT] : [COMMENT] Unhandled event. P1: APID, P2: Service ID - static constexpr Event SUPV_UNKNOWN_TM = MAKE_EVENT(2, severity::LOW); - static constexpr Event SUPV_UNINIMPLEMENTED_TM = MAKE_EVENT(3, severity::LOW); - //! [EXPORT] : [COMMENT] PLOC supervisor received acknowledgment failure report - static const Event SUPV_ACK_FAILURE = MAKE_EVENT(4, severity::LOW); - //! [EXPORT] : [COMMENT] PLOC received execution failure report - //! P1: ID of command for which the execution failed - //! P2: Status code sent by the supervisor handler - static const Event SUPV_EXE_FAILURE = MAKE_EVENT(5, severity::LOW); - //! [EXPORT] : [COMMENT] PLOC supervisor reply has invalid crc - static const Event SUPV_CRC_FAILURE_EVENT = MAKE_EVENT(6, severity::LOW); - //! [EXPORT] : [COMMENT] Supervisor helper currently executing a command - static const Event SUPV_HELPER_EXECUTING = MAKE_EVENT(7, severity::LOW); - //! [EXPORT] : [COMMENT] Failed to build the command to shutdown the MPSoC - static const Event SUPV_MPSOC_SHUTDOWN_BUILD_FAILED = MAKE_EVENT(8, severity::LOW); - static const uint16_t APID_MASK = 0x7FF; static const uint16_t PACKET_SEQUENCE_COUNT_MASK = 0x3FFF; static const uint8_t EXE_STATUS_OFFSET = 10; @@ -94,15 +75,14 @@ class PlocSupervisorHandler : public DeviceHandlerBase { // 5 s static const uint32_t EXECUTION_DEFAULT_TIMEOUT = 5000; // 70 S - static const uint32_t ACKNOWLEDGE_DEFAULT_TIMEOUT = 70000; + static const uint32_t ACKNOWLEDGE_DEFAULT_TIMEOUT = 5000; // 60 s static const uint32_t MRAM_DUMP_EXECUTION_TIMEOUT = 60000; // 70 s static const uint32_t COPY_ADC_TO_MRAM_TIMEOUT = 70000; // 60 s static const uint32_t MRAM_DUMP_TIMEOUT = 60000; - // 4 s - static const uint32_t BOOT_TIMEOUT = 4000; + enum class StartupState : uint8_t { OFF, BOOTING, @@ -131,11 +111,18 @@ class PlocSupervisorHandler : public DeviceHandlerBase { LinuxLibgpioIF* gpioComIF = nullptr; Gpio uartIsolatorSwitch; bool shutdownCmdSent = false; + // Yeah, I am using an extra variable because I once again don't know + // what the hell the base class is doing and I don't care anymore. + bool normalCommandIsPending = false; + // True men implement their reply timeout handling themselves! + Countdown normalCmdCd = Countdown(2000); + bool commandIsPending = false; + Countdown cmdCd = Countdown(2000); supv::HkSet hkset; supv::BootStatusReport bootStatusReport; supv::LatchupStatusReport latchupStatusReport; - supv::LoggingReport loggingReport; + supv::CountersReport countersReport; supv::AdcReport adcReport; const power::Switch_t powerSwitch = power::NO_SWITCH; @@ -164,9 +151,12 @@ class PlocSupervisorHandler : public DeviceHandlerBase { Countdown executionReportTimeout = Countdown(EXECUTION_DEFAULT_TIMEOUT, false); Countdown acknowledgementReportTimeout = Countdown(ACKNOWLEDGE_DEFAULT_TIMEOUT, false); // Vorago nees some time to boot properly - Countdown bootTimeout = Countdown(BOOT_TIMEOUT); + Countdown bootTimeout = Countdown(supv::BOOT_TIMEOUT_MS); Countdown mramDumpTimeout = Countdown(MRAM_DUMP_TIMEOUT); + PoolEntry adcRawEntry = PoolEntry(16); + PoolEntry adcEngEntry = PoolEntry(16); + PoolEntry latchupCounters = PoolEntry(7); PoolEntry fmcStateEntry = PoolEntry(1); PoolEntry bootStateEntry = PoolEntry(1); PoolEntry bootCyclesEntry = PoolEntry(1); @@ -231,8 +221,13 @@ class PlocSupervisorHandler : public DeviceHandlerBase { ReturnValue_t handleBootStatusReport(const uint8_t* data); ReturnValue_t handleLatchupStatusReport(const uint8_t* data); + ReturnValue_t handleCounterReport(const uint8_t* data); void handleBadApidServiceCombination(Event result, unsigned int apid, unsigned int serviceId); ReturnValue_t handleAdcReport(const uint8_t* data); + ReturnValue_t genericHandleTm(const char* contextString, const uint8_t* data, + LocalPoolDataSetBase& set); + + void disableCommand(DeviceCommandId_t cmd); /** * @brief Depending on the current active command, this function sets the reply id of the @@ -301,8 +296,8 @@ class PlocSupervisorHandler : public DeviceHandlerBase { ReturnValue_t prepareSetAdcThresholdCmd(const uint8_t* commandData); ReturnValue_t prepareRunAutoEmTest(const uint8_t* commandData); ReturnValue_t prepareWipeMramCmd(const uint8_t* commandData); - ReturnValue_t prepareSetGpioCmd(const uint8_t* commandData); - ReturnValue_t prepareReadGpioCmd(const uint8_t* commandData); + ReturnValue_t prepareSetGpioCmd(const uint8_t* commandData, size_t commandDataLen); + ReturnValue_t prepareReadGpioCmd(const uint8_t* commandData, size_t commandDataLen); /** * @brief Copies the content of a space packet to the command buffer. diff --git a/bsp_hosted/fsfwconfig/events/translateEvents.cpp b/bsp_hosted/fsfwconfig/events/translateEvents.cpp index 099a4c7a..92401ab1 100644 --- a/bsp_hosted/fsfwconfig/events/translateEvents.cpp +++ b/bsp_hosted/fsfwconfig/events/translateEvents.cpp @@ -1,7 +1,7 @@ /** - * @brief Auto-generated event translation file. Contains 315 translations. + * @brief Auto-generated event translation file. Contains 317 translations. * @details - * Generated on: 2023-10-27 14:24:05 + * Generated on: 2023-11-29 15:14:46 */ #include "translateEvents.h" @@ -157,6 +157,8 @@ const char *SUPV_EXE_FAILURE_STRING = "SUPV_EXE_FAILURE"; const char *SUPV_CRC_FAILURE_EVENT_STRING = "SUPV_CRC_FAILURE_EVENT"; const char *SUPV_HELPER_EXECUTING_STRING = "SUPV_HELPER_EXECUTING"; const char *SUPV_MPSOC_SHUTDOWN_BUILD_FAILED_STRING = "SUPV_MPSOC_SHUTDOWN_BUILD_FAILED"; +const char *SUPV_ACK_UNKNOWN_COMMAND_STRING = "SUPV_ACK_UNKNOWN_COMMAND"; +const char *SUPV_EXE_ACK_UNKNOWN_COMMAND_STRING = "SUPV_EXE_ACK_UNKNOWN_COMMAND"; const char *SANITIZATION_FAILED_STRING = "SANITIZATION_FAILED"; const char *MOUNTED_SD_CARD_STRING = "MOUNTED_SD_CARD"; const char *SEND_MRAM_DUMP_FAILED_STRING = "SEND_MRAM_DUMP_FAILED"; @@ -627,6 +629,10 @@ const char *translateEvents(Event event) { return SUPV_HELPER_EXECUTING_STRING; case (12008): return SUPV_MPSOC_SHUTDOWN_BUILD_FAILED_STRING; + case (12009): + return SUPV_ACK_UNKNOWN_COMMAND_STRING; + case (12010): + return SUPV_EXE_ACK_UNKNOWN_COMMAND_STRING; case (12100): return SANITIZATION_FAILED_STRING; case (12101): diff --git a/bsp_hosted/fsfwconfig/objects/translateObjects.cpp b/bsp_hosted/fsfwconfig/objects/translateObjects.cpp index 1fa48c9a..834bdf41 100644 --- a/bsp_hosted/fsfwconfig/objects/translateObjects.cpp +++ b/bsp_hosted/fsfwconfig/objects/translateObjects.cpp @@ -2,7 +2,7 @@ * @brief Auto-generated object translation file. * @details * Contains 175 translations. - * Generated on: 2023-10-27 14:24:05 + * Generated on: 2023-11-29 15:14:46 */ #include "translateObjects.h" diff --git a/bsp_hosted/objectFactory.cpp b/bsp_hosted/objectFactory.cpp index 0f785e70..30a4154b 100644 --- a/bsp_hosted/objectFactory.cpp +++ b/bsp_hosted/objectFactory.cpp @@ -38,9 +38,9 @@ #include "devices/gpioIds.h" #include "fsfw_hal/linux/gpio/Gpio.h" +#include "linux/payload/FreshSupvHandler.h" #include "linux/payload/PlocMpsocHandler.h" #include "linux/payload/PlocMpsocSpecialComHelper.h" -#include "linux/payload/PlocSupervisorHandler.h" #include "linux/payload/PlocSupvUartMan.h" #include "test/gpio/DummyGpioIF.h" #endif @@ -97,10 +97,11 @@ void ObjectFactory::produce(void* args) { new SerialCookie(objects::PLOC_SUPERVISOR_HANDLER, plocSupvString, uart::PLOC_SUPV_BAUD, supv::MAX_PACKET_SIZE * 20, UartModes::NON_CANONICAL); supervisorCookie->setNoFixedSizeReply(); - auto supvHelper = new PlocSupvUartManager(objects::PLOC_SUPERVISOR_HELPER); - new PlocSupervisorHandler(objects::PLOC_SUPERVISOR_HANDLER, supervisorCookie, - Gpio(gpioIds::ENABLE_SUPV_UART, dummyGpioIF), pcdu::PDU1_CH6_PLOC_12V, - *supvHelper); + new PlocSupvUartManager(objects::PLOC_SUPERVISOR_HELPER); + DhbConfig dhbConf(objects::PLOC_SUPERVISOR_HANDLER); + auto* supvHandler = + new FreshSupvHandler(dhbConf, supervisorCookie, Gpio(gpioIds::ENABLE_SUPV_UART, dummyGpioIF), + dummySwitcher, power::PDU1_CH6_PLOC_12V); #endif /* OBSW_ADD_PLOC_SUPERVISOR == 1 */ #endif diff --git a/bsp_q7s/CMakeLists.txt b/bsp_q7s/CMakeLists.txt index e3232363..0a1a9434 100644 --- a/bsp_q7s/CMakeLists.txt +++ b/bsp_q7s/CMakeLists.txt @@ -25,3 +25,4 @@ add_subdirectory(memory) add_subdirectory(callbacks) add_subdirectory(xadc) add_subdirectory(fs) +add_subdirectory(acs) diff --git a/bsp_q7s/acs/CMakeLists.txt b/bsp_q7s/acs/CMakeLists.txt new file mode 100644 index 00000000..87bf46f2 --- /dev/null +++ b/bsp_q7s/acs/CMakeLists.txt @@ -0,0 +1 @@ +# target_sources(${OBSW_NAME} PUBLIC ) diff --git a/bsp_q7s/acs/StrConfigPathGetter.h b/bsp_q7s/acs/StrConfigPathGetter.h new file mode 100644 index 00000000..58d6964c --- /dev/null +++ b/bsp_q7s/acs/StrConfigPathGetter.h @@ -0,0 +1,23 @@ +#include + +#include "bsp_q7s/fs/SdCardManager.h" +#include "mission/acs/str/strHelpers.h" + +class StrConfigPathGetter : public startracker::SdCardConfigPathGetter { + public: + StrConfigPathGetter(SdCardManager& sdcMan) : sdcMan(sdcMan) {} + + std::optional getCfgPath() override { + if (!sdcMan.isSdCardUsable(std::nullopt)) { + return std::nullopt; + } + if (sdcMan.getActiveSdCard() == sd::SdCard::SLOT_1) { + return std::string("/mnt/sd1/startracker/flight-config.json"); + } else { + return std::string("/mnt/sd0/startracker/flight-config.json"); + } + } + + private: + SdCardManager& sdcMan; +}; diff --git a/bsp_q7s/em/emObjectFactory.cpp b/bsp_q7s/em/emObjectFactory.cpp index bcba1331..949f969b 100644 --- a/bsp_q7s/em/emObjectFactory.cpp +++ b/bsp_q7s/em/emObjectFactory.cpp @@ -152,7 +152,7 @@ void ObjectFactory::produce(void* args) { #endif #if OBSW_ADD_STAR_TRACKER == 1 - createStrComponents(pwrSwitcher); + createStrComponents(pwrSwitcher, *SdCardManager::instance()); #endif /* OBSW_ADD_STAR_TRACKER == 1 */ #if OBSW_ADD_PL_PCDU == 1 diff --git a/bsp_q7s/fmObjectFactory.cpp b/bsp_q7s/fmObjectFactory.cpp index 118b583e..71722e52 100644 --- a/bsp_q7s/fmObjectFactory.cpp +++ b/bsp_q7s/fmObjectFactory.cpp @@ -109,7 +109,7 @@ void ObjectFactory::produce(void* args) { createPayloadComponents(gpioComIF, *pwrSwitcher); #if OBSW_ADD_STAR_TRACKER == 1 - createStrComponents(pwrSwitcher); + createStrComponents(pwrSwitcher, *SdCardManager::instance()); #endif /* OBSW_ADD_STAR_TRACKER == 1 */ #if OBSW_ADD_CCSDS_IP_CORES == 1 diff --git a/bsp_q7s/objectFactory.cpp b/bsp_q7s/objectFactory.cpp index eadf70c6..0880785b 100644 --- a/bsp_q7s/objectFactory.cpp +++ b/bsp_q7s/objectFactory.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -37,6 +36,7 @@ #include #include "OBSWConfig.h" +#include "bsp_q7s/acs/StrConfigPathGetter.h" #include "bsp_q7s/boardtest/Q7STestTask.h" #include "bsp_q7s/callbacks/gnssCallback.h" #include "bsp_q7s/callbacks/pcduSwitchCb.h" @@ -60,6 +60,7 @@ #include "linux/ipcore/PdecHandler.h" #include "linux/ipcore/Ptme.h" #include "linux/ipcore/PtmeConfig.h" +#include "linux/payload/FreshSupvHandler.h" #include "mission/config/configfile.h" #include "mission/system/acs/AcsBoardFdir.h" #include "mission/system/acs/AcsSubsystem.h" @@ -612,11 +613,11 @@ void ObjectFactory::createSyrlinksComponents(PowerSwitchIF* pwrSwitcher) { #endif } -void ObjectFactory::createPayloadComponents(LinuxLibgpioIF* gpioComIF, PowerSwitchIF& pwrSwitch) { +void ObjectFactory::createPayloadComponents(LinuxLibgpioIF* gpioComIF, PowerSwitchIF& pwrSwitcher) { using namespace gpio; std::stringstream consumer; auto* camSwitcher = - new CamSwitcher(objects::CAM_SWITCHER, pwrSwitch, power::PDU2_CH8_PAYLOAD_CAMERA); + new CamSwitcher(objects::CAM_SWITCHER, pwrSwitcher, power::PDU2_CH8_PAYLOAD_CAMERA); camSwitcher->connectModeTreeParent(satsystem::payload::SUBSYSTEM); #if OBSW_ADD_PLOC_MPSOC == 1 consumer << "0x" << std::hex << objects::PLOC_MPSOC_HANDLER; @@ -650,11 +651,11 @@ void ObjectFactory::createPayloadComponents(LinuxLibgpioIF* gpioComIF, PowerSwit new SerialCookie(objects::PLOC_SUPERVISOR_HANDLER, plocSupvDev, serial::PLOC_SUPV_BAUD, supv::MAX_PACKET_SIZE * 20, UartModes::NON_CANONICAL); supervisorCookie->setNoFixedSizeReply(); - auto supvHelper = new PlocSupvUartManager(objects::PLOC_SUPERVISOR_HELPER); - auto* supvHandler = new PlocSupervisorHandler(objects::PLOC_SUPERVISOR_HANDLER, supervisorCookie, - Gpio(gpioIds::ENABLE_SUPV_UART, gpioComIF), - power::PDU1_CH6_PLOC_12V, *supvHelper); - supvHandler->setPowerSwitcher(&pwrSwitch); + new PlocSupvUartManager(objects::PLOC_SUPERVISOR_HELPER); + DhbConfig dhbConf(objects::PLOC_SUPERVISOR_HANDLER); + auto* supvHandler = + new FreshSupvHandler(dhbConf, supervisorCookie, Gpio(gpioIds::ENABLE_SUPV_UART, gpioComIF), + pwrSwitcher, power::PDU1_CH6_PLOC_12V); supvHandler->connectModeTreeParent(satsystem::payload::SUBSYSTEM); #endif /* OBSW_ADD_PLOC_SUPERVISOR == 1 */ static_cast(consumer); @@ -935,7 +936,7 @@ void ObjectFactory::createTestComponents(LinuxLibgpioIF* gpioComIF) { #endif } -void ObjectFactory::createStrComponents(PowerSwitchIF* pwrSwitcher) { +void ObjectFactory::createStrComponents(PowerSwitchIF* pwrSwitcher, SdCardManager& sdcMan) { auto* strAssy = new StrAssembly(objects::STR_ASSY); strAssy->connectModeTreeParent(satsystem::acs::ACS_SUBSYSTEM); auto* starTrackerCookie = @@ -949,9 +950,10 @@ void ObjectFactory::createStrComponents(PowerSwitchIF* pwrSwitcher) { sif::error << "No valid Star Tracker parameter JSON file" << std::endl; } auto strFdir = new StrFdir(objects::STAR_TRACKER); + auto cfgGetter = new StrConfigPathGetter(sdcMan); auto starTracker = new StarTrackerHandler(objects::STAR_TRACKER, objects::STR_COM_IF, starTrackerCookie, - paramJsonFile, strComIF, power::PDU1_CH2_STAR_TRACKER_5V); + strComIF, power::PDU1_CH2_STAR_TRACKER_5V, *cfgGetter); starTracker->setPowerSwitcher(pwrSwitcher); starTracker->connectModeTreeParent(*strAssy); starTracker->setCustomFdir(strFdir); diff --git a/bsp_q7s/objectFactory.h b/bsp_q7s/objectFactory.h index b3dfa83b..2e10dd71 100644 --- a/bsp_q7s/objectFactory.h +++ b/bsp_q7s/objectFactory.h @@ -15,6 +15,8 @@ #include #include +#include "bsp_q7s/fs/SdCardManager.h" + class LinuxLibgpioIF; class SerialComIF; class SpiComIF; @@ -75,7 +77,7 @@ void createHeaterComponents(GpioIF* gpioIF, PowerSwitchIF* pwrSwitcher, HealthTa HeaterHandler*& heaterHandler); void createImtqComponents(PowerSwitchIF* pwrSwitcher, bool enableHkSets, const char* i2cDev); void createBpxBatteryComponent(bool enableHkSets, const char* i2cDev); -void createStrComponents(PowerSwitchIF* pwrSwitcher); +void createStrComponents(PowerSwitchIF* pwrSwitcher, SdCardManager& sdcMan); void createSolarArrayDeploymentComponents(PowerSwitchIF& pwrSwitcher, GpioIF& gpioIF); void createSyrlinksComponents(PowerSwitchIF* pwrSwitcher); void createPayloadComponents(LinuxLibgpioIF* gpioComIF, PowerSwitchIF& pwrSwitcher); diff --git a/bsp_q7s/scheduling.cpp b/bsp_q7s/scheduling.cpp index 3c30e91a..fd99ab3f 100644 --- a/bsp_q7s/scheduling.cpp +++ b/bsp_q7s/scheduling.cpp @@ -383,11 +383,9 @@ void scheduling::initTasks() { } #endif /* OBSW_ADD_PLOC_SUPERVISOR */ - PeriodicTaskIF* plTask = factory->createPeriodicTask( - "PL_TASK", 25, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.5, missedDeadlineFunc, &RR_SCHEDULING); - plTask->addComponent(objects::CAM_SWITCHER); - scheduling::addMpsocSupvHandlers(plTask); - scheduling::scheduleScexDev(plTask); + FixedTimeslotTaskIF* plTask = factory->createFixedTimeslotTask( + "PL_TASK", 25, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.5, missedDeadlineFunc); + pst::pstPayload(plTask); #if OBSW_ADD_SCEX_DEVICE == 1 PeriodicTaskIF* scexReaderTask; diff --git a/cmake/scripts/q7s/q7s-make-debug.sh b/cmake/scripts/q7s/q7s-make-debug.sh index 0abbc3cb..a9536c97 100755 --- a/cmake/scripts/q7s/q7s-make-debug.sh +++ b/cmake/scripts/q7s/q7s-make-debug.sh @@ -24,6 +24,8 @@ if [ ! -z "${EIVE_Q7S_EM}" ]; then build_defs="EIVE_Q7S_EM=ON" fi +build_defs="${build_defs} CMAKE_EXPORT_COMPILE_COMMANDS=ON" + os_fsfw="linux" tgt_bsp="arm/q7s" build_dir="cmake-build-debug-q7s" diff --git a/cmake/scripts/q7s/q7s-make-release.sh b/cmake/scripts/q7s/q7s-make-release.sh index b86ca873..f5e970df 100755 --- a/cmake/scripts/q7s/q7s-make-release.sh +++ b/cmake/scripts/q7s/q7s-make-release.sh @@ -24,6 +24,8 @@ if [ ! -z "${EIVE_Q7S_EM}" ]; then build_defs="EIVE_Q7S_EM=ON" fi +build_defs="${build_defs} CMAKE_EXPORT_COMPILE_COMMANDS=ON" + os_fsfw="linux" tgt_bsp="arm/q7s" build_dir="cmake-build-release-q7s" diff --git a/generators/bsp_hosted_events.csv b/generators/bsp_hosted_events.csv index de7416f5..656843f1 100644 --- a/generators/bsp_hosted_events.csv +++ b/generators/bsp_hosted_events.csv @@ -143,14 +143,16 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path 11901;0x2e7d;BOOTING_FIRMWARE_FAILED_EVENT;LOW;Failed to boot firmware;mission/acs/str/StarTrackerHandler.h 11902;0x2e7e;BOOTING_BOOTLOADER_FAILED_EVENT;LOW;Failed to boot star tracker into bootloader mode;mission/acs/str/StarTrackerHandler.h 11903;0x2e7f;COM_ERROR_REPLY_RECEIVED;LOW;Received COM error. P1: Communication Error ID (datasheet p32);mission/acs/str/StarTrackerHandler.h -12001;0x2ee1;SUPV_MEMORY_READ_RPT_CRC_FAILURE;LOW;PLOC supervisor crc failure in telemetry packet;linux/payload/PlocSupervisorHandler.h -12002;0x2ee2;SUPV_UNKNOWN_TM;LOW;Unhandled event. P1: APID, P2: Service ID;linux/payload/PlocSupervisorHandler.h -12003;0x2ee3;SUPV_UNINIMPLEMENTED_TM;LOW;No description;linux/payload/PlocSupervisorHandler.h -12004;0x2ee4;SUPV_ACK_FAILURE;LOW;PLOC supervisor received acknowledgment failure report;linux/payload/PlocSupervisorHandler.h -12005;0x2ee5;SUPV_EXE_FAILURE;LOW;PLOC received execution failure report P1: ID of command for which the execution failed P2: Status code sent by the supervisor handler;linux/payload/PlocSupervisorHandler.h -12006;0x2ee6;SUPV_CRC_FAILURE_EVENT;LOW;PLOC supervisor reply has invalid crc;linux/payload/PlocSupervisorHandler.h -12007;0x2ee7;SUPV_HELPER_EXECUTING;LOW;Supervisor helper currently executing a command;linux/payload/PlocSupervisorHandler.h -12008;0x2ee8;SUPV_MPSOC_SHUTDOWN_BUILD_FAILED;LOW;Failed to build the command to shutdown the MPSoC;linux/payload/PlocSupervisorHandler.h +12001;0x2ee1;SUPV_MEMORY_READ_RPT_CRC_FAILURE;LOW;PLOC supervisor crc failure in telemetry packet;linux/payload/plocSupvDefs.h +12002;0x2ee2;SUPV_UNKNOWN_TM;LOW;Unhandled event. P1: APID, P2: Service ID;linux/payload/plocSupvDefs.h +12003;0x2ee3;SUPV_UNINIMPLEMENTED_TM;LOW;No description;linux/payload/plocSupvDefs.h +12004;0x2ee4;SUPV_ACK_FAILURE;LOW;PLOC supervisor received acknowledgment failure report;linux/payload/plocSupvDefs.h +12005;0x2ee5;SUPV_EXE_FAILURE;LOW;PLOC received execution failure report P1: ID of command for which the execution failed P2: Status code sent by the supervisor handler;linux/payload/plocSupvDefs.h +12006;0x2ee6;SUPV_CRC_FAILURE_EVENT;LOW;PLOC supervisor reply has invalid crc;linux/payload/plocSupvDefs.h +12007;0x2ee7;SUPV_HELPER_EXECUTING;LOW;Supervisor helper currently executing a command;linux/payload/plocSupvDefs.h +12008;0x2ee8;SUPV_MPSOC_SHUTDOWN_BUILD_FAILED;LOW;Failed to build the command to shutdown the MPSoC;linux/payload/plocSupvDefs.h +12009;0x2ee9;SUPV_ACK_UNKNOWN_COMMAND;LOW;Received ACK, but no related command is unknown or has not been sent by this software instance. P1: Module APID. P2: Service ID.;linux/payload/plocSupvDefs.h +12010;0x2eea;SUPV_EXE_ACK_UNKNOWN_COMMAND;LOW;Received ACK EXE, but no related command is unknown or has not been sent by this software instance. P1: Module APID. P2: Service ID.;linux/payload/plocSupvDefs.h 12100;0x2f44;SANITIZATION_FAILED;LOW;No description;bsp_q7s/fs/SdCardManager.h 12101;0x2f45;MOUNTED_SD_CARD;INFO;No description;bsp_q7s/fs/SdCardManager.h 12300;0x300c;SEND_MRAM_DUMP_FAILED;LOW;Failed to send mram dump command to supervisor handler P1: Return value of commandAction function P2: Start address of MRAM to dump with this command;linux/payload/PlocMemoryDumper.h diff --git a/generators/bsp_hosted_returnvalues.csv b/generators/bsp_hosted_returnvalues.csv index 1964e00e..abc43314 100644 --- a/generators/bsp_hosted_returnvalues.csv +++ b/generators/bsp_hosted_returnvalues.csv @@ -522,4 +522,5 @@ Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path 0x6f00;TMS_IsBusy;No description;0;TM_SINK;mission/tmtc/DirectTmSinkIF.h 0x6f01;TMS_PartiallyWritten;No description;1;TM_SINK;mission/tmtc/DirectTmSinkIF.h 0x6f02;TMS_NoWriteActive;No description;2;TM_SINK;mission/tmtc/DirectTmSinkIF.h +0x6f03;TMS_Timeout;No description;3;TM_SINK;mission/tmtc/DirectTmSinkIF.h 0x7000;VCS_ChannelDoesNotExist;No description;0;VIRTUAL_CHANNEL;mission/com/VirtualChannel.h diff --git a/generators/bsp_q7s_events.csv b/generators/bsp_q7s_events.csv index de7416f5..656843f1 100644 --- a/generators/bsp_q7s_events.csv +++ b/generators/bsp_q7s_events.csv @@ -143,14 +143,16 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path 11901;0x2e7d;BOOTING_FIRMWARE_FAILED_EVENT;LOW;Failed to boot firmware;mission/acs/str/StarTrackerHandler.h 11902;0x2e7e;BOOTING_BOOTLOADER_FAILED_EVENT;LOW;Failed to boot star tracker into bootloader mode;mission/acs/str/StarTrackerHandler.h 11903;0x2e7f;COM_ERROR_REPLY_RECEIVED;LOW;Received COM error. P1: Communication Error ID (datasheet p32);mission/acs/str/StarTrackerHandler.h -12001;0x2ee1;SUPV_MEMORY_READ_RPT_CRC_FAILURE;LOW;PLOC supervisor crc failure in telemetry packet;linux/payload/PlocSupervisorHandler.h -12002;0x2ee2;SUPV_UNKNOWN_TM;LOW;Unhandled event. P1: APID, P2: Service ID;linux/payload/PlocSupervisorHandler.h -12003;0x2ee3;SUPV_UNINIMPLEMENTED_TM;LOW;No description;linux/payload/PlocSupervisorHandler.h -12004;0x2ee4;SUPV_ACK_FAILURE;LOW;PLOC supervisor received acknowledgment failure report;linux/payload/PlocSupervisorHandler.h -12005;0x2ee5;SUPV_EXE_FAILURE;LOW;PLOC received execution failure report P1: ID of command for which the execution failed P2: Status code sent by the supervisor handler;linux/payload/PlocSupervisorHandler.h -12006;0x2ee6;SUPV_CRC_FAILURE_EVENT;LOW;PLOC supervisor reply has invalid crc;linux/payload/PlocSupervisorHandler.h -12007;0x2ee7;SUPV_HELPER_EXECUTING;LOW;Supervisor helper currently executing a command;linux/payload/PlocSupervisorHandler.h -12008;0x2ee8;SUPV_MPSOC_SHUTDOWN_BUILD_FAILED;LOW;Failed to build the command to shutdown the MPSoC;linux/payload/PlocSupervisorHandler.h +12001;0x2ee1;SUPV_MEMORY_READ_RPT_CRC_FAILURE;LOW;PLOC supervisor crc failure in telemetry packet;linux/payload/plocSupvDefs.h +12002;0x2ee2;SUPV_UNKNOWN_TM;LOW;Unhandled event. P1: APID, P2: Service ID;linux/payload/plocSupvDefs.h +12003;0x2ee3;SUPV_UNINIMPLEMENTED_TM;LOW;No description;linux/payload/plocSupvDefs.h +12004;0x2ee4;SUPV_ACK_FAILURE;LOW;PLOC supervisor received acknowledgment failure report;linux/payload/plocSupvDefs.h +12005;0x2ee5;SUPV_EXE_FAILURE;LOW;PLOC received execution failure report P1: ID of command for which the execution failed P2: Status code sent by the supervisor handler;linux/payload/plocSupvDefs.h +12006;0x2ee6;SUPV_CRC_FAILURE_EVENT;LOW;PLOC supervisor reply has invalid crc;linux/payload/plocSupvDefs.h +12007;0x2ee7;SUPV_HELPER_EXECUTING;LOW;Supervisor helper currently executing a command;linux/payload/plocSupvDefs.h +12008;0x2ee8;SUPV_MPSOC_SHUTDOWN_BUILD_FAILED;LOW;Failed to build the command to shutdown the MPSoC;linux/payload/plocSupvDefs.h +12009;0x2ee9;SUPV_ACK_UNKNOWN_COMMAND;LOW;Received ACK, but no related command is unknown or has not been sent by this software instance. P1: Module APID. P2: Service ID.;linux/payload/plocSupvDefs.h +12010;0x2eea;SUPV_EXE_ACK_UNKNOWN_COMMAND;LOW;Received ACK EXE, but no related command is unknown or has not been sent by this software instance. P1: Module APID. P2: Service ID.;linux/payload/plocSupvDefs.h 12100;0x2f44;SANITIZATION_FAILED;LOW;No description;bsp_q7s/fs/SdCardManager.h 12101;0x2f45;MOUNTED_SD_CARD;INFO;No description;bsp_q7s/fs/SdCardManager.h 12300;0x300c;SEND_MRAM_DUMP_FAILED;LOW;Failed to send mram dump command to supervisor handler P1: Return value of commandAction function P2: Start address of MRAM to dump with this command;linux/payload/PlocMemoryDumper.h diff --git a/generators/bsp_q7s_returnvalues.csv b/generators/bsp_q7s_returnvalues.csv index 9aa12b12..d2922a1c 100644 --- a/generators/bsp_q7s_returnvalues.csv +++ b/generators/bsp_q7s_returnvalues.csv @@ -617,5 +617,6 @@ Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path 0x6f00;TMS_IsBusy;No description;0;TM_SINK;mission/tmtc/DirectTmSinkIF.h 0x6f01;TMS_PartiallyWritten;No description;1;TM_SINK;mission/tmtc/DirectTmSinkIF.h 0x6f02;TMS_NoWriteActive;No description;2;TM_SINK;mission/tmtc/DirectTmSinkIF.h +0x6f03;TMS_Timeout;No description;3;TM_SINK;mission/tmtc/DirectTmSinkIF.h 0x7000;VCS_ChannelDoesNotExist;No description;0;VIRTUAL_CHANNEL;mission/com/VirtualChannel.h 0x7200;SCBU_KeyNotFound;No description;0;SCRATCH_BUFFER;bsp_q7s/memory/scratchApi.h diff --git a/generators/events/translateEvents.cpp b/generators/events/translateEvents.cpp index 099a4c7a..92401ab1 100644 --- a/generators/events/translateEvents.cpp +++ b/generators/events/translateEvents.cpp @@ -1,7 +1,7 @@ /** - * @brief Auto-generated event translation file. Contains 315 translations. + * @brief Auto-generated event translation file. Contains 317 translations. * @details - * Generated on: 2023-10-27 14:24:05 + * Generated on: 2023-11-29 15:14:46 */ #include "translateEvents.h" @@ -157,6 +157,8 @@ const char *SUPV_EXE_FAILURE_STRING = "SUPV_EXE_FAILURE"; const char *SUPV_CRC_FAILURE_EVENT_STRING = "SUPV_CRC_FAILURE_EVENT"; const char *SUPV_HELPER_EXECUTING_STRING = "SUPV_HELPER_EXECUTING"; const char *SUPV_MPSOC_SHUTDOWN_BUILD_FAILED_STRING = "SUPV_MPSOC_SHUTDOWN_BUILD_FAILED"; +const char *SUPV_ACK_UNKNOWN_COMMAND_STRING = "SUPV_ACK_UNKNOWN_COMMAND"; +const char *SUPV_EXE_ACK_UNKNOWN_COMMAND_STRING = "SUPV_EXE_ACK_UNKNOWN_COMMAND"; const char *SANITIZATION_FAILED_STRING = "SANITIZATION_FAILED"; const char *MOUNTED_SD_CARD_STRING = "MOUNTED_SD_CARD"; const char *SEND_MRAM_DUMP_FAILED_STRING = "SEND_MRAM_DUMP_FAILED"; @@ -627,6 +629,10 @@ const char *translateEvents(Event event) { return SUPV_HELPER_EXECUTING_STRING; case (12008): return SUPV_MPSOC_SHUTDOWN_BUILD_FAILED_STRING; + case (12009): + return SUPV_ACK_UNKNOWN_COMMAND_STRING; + case (12010): + return SUPV_EXE_ACK_UNKNOWN_COMMAND_STRING; case (12100): return SANITIZATION_FAILED_STRING; case (12101): diff --git a/generators/objects/translateObjects.cpp b/generators/objects/translateObjects.cpp index 5cc157c2..2af38f77 100644 --- a/generators/objects/translateObjects.cpp +++ b/generators/objects/translateObjects.cpp @@ -2,7 +2,7 @@ * @brief Auto-generated object translation file. * @details * Contains 179 translations. - * Generated on: 2023-10-27 14:24:05 + * Generated on: 2023-11-29 15:14:46 */ #include "translateObjects.h" diff --git a/linux/acs/StrComHandler.cpp b/linux/acs/StrComHandler.cpp index 2db73f35..0bb4d749 100644 --- a/linux/acs/StrComHandler.cpp +++ b/linux/acs/StrComHandler.cpp @@ -54,7 +54,7 @@ ReturnValue_t StrComHandler::performOperation(uint8_t operationCode) { switch (state) { case InternalState::POLL_ONE_REPLY: { // Stopwatch watch; - replyTimeout.setTimeout(200); + replyTimeout.setTimeout(400); readOneReply(static_cast(state)); { MutexGuard mg(lock); @@ -720,7 +720,7 @@ ReturnValue_t StrComHandler::readReceivedMessage(CookieIF* cookie, uint8_t** buf { MutexGuard mg(lock); if (state != InternalState::SLEEPING) { - return returnvalue::OK; + return BUSY; } replyWasReceived = this->replyWasReceived; } @@ -733,7 +733,7 @@ ReturnValue_t StrComHandler::readReceivedMessage(CookieIF* cookie, uint8_t** buf *size = replyLen; } replyLen = 0; - return returnvalue::OK; + return replyResult; } ReturnValue_t StrComHandler::unlockAndEraseRegions(uint32_t from, uint32_t to) { diff --git a/linux/fsfwconfig/events/translateEvents.cpp b/linux/fsfwconfig/events/translateEvents.cpp index 099a4c7a..92401ab1 100644 --- a/linux/fsfwconfig/events/translateEvents.cpp +++ b/linux/fsfwconfig/events/translateEvents.cpp @@ -1,7 +1,7 @@ /** - * @brief Auto-generated event translation file. Contains 315 translations. + * @brief Auto-generated event translation file. Contains 317 translations. * @details - * Generated on: 2023-10-27 14:24:05 + * Generated on: 2023-11-29 15:14:46 */ #include "translateEvents.h" @@ -157,6 +157,8 @@ const char *SUPV_EXE_FAILURE_STRING = "SUPV_EXE_FAILURE"; const char *SUPV_CRC_FAILURE_EVENT_STRING = "SUPV_CRC_FAILURE_EVENT"; const char *SUPV_HELPER_EXECUTING_STRING = "SUPV_HELPER_EXECUTING"; const char *SUPV_MPSOC_SHUTDOWN_BUILD_FAILED_STRING = "SUPV_MPSOC_SHUTDOWN_BUILD_FAILED"; +const char *SUPV_ACK_UNKNOWN_COMMAND_STRING = "SUPV_ACK_UNKNOWN_COMMAND"; +const char *SUPV_EXE_ACK_UNKNOWN_COMMAND_STRING = "SUPV_EXE_ACK_UNKNOWN_COMMAND"; const char *SANITIZATION_FAILED_STRING = "SANITIZATION_FAILED"; const char *MOUNTED_SD_CARD_STRING = "MOUNTED_SD_CARD"; const char *SEND_MRAM_DUMP_FAILED_STRING = "SEND_MRAM_DUMP_FAILED"; @@ -627,6 +629,10 @@ const char *translateEvents(Event event) { return SUPV_HELPER_EXECUTING_STRING; case (12008): return SUPV_MPSOC_SHUTDOWN_BUILD_FAILED_STRING; + case (12009): + return SUPV_ACK_UNKNOWN_COMMAND_STRING; + case (12010): + return SUPV_EXE_ACK_UNKNOWN_COMMAND_STRING; case (12100): return SANITIZATION_FAILED_STRING; case (12101): diff --git a/linux/fsfwconfig/objects/translateObjects.cpp b/linux/fsfwconfig/objects/translateObjects.cpp index 5cc157c2..2af38f77 100644 --- a/linux/fsfwconfig/objects/translateObjects.cpp +++ b/linux/fsfwconfig/objects/translateObjects.cpp @@ -2,7 +2,7 @@ * @brief Auto-generated object translation file. * @details * Contains 179 translations. - * Generated on: 2023-10-27 14:24:05 + * Generated on: 2023-11-29 15:14:46 */ #include "translateObjects.h" diff --git a/linux/ipcore/PapbVcInterface.cpp b/linux/ipcore/PapbVcInterface.cpp index c02d0935..e4414363 100644 --- a/linux/ipcore/PapbVcInterface.cpp +++ b/linux/ipcore/PapbVcInterface.cpp @@ -30,6 +30,7 @@ ReturnValue_t PapbVcInterface::initialize() { ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size, size_t& writtenSize) { // There are no packets smaller than 4, this is considered a configuration error. if (size < 4) { + sif::warning << "PapbVcInterface::write: Passed packet smaller than 4 bytes" << std::endl; return returnvalue::FAILED; } // The user must call advance until completion before starting a new packet transfer. @@ -83,6 +84,9 @@ ReturnValue_t PapbVcInterface::advanceWrite(size_t& writtenSize) { writtenSize++; } if (not pollReadyForOctet(MAX_BUSY_POLLS)) { + if (not pollReadyForPacket()) { + return PARTIALLY_WRITTEN; + } abortPacketTransfer(); return returnvalue::FAILED; } diff --git a/linux/payload/CMakeLists.txt b/linux/payload/CMakeLists.txt index e697fac6..48fb9d96 100644 --- a/linux/payload/CMakeLists.txt +++ b/linux/payload/CMakeLists.txt @@ -2,9 +2,9 @@ target_sources( ${OBSW_NAME} PUBLIC PlocMemoryDumper.cpp PlocMpsocHandler.cpp + FreshSupvHandler.cpp PlocMpsocSpecialComHelper.cpp plocMpsocHelpers.cpp - PlocSupervisorHandler.cpp PlocSupvUartMan.cpp ScexDleParser.cpp ScexHelper.cpp diff --git a/linux/payload/FreshSupvHandler.cpp b/linux/payload/FreshSupvHandler.cpp new file mode 100644 index 00000000..0d34b63f --- /dev/null +++ b/linux/payload/FreshSupvHandler.cpp @@ -0,0 +1,1584 @@ +#include "FreshSupvHandler.h" + +#include +#include + +#include +#include + +#include "eive/definitions.h" +#include "eive/objects.h" +#include "fsfw/action.h" +#include "fsfw/globalfunctions/arrayprinter.h" +#include "fsfw/ipc/CommandMessage.h" +#include "fsfw/ipc/MessageQueueIF.h" +#include "fsfw/ipc/QueueFactory.h" +#include "fsfw/objectmanager/ObjectManagerIF.h" +#include "fsfw/returnvalues/returnvalue.h" +#include "fsfw/tasks/TaskFactory.h" +#include "linux/payload/plocSupvDefs.h" + +using namespace supv; +using namespace returnvalue; + +std::atomic_bool supv::SUPV_ON = false; + +FreshSupvHandler::FreshSupvHandler(DhbConfig cfg, CookieIF* comCookie, Gpio uartIsolatorSwitch, + PowerSwitchIF& switchIF, power::Switch_t powerSwitch) + : FreshDeviceHandlerBase(cfg), + comCookie(comCookie), + switchIF(switchIF), + switchId(powerSwitch), + uartIsolatorSwitch(uartIsolatorSwitch), + hkSet(this), + bootStatusReport(this), + latchupStatusReport(this), + countersReport(this), + adcReport(this) { + spParams.buf = commandBuffer.data(); + spParams.maxSize = commandBuffer.size(); + eventQueue = QueueFactory::instance()->createMessageQueue(10); +} + +void FreshSupvHandler::performDeviceOperation(uint8_t opCode) { + if (not transitionActive and mode == MODE_OFF) { + // Nothing to do for now. + return; + } + if (opCode == OpCode::DEFAULT_OPERATION) { + EventMessage event; + for (ReturnValue_t result = eventQueue->receiveMessage(&event); result == returnvalue::OK; + result = eventQueue->receiveMessage(&event)) { + switch (event.getMessageId()) { + case EventMessage::EVENT_MESSAGE: + handleEvent(&event); + break; + default: + sif::debug + << "PlocSupervisorHandler::performOperationHook: Did not subscribe to this event" + << " message" << std::endl; + break; + } + } + if (transitionActive) { + if (targetMode == MODE_ON or targetMode == MODE_NORMAL) { + handleTransitionToOn(); + } else if (targetMode == MODE_OFF) { + handleTransitionToOff(); + } else { + // This should never happen. + sif::error << "FreshSupvHandler: Invalid transition mode: " << targetMode << std::endl; + targetMode = MODE_OFF; + targetSubmode = 0; + handleTransitionToOff(); + } + } else { + // I think the SUPV is not able to process multiple commands consecutively, so only send + // normal command if no other command is pending. We handle the action queue first, which + // should ensure that these commands take precendence. + if (mode == MODE_NORMAL and not isCommandPending()) { + auto cmdIter = activeActionCmds.find( + buildActiveCmdKey(Apid::HK, static_cast(tc::HkId::GET_REPORT))); + if (cmdIter == activeActionCmds.end() or not cmdIter->second.isPending) { + spParams.buf = commandBuffer.data(); + commandedByCached = MessageQueueIF::NO_QUEUE; + sendEmptyCmd(supv::GET_HK_REPORT, Apid::HK, static_cast(tc::HkId::GET_REPORT), + true); + } + } + } + } else if (opCode == OpCode::PARSE_TM) { + for (auto& activeCmd : activeActionCmds) { + if (activeCmd.second.isPending and activeCmd.second.cmdCountdown.hasTimedOut()) { + if (activeCmd.second.commandedBy != MessageQueueIF::NO_QUEUE) { + actionHelper.finish(false, activeCmd.second.commandedBy, activeCmd.first, + DeviceHandlerIF::TIMEOUT); + } + activeCmd.second.isPending = false; + } + } + + parseTmPackets(); + } +} + +ReturnValue_t FreshSupvHandler::performDeviceOperationPreQueueHandling(uint8_t opCode) { + if (opCode != OpCode::DEFAULT_OPERATION) { + return returnvalue::OK; + } + // We parse for TM packets shortly before handling the queue, this might complete some packets, + // which then allows the handling of new action commands. + return parseTmPackets(); +} + +ReturnValue_t FreshSupvHandler::handleCommandMessage(CommandMessage* message) { + // No custom messages. + return returnvalue::FAILED; +} + +LocalPoolDataSetBase* FreshSupvHandler::getDataSetHandle(sid_t sid) { + if (sid == hkSet.getSid()) { + return &hkSet; + } else if (sid == bootStatusReport.getSid()) { + return &bootStatusReport; + } else if (sid == latchupStatusReport.getSid()) { + return &latchupStatusReport; + } else if (sid == countersReport.getSid()) { + return &countersReport; + } else if (sid == adcReport.getSid()) { + return &adcReport; + } + return nullptr; +} + +ReturnValue_t FreshSupvHandler::initializeLocalDataPool(localpool::DataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) { + // TODO: Copy code from god handler here. + localDataPoolMap.emplace(supv::NUM_TMS, new PoolEntry({0})); + localDataPoolMap.emplace(supv::TEMP_PS, new PoolEntry({0})); + localDataPoolMap.emplace(supv::TEMP_PL, new PoolEntry({0})); + localDataPoolMap.emplace(supv::HK_SOC_STATE, new PoolEntry({0})); + localDataPoolMap.emplace(supv::NVM0_1_STATE, new PoolEntry({0})); + localDataPoolMap.emplace(supv::NVM3_STATE, new PoolEntry({0})); + localDataPoolMap.emplace(supv::MISSION_IO_STATE, new PoolEntry({0})); + localDataPoolMap.emplace(supv::FMC_STATE, &fmcStateEntry); + localDataPoolMap.emplace(supv::NUM_TCS, new PoolEntry({0})); + localDataPoolMap.emplace(supv::TEMP_SUP, &tempSupEntry); + localDataPoolMap.emplace(supv::UPTIME, new PoolEntry({0})); + localDataPoolMap.emplace(supv::CPULOAD, new PoolEntry({0})); + localDataPoolMap.emplace(supv::AVAILABLEHEAP, new PoolEntry({0})); + + localDataPoolMap.emplace(supv::BR_SOC_STATE, new PoolEntry({0})); + localDataPoolMap.emplace(supv::POWER_CYCLES, new PoolEntry({0})); + localDataPoolMap.emplace(supv::BOOT_AFTER_MS, new PoolEntry({0})); + localDataPoolMap.emplace(supv::BOOT_TIMEOUT_POOL_VAR_MS, new PoolEntry({0})); + localDataPoolMap.emplace(supv::ACTIVE_NVM, new PoolEntry({0})); + localDataPoolMap.emplace(supv::BP0_STATE, new PoolEntry({0})); + localDataPoolMap.emplace(supv::BP1_STATE, new PoolEntry({0})); + localDataPoolMap.emplace(supv::BP2_STATE, new PoolEntry({0})); + localDataPoolMap.emplace(supv::BOOT_STATE, &bootStateEntry); + localDataPoolMap.emplace(supv::BOOT_CYCLES, &bootCyclesEntry); + + localDataPoolMap.emplace(supv::LATCHUP_ID, new PoolEntry({0})); + localDataPoolMap.emplace(supv::CNT0, new PoolEntry({0})); + localDataPoolMap.emplace(supv::CNT1, new PoolEntry({0})); + localDataPoolMap.emplace(supv::CNT2, new PoolEntry({0})); + localDataPoolMap.emplace(supv::CNT3, new PoolEntry({0})); + localDataPoolMap.emplace(supv::CNT4, new PoolEntry({0})); + localDataPoolMap.emplace(supv::CNT5, new PoolEntry({0})); + localDataPoolMap.emplace(supv::CNT6, new PoolEntry({0})); + localDataPoolMap.emplace(supv::LATCHUP_RPT_TIME_MSEC, new PoolEntry({0})); + localDataPoolMap.emplace(supv::LATCHUP_RPT_TIME_SEC, new PoolEntry({0})); + localDataPoolMap.emplace(supv::LATCHUP_RPT_TIME_MIN, new PoolEntry({0})); + localDataPoolMap.emplace(supv::LATCHUP_RPT_TIME_HOUR, new PoolEntry({0})); + localDataPoolMap.emplace(supv::LATCHUP_RPT_TIME_DAY, new PoolEntry({0})); + localDataPoolMap.emplace(supv::LATCHUP_RPT_TIME_MON, new PoolEntry({0})); + localDataPoolMap.emplace(supv::LATCHUP_RPT_TIME_YEAR, new PoolEntry({0})); + localDataPoolMap.emplace(supv::LATCHUP_RPT_IS_SET, new PoolEntry({0})); + + localDataPoolMap.emplace(supv::SIGNATURE, new PoolEntry()); + localDataPoolMap.emplace(supv::LATCHUP_HAPPENED_CNTS, &latchupCounters); + localDataPoolMap.emplace(supv::ADC_DEVIATION_TRIGGERS_CNT, new PoolEntry({0})); + localDataPoolMap.emplace(supv::TC_RECEIVED_CNT, new PoolEntry({0})); + localDataPoolMap.emplace(supv::TM_AVAILABLE_CNT, new PoolEntry({0})); + localDataPoolMap.emplace(supv::SUPERVISOR_BOOTS, new PoolEntry({0})); + localDataPoolMap.emplace(supv::MPSOC_BOOTS, new PoolEntry({0})); + localDataPoolMap.emplace(supv::MPSOC_BOOT_FAILED_ATTEMPTS, new PoolEntry({0})); + localDataPoolMap.emplace(supv::MPSOC_POWER_UP, new PoolEntry({0})); + localDataPoolMap.emplace(supv::MPSOC_UPDATES, new PoolEntry({0})); + localDataPoolMap.emplace(supv::MPSOC_HEARTBEAT_RESETS, new PoolEntry({0})); + localDataPoolMap.emplace(supv::CPU_WDT_RESETS, new PoolEntry({0})); + localDataPoolMap.emplace(supv::PS_HEARTBEATS_LOST, new PoolEntry({0})); + localDataPoolMap.emplace(supv::PL_HEARTBEATS_LOST, new PoolEntry({0})); + localDataPoolMap.emplace(supv::EB_TASK_LOST, new PoolEntry({0})); + localDataPoolMap.emplace(supv::BM_TASK_LOST, new PoolEntry({0})); + localDataPoolMap.emplace(supv::LM_TASK_LOST, new PoolEntry({0})); + localDataPoolMap.emplace(supv::AM_TASK_LOST, new PoolEntry({0})); + localDataPoolMap.emplace(supv::TCTMM_TASK_LOST, new PoolEntry({0})); + localDataPoolMap.emplace(supv::MM_TASK_LOST, new PoolEntry({0})); + localDataPoolMap.emplace(supv::HK_TASK_LOST, new PoolEntry({0})); + localDataPoolMap.emplace(supv::DL_TASK_LOST, new PoolEntry({0})); + localDataPoolMap.emplace(supv::RWS_TASKS_LOST, new PoolEntry(3)); + + localDataPoolMap.emplace(supv::ADC_RAW, &adcRawEntry); + localDataPoolMap.emplace(supv::ADC_ENG, &adcEngEntry); + + poolManager.subscribeForRegularPeriodicPacket( + subdp::RegularHkPeriodicParams(hkSet.getSid(), false, 10.0)); + return returnvalue::OK; +} + +ReturnValue_t FreshSupvHandler::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy, + const uint8_t* data, size_t size) { + using namespace supv; + // The SUPV does not have any action commands where there is no communication with the device + // involved. + if (mode != MODE_ON and mode != MODE_NORMAL) { + return HasModesIF::INVALID_MODE; + } + ReturnValue_t result; + if (uartManager->longerRequestActive()) { + return result::SUPV_HELPER_EXECUTING; + } + + switch (actionId) { + case PERFORM_UPDATE: { + if (size > config::MAX_PATH_SIZE + config::MAX_FILENAME_SIZE) { + return result::FILENAME_TOO_LONG; + } + UpdateParams params; + result = extractUpdateCommand(data, size, params); + if (result != returnvalue::OK) { + return result; + } + result = uartManager->performUpdate(params); + if (result != returnvalue::OK) { + return result; + } + return EXECUTION_FINISHED; + } + case CONTINUE_UPDATE: { + uartManager->initiateUpdateContinuation(); + return EXECUTION_FINISHED; + } + case MEMORY_CHECK_WITH_FILE: { + UpdateParams params; + result = extractBaseParams(&data, size, params); + if (result != returnvalue::OK) { + return result; + } + if (not std::filesystem::exists(params.file)) { + return HasFileSystemIF::FILE_DOES_NOT_EXIST; + } + uartManager->performMemCheck(params.file, params.memId, params.startAddr); + return EXECUTION_FINISHED; + } + default: + break; + } + // The PLOC SUPV is not able to process multiple commands consecutively. + if (isCommandPending()) { + return HasActionsIF::IS_BUSY; + } + if (isCommandAlreadyActive(actionId)) { + return HasActionsIF::IS_BUSY; + } + spParams.buf = commandBuffer.data(); + this->commandedByCached = commandedBy; + switch (actionId) { + case GET_HK_REPORT: { + sendEmptyCmd(supv::GET_HK_REPORT, Apid::HK, static_cast(tc::HkId::GET_REPORT), true); + result = returnvalue::OK; + break; + } + case START_MPSOC: { + sif::info << "PLOC SUPV: Starting MPSoC" << std::endl; + sendEmptyCmd(supv::START_MPSOC, Apid::BOOT_MAN, + static_cast(tc::BootManId::START_MPSOC), false); + result = returnvalue::OK; + break; + } + case SHUTDOWN_MPSOC: { + sif::info << "PLOC SUPV: Shutting down MPSoC" << std::endl; + sendEmptyCmd(supv::SHUTDOWN_MPSOC, Apid::BOOT_MAN, + static_cast(tc::BootManId::SHUTDOWN_MPSOC), false); + result = returnvalue::OK; + break; + } + case SEL_MPSOC_BOOT_IMAGE: { + prepareSelBootImageCmd(data); + result = returnvalue::OK; + break; + } + case RESET_MPSOC: { + sif::info << "PLOC SUPV: Resetting MPSoC" << std::endl; + sendEmptyCmd(supv::RESET_MPSOC, Apid::BOOT_MAN, + static_cast(tc::BootManId::RESET_MPSOC), false); + result = returnvalue::OK; + break; + } + case SET_TIME_REF: { + result = prepareSetTimeRefCmd(); + break; + } + case SET_BOOT_TIMEOUT: { + prepareSetBootTimeoutCmd(data, size); + result = returnvalue::OK; + break; + } + case SET_MAX_RESTART_TRIES: { + prepareRestartTriesCmd(data, size); + result = returnvalue::OK; + break; + } + case DISABLE_PERIOIC_HK_TRANSMISSION: { + prepareDisableHk(); + result = returnvalue::OK; + break; + } + case GET_BOOT_STATUS_REPORT: { + sendEmptyCmd(supv::GET_BOOT_STATUS_REPORT, Apid::BOOT_MAN, + static_cast(tc::BootManId::GET_BOOT_STATUS_REPORT), true); + result = returnvalue::OK; + break; + } + case ENABLE_LATCHUP_ALERT: { + result = prepareLatchupConfigCmd(data, actionId, size); + break; + } + case DISABLE_LATCHUP_ALERT: { + result = prepareLatchupConfigCmd(data, actionId, size); + break; + } + case SET_ALERT_LIMIT: { + result = prepareSetAlertLimitCmd(data, size); + break; + } + case GET_LATCHUP_STATUS_REPORT: { + sendEmptyCmd(supv::GET_LATCHUP_STATUS_REPORT, Apid::LATCHUP_MON, + static_cast(tc::LatchupMonId::GET_STATUS_REPORT), true); + result = returnvalue::OK; + break; + } + case SET_GPIO: { + result = prepareSetGpioCmd(data, size); + break; + } + case FACTORY_RESET: { + result = prepareFactoryResetCmd(data, size); + break; + } + case READ_GPIO: { + result = prepareReadGpioCmd(data, size); + break; + } + case SET_SHUTDOWN_TIMEOUT: { + prepareSetShutdownTimeoutCmd(data, size); + result = returnvalue::OK; + break; + } + case FACTORY_FLASH: { + sendEmptyCmd(supv::FACTORY_FLASH, Apid::BOOT_MAN, + static_cast(tc::BootManId::FACTORY_FLASH), false); + result = returnvalue::OK; + break; + } + case RESET_PL: { + sendEmptyCmd(supv::RESET_PL, Apid::BOOT_MAN, static_cast(tc::BootManId::RESET_PL), + false); + result = returnvalue::OK; + break; + } + case SET_ADC_ENABLED_CHANNELS: { + prepareSetAdcEnabledChannelsCmd(data); + result = returnvalue::OK; + break; + } + case SET_ADC_WINDOW_AND_STRIDE: { + prepareSetAdcWindowAndStrideCmd(data); + result = returnvalue::OK; + break; + } + case SET_ADC_THRESHOLD: { + prepareSetAdcThresholdCmd(data); + result = returnvalue::OK; + break; + } + case WIPE_MRAM: { + result = prepareWipeMramCmd(data, size); + break; + } + case REQUEST_ADC_REPORT: { + sendEmptyCmd(supv::REQUEST_ADC_REPORT, Apid::ADC_MON, + static_cast(tc::AdcMonId::REQUEST_ADC_SAMPLE), true); + result = returnvalue::OK; + break; + } + case REQUEST_LOGGING_COUNTERS: { + sendEmptyCmd(supv::REQUEST_LOGGING_COUNTERS, Apid::DATA_LOGGER, + static_cast(tc::DataLoggerServiceId::REQUEST_COUNTERS), true); + result = returnvalue::OK; + break; + } + default: + sif::debug << "PlocSupervisorHandler::buildCommandFromCommand: Command not implemented" + << std::endl; + result = DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; + break; + } + return result; +} + +ReturnValue_t FreshSupvHandler::prepareSetTimeRefCmd() { + Clock::TimeOfDay_t time; + ReturnValue_t result = Clock::getDateAndTime(&time); + if (result != returnvalue::OK) { + sif::warning << "PlocSupervisorHandler::prepareSetTimeRefCmd: Failed to get current time" + << std::endl; + return result::GET_TIME_FAILURE; + } + supv::SetTimeRef packet(spParams); + result = packet.buildPacket(&time); + if (result != returnvalue::OK) { + return result; + } + sendCommand(supv::SET_TIME_REF, packet, false); + return returnvalue::OK; +} + +ReturnValue_t FreshSupvHandler::checkModeCommand(Mode_t commandedMode, Submode_t commandedSubmode, + uint32_t* msToReachTheMode) { + if (commandedMode != MODE_OFF) { + PoolReadGuard pg(&enablePl); + if (pg.getReadResult() == returnvalue::OK) { + if (enablePl.plUseAllowed.isValid() and not enablePl.plUseAllowed.value) { + return NON_OP_STATE_OF_CHARGE; + } + } + } + if (commandedMode != HasModesIF::MODE_OFF and commandedMode != HasModesIF::MODE_ON and + commandedMode != MODE_NORMAL) { + return returnvalue::FAILED; + } + if (commandedMode != mode and msToReachTheMode != nullptr) { + if (commandedMode == MODE_OFF) { + *msToReachTheMode = supv::MAX_TRANSITION_TIME_TO_OFF_MS; + } else { + *msToReachTheMode = supv::MAX_TRANSITION_TIME_TO_ON_MS; + } + } + return returnvalue::OK; +} + +ReturnValue_t FreshSupvHandler::prepareSelBootImageCmd(const uint8_t* commandData) { + supv::MPSoCBootSelect packet(spParams); + ReturnValue_t result = + packet.buildPacket(commandData[0], commandData[1], commandData[2], commandData[3]); + if (result != returnvalue::OK) { + return result; + } + sendCommand(supv::SEL_MPSOC_BOOT_IMAGE, packet, false); + return returnvalue::OK; +} + +void FreshSupvHandler::startTransition(Mode_t newMode, Submode_t newSubmode) { + if (newMode == mode or (mode == MODE_ON and newMode == MODE_NORMAL) or + (newMode == MODE_ON and mode == MODE_NORMAL)) { + // Can finish immediately. + setMode(newMode, newSubmode); + return; + } + // Transition for both OFF to ON/NORMAL and ON/NORMAL to OFF require small state machine. + transitionActive = true; + targetMode = newMode; + targetSubmode = newSubmode; + if (targetMode == MODE_ON or targetMode == MODE_NORMAL) { + startupState = StartupState::IDLE; + } else if (targetMode == MODE_OFF) { + shutdownState = ShutdownState::IDLE; + } +} + +void FreshSupvHandler::handleTransitionToOn() { + if (startupState == StartupState::IDLE) { + startupState = StartupState::POWER_SWITCHING; + switchIF.sendSwitchCommand(switchId, PowerSwitchIF::SWITCH_ON); + switchTimeout.resetTimer(); + } else if (modeHelper.isTimedOut()) { + targetMode = MODE_OFF; + shutdownState = ShutdownState::IDLE; + handleTransitionToOff(); + return; + } + if (startupState == StartupState::POWER_SWITCHING) { + if (switchIF.getSwitchState(switchId) == PowerSwitchIF::SWITCH_ON) { + startupState = StartupState::BOOTING; + bootTimeout.resetTimer(); + } else if (switchTimeout.hasTimedOut()) { + targetMode = MODE_OFF; + shutdownState = ShutdownState::IDLE; + handleTransitionToOff(); + return; + } + } + if (startupState == StartupState::BOOTING and bootTimeout.hasTimedOut()) { + uartIsolatorSwitch.pullHigh(); + uartManager->start(); + if (SET_TIME_DURING_BOOT) { + startupState = StartupState::SET_TIME; + } else { + startupState = StartupState::ON; + } + } + if (startupState == StartupState::SET_TIME) { + spParams.buf = commandBuffer.data(); + ReturnValue_t result = prepareSetTimeRefCmd(); + if (result != returnvalue::OK) { + sif::error << "FreshSupvHandler: Setting time command prepration failed" << std::endl; + startupState = StartupState::ON; + } else { + startupState = StartupState::WAIT_FOR_TIME_REPLY; + } + } + if (startupState == StartupState::TIME_WAS_SET) { + startupState = StartupState::ON; + } + if (startupState == StartupState::ON) { + hkSet.setReportingEnabled(true); + supv::SUPV_ON = true; + transitionActive = false; + setMode(targetMode); + } +} + +void FreshSupvHandler::handleTransitionToOff() { + if (shutdownState == ShutdownState::IDLE) { + hkSet.setReportingEnabled(false); + hkSet.setValidity(false, true); + uartManager->stop(); + activeActionCmds.clear(); + uartIsolatorSwitch.pullLow(); + switchIF.sendSwitchCommand(switchId, PowerSwitchIF::SWITCH_OFF); + shutdownState = ShutdownState::POWER_SWITCHING; + } + if (shutdownState == ShutdownState::POWER_SWITCHING) { + if (switchIF.getSwitchState(switchId) == PowerSwitchIF::SWITCH_OFF or modeHelper.isTimedOut()) { + supv::SUPV_ON = false; + transitionActive = false; + setMode(MODE_OFF); + } + } +} + +ReturnValue_t FreshSupvHandler::sendCommand(DeviceCommandId_t commandId, TcBase& tc, + bool replyExpected, uint32_t cmdCountdownMs) { + if (supv::DEBUG_PLOC_SUPV) { + if (not(supv::REDUCE_NORMAL_MODE_PRINTOUT and mode == MODE_NORMAL and + commandId == supv::GET_HK_REPORT)) { + sif::debug << "PLOC SUPV: SEND PACKET Size " << tc.getFullPacketLen() << " Module APID " + << (int)tc.getModuleApid() << " Service ID " << (int)tc.getServiceId() + << std::endl; + } + } + ActiveCmdInfo info(commandId, cmdCountdownMs); + auto activeCmdIter = + activeActionCmds.find(buildActiveCmdKey(tc.getModuleApid(), tc.getServiceId())); + if (activeCmdIter == activeActionCmds.end()) { + info.isPending = true; + info.replyPacketExpected = replyExpected; + info.commandedBy = commandedByCached; + info.cmdCountdown.resetTimer(); + activeActionCmds.emplace(buildActiveCmdKey(tc.getModuleApid(), tc.getServiceId()), info); + } else { + if (activeCmdIter->second.isPending) { + return HasActionsIF::IS_BUSY; + } + activeCmdIter->second.isPending = true; + activeCmdIter->second.commandId = commandId; + activeCmdIter->second.commandedBy = commandedByCached; + activeCmdIter->second.ackRecv = false; + activeCmdIter->second.ackExeRecv = false; + activeCmdIter->second.replyPacketExpected = replyExpected; + activeCmdIter->second.replyPacketReceived = false; + activeCmdIter->second.cmdCountdown.setTimeout(cmdCountdownMs); + activeCmdIter->second.cmdCountdown.resetTimer(); + } + ReturnValue_t result = + uartManager->sendMessage(comCookie, tc.getFullPacket(), tc.getFullPacketLen()); + return result; +} + +ReturnValue_t FreshSupvHandler::initialize() { + uartManager = + ObjectManager::instance()->get(objects::PLOC_SUPERVISOR_HELPER); + if (uartManager == nullptr) { + return returnvalue::FAILED; + } + uartManager->initializeInterface(comCookie); + + ReturnValue_t result = eventSubscription(); + if (result != returnvalue::OK) { + return result; + } + return FreshDeviceHandlerBase::initialize(); +} + +ReturnValue_t FreshSupvHandler::sendEmptyCmd(DeviceCommandId_t commandId, uint16_t apid, + uint8_t serviceId, bool replyExpected) { + supv::NoPayloadPacket packet(spParams, apid, serviceId); + ReturnValue_t result = packet.buildPacket(); + if (result != returnvalue::OK) { + return result; + } + sendCommand(commandId, packet, replyExpected); + return returnvalue::OK; +} + +ReturnValue_t FreshSupvHandler::prepareSetBootTimeoutCmd(const uint8_t* commandData, + size_t cmdDataLen) { + if (cmdDataLen < 4) { + return HasActionsIF::INVALID_PARAMETERS; + } + supv::SetBootTimeout packet(spParams); + uint32_t timeout = *(commandData) << 24 | *(commandData + 1) << 16 | *(commandData + 2) << 8 | + *(commandData + 3); + ReturnValue_t result = packet.buildPacket(timeout); + if (result != returnvalue::OK) { + return result; + } + sendCommand(supv::SET_BOOT_TIMEOUT, packet, false); + return returnvalue::OK; +} + +ReturnValue_t FreshSupvHandler::prepareRestartTriesCmd(const uint8_t* commandData, + size_t cmdDataLen) { + if (cmdDataLen < 1) { + return HasActionsIF::INVALID_PARAMETERS; + } + uint8_t restartTries = *(commandData); + supv::SetRestartTries packet(spParams); + ReturnValue_t result = packet.buildPacket(restartTries); + if (result != returnvalue::OK) { + return result; + } + sendCommand(supv::ENABLE_AUTO_TM, packet, false); + return returnvalue::OK; +} + +ReturnValue_t FreshSupvHandler::prepareDisableHk() { + supv::DisablePeriodicHkTransmission packet(spParams); + ReturnValue_t result = packet.buildPacket(); + if (result != returnvalue::OK) { + return result; + } + sendCommand(supv::DISABLE_AUTO_TM, packet, false); + return returnvalue::OK; +} + +ReturnValue_t FreshSupvHandler::prepareLatchupConfigCmd(const uint8_t* commandData, + DeviceCommandId_t deviceCommand, + size_t cmdDataLen) { + ReturnValue_t result = returnvalue::OK; + if (cmdDataLen < 1) { + return HasActionsIF::INVALID_PARAMETERS; + } + uint8_t latchupId = *commandData; + if (latchupId > 6) { + return result::INVALID_LATCHUP_ID; + } + switch (deviceCommand) { + case (supv::ENABLE_LATCHUP_ALERT): { + supv::LatchupAlert packet(spParams); + result = packet.buildPacket(true, latchupId); + if (result != returnvalue::OK) { + return result; + } + sendCommand(deviceCommand, packet, false); + break; + } + case (supv::DISABLE_LATCHUP_ALERT): { + supv::LatchupAlert packet(spParams); + result = packet.buildPacket(false, latchupId); + if (result != returnvalue::OK) { + return result; + } + sendCommand(deviceCommand, packet, false); + break; + } + default: { + sif::debug << "PlocSupervisorHandler::prepareLatchupConfigCmd: Invalid command id" + << std::endl; + result = returnvalue::FAILED; + break; + } + } + return result; +} + +ReturnValue_t FreshSupvHandler::prepareSetAlertLimitCmd(const uint8_t* commandData, + size_t cmdDataLen) { + if (cmdDataLen < 5) { + return HasActionsIF::INVALID_PARAMETERS; + } + uint8_t offset = 0; + uint8_t latchupId = *commandData; + offset += 1; + uint32_t dutycycle = *(commandData + offset) << 24 | *(commandData + offset + 1) << 16 | + *(commandData + offset + 2) << 8 | *(commandData + offset + 3); + if (latchupId > 6) { + return result::INVALID_LATCHUP_ID; + } + supv::SetAlertlimit packet(spParams); + ReturnValue_t result = packet.buildPacket(latchupId, dutycycle); + if (result != returnvalue::OK) { + return result; + } + sendCommand(supv::SET_ALERT_LIMIT, packet, false); + return returnvalue::OK; +} + +ReturnValue_t FreshSupvHandler::prepareSetShutdownTimeoutCmd(const uint8_t* commandData, + size_t cmdDataLen) { + if (cmdDataLen < 4) { + return HasActionsIF::INVALID_PARAMETERS; + } + uint32_t timeout = 0; + ReturnValue_t result = returnvalue::OK; + size_t size = sizeof(timeout); + result = + SerializeAdapter::deSerialize(&timeout, &commandData, &size, SerializeIF::Endianness::BIG); + if (result != returnvalue::OK) { + sif::warning + << "PlocSupervisorHandler::prepareSetShutdownTimeoutCmd: Failed to deserialize timeout" + << std::endl; + return result; + } + supv::SetShutdownTimeout packet(spParams); + result = packet.buildPacket(timeout); + if (result != returnvalue::OK) { + return result; + } + sendCommand(supv::SET_SHUTDOWN_TIMEOUT, packet, false); + return returnvalue::OK; +} + +ReturnValue_t FreshSupvHandler::prepareSetGpioCmd(const uint8_t* commandData, + size_t commandDataLen) { + if (commandDataLen < 3) { + return HasActionsIF::INVALID_PARAMETERS; + } + uint8_t port = *commandData; + uint8_t pin = *(commandData + 1); + uint8_t val = *(commandData + 2); + supv::SetGpio packet(spParams); + ReturnValue_t result = packet.buildPacket(port, pin, val); + if (result != returnvalue::OK) { + return result; + } + sendCommand(supv::SET_GPIO, packet, false); + return returnvalue::OK; +} + +ReturnValue_t FreshSupvHandler::prepareReadGpioCmd(const uint8_t* commandData, + size_t commandDataLen) { + if (commandDataLen < 2) { + return HasActionsIF::INVALID_PARAMETERS; + } + uint8_t port = *commandData; + uint8_t pin = *(commandData + 1); + supv::ReadGpio packet(spParams); + ReturnValue_t result = packet.buildPacket(port, pin); + if (result != returnvalue::OK) { + return result; + } + sendCommand(supv::READ_GPIO, packet, false); + return returnvalue::OK; +} + +ReturnValue_t FreshSupvHandler::prepareFactoryResetCmd(const uint8_t* commandData, size_t len) { + FactoryReset resetCmd(spParams); + if (len < 1) { + return HasActionsIF::INVALID_PARAMETERS; + } + ReturnValue_t result = resetCmd.buildPacket(commandData[0]); + if (result != returnvalue::OK) { + return result; + } + sendCommand(supv::FACTORY_RESET, resetCmd, false); + return returnvalue::OK; +} + +ReturnValue_t FreshSupvHandler::prepareSetAdcEnabledChannelsCmd(const uint8_t* commandData) { + uint16_t ch = *(commandData) << 8 | *(commandData + 1); + supv::SetAdcEnabledChannels packet(spParams); + ReturnValue_t result = packet.buildPacket(ch); + if (result != returnvalue::OK) { + return result; + } + sendCommand(supv::SET_ADC_ENABLED_CHANNELS, packet, false); + return returnvalue::OK; +} + +ReturnValue_t FreshSupvHandler::prepareSetAdcWindowAndStrideCmd(const uint8_t* commandData) { + uint8_t offset = 0; + uint16_t windowSize = *(commandData + offset) << 8 | *(commandData + offset + 1); + offset += 2; + uint16_t stridingStepSize = *(commandData + offset) << 8 | *(commandData + offset + 1); + supv::SetAdcWindowAndStride packet(spParams); + ReturnValue_t result = packet.buildPacket(windowSize, stridingStepSize); + if (result != returnvalue::OK) { + return result; + } + sendCommand(supv::SET_ADC_WINDOW_AND_STRIDE, packet, false); + return returnvalue::OK; +} + +ReturnValue_t FreshSupvHandler::prepareSetAdcThresholdCmd(const uint8_t* commandData) { + uint32_t threshold = *(commandData) << 24 | *(commandData + 1) << 16 | *(commandData + 2) << 8 | + *(commandData + 3); + supv::SetAdcThreshold packet(spParams); + ReturnValue_t result = packet.buildPacket(threshold); + if (result != returnvalue::OK) { + return result; + } + sendCommand(supv::SET_ADC_THRESHOLD, packet, false); + return returnvalue::OK; +} + +ReturnValue_t FreshSupvHandler::prepareWipeMramCmd(const uint8_t* commandData, size_t cmdDataLen) { + if (cmdDataLen < 8) { + return HasActionsIF::INVALID_PARAMETERS; + } + uint32_t start = 0; + uint32_t stop = 0; + size_t size = sizeof(start) + sizeof(stop); + SerializeAdapter::deSerialize(&start, &commandData, &size, SerializeIF::Endianness::BIG); + SerializeAdapter::deSerialize(&stop, &commandData, &size, SerializeIF::Endianness::BIG); + if ((stop - start) <= 0) { + return result::INVALID_MRAM_ADDRESSES; + } + supv::MramCmd packet(spParams); + ReturnValue_t result = packet.buildPacket(start, stop, supv::MramCmd::MramAction::WIPE); + if (result != returnvalue::OK) { + return result; + } + sendCommand(supv::WIPE_MRAM, packet, false); + return returnvalue::OK; +} + +ReturnValue_t FreshSupvHandler::parseTmPackets() { + uint8_t* receivedData = nullptr; + size_t receivedSize = 0; + while (true) { + ReturnValue_t result = + uartManager->readReceivedMessage(comCookie, &receivedData, &receivedSize); + if (result != returnvalue::OK or receivedSize == 0) { + break; + } + tmReader.setReadOnlyData(receivedData, receivedSize); + if (tmReader.checkCrc() != returnvalue::OK) { + sif::warning << "PlocSupervisorHandler::parseTmPackets: CRC failure for packet with size " + << receivedSize << std::endl; + arrayprinter::print(receivedData, receivedSize); + continue; + } + if (supv::DEBUG_PLOC_SUPV) { + handlePacketPrint(); + } + uint16_t apid = tmReader.getModuleApid(); + switch (apid) { + case (Apid::TMTC_MAN): { + switch (tmReader.getServiceId()) { + case (static_cast(supv::tm::TmtcId::ACK)): + case (static_cast(supv::tm::TmtcId::NAK)): { + handleAckReport(receivedData); + continue; + } + case (static_cast(supv::tm::TmtcId::EXEC_ACK)): + case (static_cast(supv::tm::TmtcId::EXEC_NAK)): { + handleExecutionReport(receivedData); + continue; + } + } + break; + } + case (Apid::HK): { + if (tmReader.getServiceId() == static_cast(supv::tm::HkId::REPORT)) { + handleHkReport(receivedData); + continue; + } else if (tmReader.getServiceId() == static_cast(supv::tm::HkId::HARDFAULTS)) { + handleBadApidServiceCombination(SUPV_UNINIMPLEMENTED_TM, apid, tmReader.getServiceId()); + return INVALID_DATA; + } + break; + } + case (Apid::BOOT_MAN): { + if (tmReader.getServiceId() == + static_cast(supv::tm::BootManId::BOOT_STATUS_REPORT)) { + handleBootStatusReport(receivedData); + continue; + } + break; + } + case (Apid::ADC_MON): { + if (tmReader.getServiceId() == static_cast(supv::tm::AdcMonId::ADC_REPORT)) { + genericHandleTm("ADC", receivedData, adcReport, supv::Apid::ADC_MON, + static_cast(supv::tc::AdcMonId::REQUEST_ADC_SAMPLE)); + continue; + } + break; + } + case (Apid::MEM_MAN): { + if (tmReader.getServiceId() == + static_cast(supv::tm::MemManId::UPDATE_STATUS_REPORT)) { + sif::warning << "FreshSupvHandler: Update status report parsing not implemented" + << std::endl; + // confirmReplyPacketReceived(supv::Apid::MEM_MAN, + // supv::tc::MemManId::UPDATE_STATUS_REPORT); + continue; + } + break; + } + case (Apid::DATA_LOGGER): { + if (tmReader.getServiceId() == + static_cast(supv::tm::DataLoggerId::COUNTERS_REPORT)) { + genericHandleTm("COUNTERS", receivedData, countersReport, supv::Apid::DATA_LOGGER, + static_cast(supv::tc::DataLoggerServiceId::REQUEST_COUNTERS)); + continue; + } + } + } + handleBadApidServiceCombination(SUPV_UNKNOWN_TM, apid, tmReader.getServiceId()); + } + return returnvalue::OK; +} + +void FreshSupvHandler::handleBadApidServiceCombination(Event event, unsigned int apid, + unsigned int serviceId) { + const char* printString = ""; + if (event == SUPV_UNKNOWN_TM) { + printString = "PlocSupervisorHandler: Unknown"; + } else if (event == SUPV_UNINIMPLEMENTED_TM) { + printString = "PlocSupervisorHandler: Unimplemented"; + } + triggerEvent(event, apid, tmReader.getServiceId()); + sif::warning << printString << " APID service combination 0x" << std::setw(2) << std::setfill('0') + << std::hex << apid << ", 0x" << std::setw(2) << serviceId << std::endl; +} + +void FreshSupvHandler::handlePacketPrint() { + if (tmReader.getModuleApid() == Apid::TMTC_MAN) { + if ((tmReader.getServiceId() == static_cast(supv::tm::TmtcId::ACK)) or + (tmReader.getServiceId() == static_cast(supv::tm::TmtcId::NAK))) { + AcknowledgmentReport ack(tmReader); + ReturnValue_t result = ack.parse(false); + if (result != returnvalue::OK) { + sif::warning << "PlocSupervisorHandler: Parsing ACK failed. "; + if (result == result::INVALID_SERVICE_ID) { + sif::warning << "Invalid service ID" << std::endl; + } else if (result == result::CRC_FAILURE) { + sif::warning << "CRC check failed" << std::endl; + } else { + sif::warning << "Returncode 0x" << std::hex << std::setw(4) << result << std::dec + << std::endl; + } + } + if (mode == MODE_NORMAL and supv::REDUCE_NORMAL_MODE_PRINTOUT and + ack.getRefModuleApid() == (uint8_t)supv::Apid::HK and + ack.getRefServiceId() == (uint8_t)supv::tc::HkId::GET_REPORT) { + return; + } + const char* printStr = "???"; + if (tmReader.getServiceId() == static_cast(supv::tm::TmtcId::ACK)) { + printStr = "ACK"; + + } else if (tmReader.getServiceId() == static_cast(supv::tm::TmtcId::NAK)) { + printStr = "NAK"; + } + sif::debug << "PlocSupervisorHandler: RECV " << printStr << " for APID Module ID " + << (int)ack.getRefModuleApid() << " Service ID " << (int)ack.getRefServiceId() + << " Seq Count " << ack.getRefSequenceCount() << std::endl; + return; + } else if ((tmReader.getServiceId() == static_cast(supv::tm::TmtcId::EXEC_ACK)) or + (tmReader.getServiceId() == static_cast(supv::tm::TmtcId::EXEC_NAK))) { + ExecutionReport exe(tmReader); + ReturnValue_t result = exe.parse(false); + if (result != returnvalue::OK) { + sif::warning << "PlocSupervisorHandler: Parsing EXE failed" << std::endl; + } + const char* printStr = "???"; + if (mode == MODE_NORMAL and supv::REDUCE_NORMAL_MODE_PRINTOUT and + exe.getRefModuleApid() == (uint8_t)supv::Apid::HK and + exe.getRefServiceId() == (uint8_t)supv::tc::HkId::GET_REPORT) { + return; + } + if (tmReader.getServiceId() == static_cast(supv::tm::TmtcId::EXEC_ACK)) { + printStr = "ACK EXE"; + + } else if (tmReader.getServiceId() == static_cast(supv::tm::TmtcId::EXEC_NAK)) { + printStr = "NAK EXE"; + } + sif::debug << "PlocSupervisorHandler: RECV " << printStr << " for APID Module ID " + << (int)exe.getRefModuleApid() << " Service ID " << (int)exe.getRefServiceId() + << " Seq Count " << exe.getRefSequenceCount() << std::endl; + return; + } + } + if (mode == MODE_NORMAL and supv::REDUCE_NORMAL_MODE_PRINTOUT and + tmReader.getModuleApid() == supv::Apid::HK and + tmReader.getServiceId() == static_cast(supv::tm::HkId::REPORT)) { + return; + } + sif::debug << "PlocSupervisorHandler: RECV PACKET Size " << tmReader.getFullPacketLen() + << " Module APID " << (int)tmReader.getModuleApid() << " Service ID " + << (int)tmReader.getServiceId() << std::endl; +} + +bool FreshSupvHandler::isCommandAlreadyActive(ActionId_t actionId) const { + // Not the most efficient implementation but who cares. It's not like this map is going + // to be huge in the nominal case.. + for (const auto& info : activeActionCmds) { + if (info.second.commandId == actionId and info.second.isPending) { + return true; + } + } + return false; +} + +ReturnValue_t FreshSupvHandler::extractUpdateCommand(const uint8_t* commandData, size_t size, + supv::UpdateParams& params) { + size_t remSize = size; + if (size > (config::MAX_FILENAME_SIZE + config::MAX_PATH_SIZE + sizeof(params.memId)) + + sizeof(params.startAddr) + sizeof(params.bytesWritten) + sizeof(params.seqCount) + + sizeof(uint8_t)) { + sif::warning << "PlocSupervisorHandler::extractUpdateCommand: Data size too big" << std::endl; + return result::INVALID_LENGTH; + } + ReturnValue_t result = returnvalue::OK; + result = extractBaseParams(&commandData, size, params); + result = SerializeAdapter::deSerialize(¶ms.bytesWritten, &commandData, &remSize, + SerializeIF::Endianness::BIG); + if (result != returnvalue::OK) { + sif::warning << "PlocSupervisorHandler::extractUpdateCommand: Failed to deserialize bytes " + "already written" + << std::endl; + return result; + } + result = SerializeAdapter::deSerialize(¶ms.seqCount, &commandData, &remSize, + SerializeIF::Endianness::BIG); + if (result != returnvalue::OK) { + sif::warning + << "PlocSupervisorHandler::extractUpdateCommand: Failed to deserialize start sequence count" + << std::endl; + return result; + } + uint8_t delMemRaw = 0; + result = SerializeAdapter::deSerialize(&delMemRaw, &commandData, &remSize, + SerializeIF::Endianness::BIG); + if (result != returnvalue::OK) { + sif::warning + << "PlocSupervisorHandler::extractUpdateCommand: Failed to deserialize whether to delete " + "memory" + << std::endl; + return result; + } + params.deleteMemory = delMemRaw; + return returnvalue::OK; +} + +ReturnValue_t FreshSupvHandler::extractBaseParams(const uint8_t** commandData, size_t& remSize, + supv::UpdateParams& params) { + bool nullTermFound = false; + for (size_t idx = 0; idx < remSize; idx++) { + if ((*commandData)[idx] == '\0') { + nullTermFound = true; + break; + } + } + if (not nullTermFound) { + return returnvalue::FAILED; + } + params.file = std::string(reinterpret_cast(*commandData)); + if (params.file.size() > (config::MAX_FILENAME_SIZE + config::MAX_PATH_SIZE)) { + sif::warning << "PlocSupervisorHandler::extractUpdateCommand: Filename too long" << std::endl; + return result::FILENAME_TOO_LONG; + } + *commandData += params.file.size() + SIZE_NULL_TERMINATOR; + remSize -= (params.file.size() + SIZE_NULL_TERMINATOR); + params.memId = **commandData; + *commandData += 1; + remSize -= 1; + ReturnValue_t result = SerializeAdapter::deSerialize(¶ms.startAddr, commandData, &remSize, + SerializeIF::Endianness::BIG); + if (result != returnvalue::OK) { + sif::warning << "PlocSupervisorHandler::extractBaseParams: Failed to deserialize start address" + << std::endl; + return result; + } + return result; +} + +void FreshSupvHandler::handleEvent(EventMessage* eventMessage) { + ReturnValue_t result = returnvalue::OK; + object_id_t objectId = eventMessage->getReporter(); + Event event = eventMessage->getEvent(); + switch (objectId) { + case objects::PLOC_SUPERVISOR_HELPER: { + // After execution of update procedure, PLOC is in a state where it draws approx. 700 mA of + // current. To leave this state the shutdown MPSoC command must be sent here. + if (event == PlocSupvUartManager::SUPV_UPDATE_FAILED || + event == PlocSupvUartManager::SUPV_UPDATE_SUCCESSFUL || + event == PlocSupvUartManager::SUPV_CONTINUE_UPDATE_FAILED || + event == PlocSupvUartManager::SUPV_CONTINUE_UPDATE_SUCCESSFUL || + event == PlocSupvUartManager::SUPV_MEM_CHECK_FAIL || + event == PlocSupvUartManager::SUPV_MEM_CHECK_OK) { + if (not isCommandAlreadyActive(supv::SHUTDOWN_MPSOC)) { + CommandMessage actionMsg; + ActionMessage::setCommand(&actionMsg, supv::SHUTDOWN_MPSOC, store_address_t::invalid()); + result = messageQueue->sendMessage(getCommandQueue(), &actionMsg); + if (result != returnvalue::OK) { + triggerEvent(supv::SUPV_MPSOC_SHUTDOWN_BUILD_FAILED); + sif::warning << "PlocSupervisorHandler::handleEvent: Failed to build MPSoC shutdown " + "command" + << std::endl; + return; + } + } + } + break; + } + default: + sif::debug << "PlocMPSoCHandler::handleEvent: Did not subscribe to this event" << std::endl; + break; + } +} + +ReturnValue_t FreshSupvHandler::eventSubscription() { + ReturnValue_t result = returnvalue::OK; + EventManagerIF* manager = ObjectManager::instance()->get(objects::EVENT_MANAGER); + if (manager == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "PlocSupervisorHandler::eventSubscritpion: Invalid event manager" << std::endl; +#endif + return ObjectManagerIF::CHILD_INIT_FAILED; + ; + } + result = manager->registerListener(eventQueue->getId()); + if (result != returnvalue::OK) { + return result; + } + result = manager->subscribeToEventRange( + eventQueue->getId(), event::getEventId(PlocSupvUartManager::SUPV_UPDATE_FAILED), + event::getEventId(PlocSupvUartManager::SUPV_MEM_CHECK_FAIL)); + if (result != returnvalue::OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "PlocSupervisorHandler::eventSubscritpion: Failed to subscribe to events from " + " ploc supervisor helper" + << std::endl; +#endif + return ObjectManagerIF::CHILD_INIT_FAILED; + } + return result; +} + +ReturnValue_t FreshSupvHandler::handleAckReport(const uint8_t* data) { + using namespace supv; + ReturnValue_t result = returnvalue::OK; + AcknowledgmentReport ack(tmReader); + result = ack.parse(false); + if (result != returnvalue::OK) { + return result; + } + auto infoIter = + activeActionCmds.find(buildActiveCmdKey(ack.getRefModuleApid(), ack.getRefServiceId())); + if (infoIter == activeActionCmds.end()) { + triggerEvent(SUPV_ACK_UNKNOWN_COMMAND, ack.getRefModuleApid(), ack.getRefServiceId()); + return result; + } + ActiveCmdInfo& info = infoIter->second; + if (tmReader.getServiceId() == static_cast(supv::tm::TmtcId::NAK)) { + triggerEvent(SUPV_ACK_FAILURE, info.commandId, static_cast(ack.getStatusCode())); + ack.printStatusInformationAck(); + printAckFailureInfo(ack.getStatusCode(), info.commandId); + if (info.commandedBy != MessageQueueIF::NO_QUEUE) { + actionHelper.finish(false, info.commandedBy, info.commandId, result::RECEIVED_ACK_FAILURE); + } + info.isPending = false; + return returnvalue::OK; + } + info.ackRecv = true; + performCommandCompletionHandling(static_cast((infoIter->first >> 16) & 0xffff), + infoIter->first & 0xff, info); + return result; +} + +void FreshSupvHandler::performCommandCompletionHandling(supv::Apid apid, uint8_t serviceId, + ActiveCmdInfo& info) { + if (info.ackRecv and info.ackExeRecv and + (not info.replyPacketExpected or info.replyPacketReceived)) { + if (info.commandedBy != MessageQueueIF::NO_QUEUE) { + actionHelper.finish(true, info.commandedBy, info.commandId, returnvalue::OK); + } + info.isPending = false; + } +} + +void FreshSupvHandler::printAckFailureInfo(uint16_t statusCode, DeviceCommandId_t commandId) { + switch (commandId) { + case (supv::SET_TIME_REF): { + sif::warning + << "PlocSupervisoHandler: Setting time failed. Make sure the OBC has a valid time" + << std::endl; + break; + } + default: + break; + } +} + +uint32_t FreshSupvHandler::buildActiveCmdKey(uint16_t moduleApid, uint8_t serviceId) { + return (moduleApid << 16) | serviceId; +} + +ReturnValue_t FreshSupvHandler::handleExecutionReport(const uint8_t* data) { + using namespace supv; + ReturnValue_t result = returnvalue::OK; + ExecutionReport exe(tmReader); + result = exe.parse(false); + if (result != OK) { + sif::warning << "FreshSupvHandler::handleExecutionReport: Parsing ACK EXE failed" << std::endl; + return result; + } + auto infoIter = + activeActionCmds.find(buildActiveCmdKey(exe.getRefModuleApid(), exe.getRefServiceId())); + if (infoIter == activeActionCmds.end()) { + triggerEvent(SUPV_EXE_ACK_UNKNOWN_COMMAND, exe.getRefModuleApid(), exe.getRefServiceId()); + return result; + } + ActiveCmdInfo& info = infoIter->second; + if (tmReader.getServiceId() == static_cast(supv::tm::TmtcId::EXEC_ACK)) { + result = handleExecutionSuccessReport(info, exe); + } else if (tmReader.getServiceId() == static_cast(supv::tm::TmtcId::EXEC_NAK)) { + handleExecutionFailureReport(info, exe); + return returnvalue::OK; + } + info.ackExeRecv = true; + performCommandCompletionHandling(static_cast((infoIter->first >> 16) & 0xffff), + infoIter->first & 0xff, info); + + return result; +} + +ReturnValue_t FreshSupvHandler::handleExecutionSuccessReport(ActiveCmdInfo& info, + ExecutionReport& report) { + switch (info.commandId) { + case supv::READ_GPIO: { + // TODO: Fix + uint16_t gpioState = report.getStatusCode(); +#if OBSW_DEBUG_PLOC_SUPERVISOR == 1 + sif::info << "PlocSupervisorHandler: Read GPIO TM, State: " << gpioState << std::endl; +#endif /* OBSW_DEBUG_PLOC_SUPERVISOR == 1 */ + uint8_t data[sizeof(gpioState)]; + size_t size = 0; + ReturnValue_t result = SerializeAdapter::serialize(&gpioState, data, &size, sizeof(gpioState), + SerializeIF::Endianness::BIG); + if (result != returnvalue::OK) { + sif::debug << "PlocSupervisorHandler: Failed to deserialize GPIO state" << std::endl; + } + result = actionHelper.reportData(info.commandedBy, info.commandId, data, sizeof(data)); + if (result != returnvalue::OK) { + sif::warning << "PlocSupervisorHandler: Read GPIO, failed to report data" << std::endl; + } + break; + } + case supv::SET_TIME_REF: { + if (startupState == StartupState::WAIT_FOR_TIME_REPLY) { + startupState = StartupState::TIME_WAS_SET; + } + break; + } + default: + break; + } + return returnvalue::OK; +} + +void FreshSupvHandler::handleExecutionFailureReport(ActiveCmdInfo& info, ExecutionReport& report) { + using namespace supv; + report.printStatusInformationExe(); + if (info.commandId != DeviceHandlerIF::NO_COMMAND_ID) { + triggerEvent(SUPV_EXE_FAILURE, info.commandId, static_cast(report.getStatusCode())); + } + if (info.commandedBy) { + actionHelper.finish(false, info.commandedBy, info.commandId, report.getStatusCode()); + } + info.isPending = false; +} + +void FreshSupvHandler::confirmReplyPacketReceived(supv::Apid apid, uint8_t serviceId) { + auto infoIter = activeActionCmds.find(buildActiveCmdKey(apid, serviceId)); + if (infoIter != activeActionCmds.end()) { + ActiveCmdInfo& info = infoIter->second; + info.replyPacketReceived = true; + performCommandCompletionHandling(static_cast((infoIter->first >> 16) & 0xffff), + infoIter->first & 0xff, info); + } +} + +ReturnValue_t FreshSupvHandler::handleHkReport(const uint8_t* data) { + ReturnValue_t result = returnvalue::OK; + + result = verifyPacket(data, tmReader.getFullPacketLen()); + + if (result == result::CRC_FAILURE) { + sif::error << "PlocSupervisorHandler::handleHkReport: Hk report has invalid crc" << std::endl; + return result; + } + + uint16_t offset = supv::PAYLOAD_OFFSET; + hkSet.tempPs = *(data + offset) << 24 | *(data + offset + 1) << 16 | *(data + offset + 2) << 8 | + *(data + offset + 3); + offset += 4; + hkSet.tempPl = *(data + offset) << 24 | *(data + offset + 1) << 16 | *(data + offset + 2) << 8 | + *(data + offset + 3); + offset += 4; + hkSet.tempSup = *(data + offset) << 24 | *(data + offset + 1) << 16 | *(data + offset + 2) << 8 | + *(data + offset + 3); + offset += 4; + size_t size = sizeof(hkSet.uptime.value); + result = SerializeAdapter::deSerialize(&hkSet.uptime, data + offset, &size, + SerializeIF::Endianness::BIG); + offset += 8; + hkSet.cpuLoad = *(data + offset) << 24 | *(data + offset + 1) << 16 | *(data + offset + 2) << 8 | + *(data + offset + 3); + offset += 4; + hkSet.availableHeap = *(data + offset) << 24 | *(data + offset + 1) << 16 | + *(data + offset + 2) << 8 | *(data + offset + 3); + offset += 4; + hkSet.numTcs = *(data + offset) << 24 | *(data + offset + 1) << 16 | *(data + offset + 2) << 8 | + *(data + offset + 3); + offset += 4; + hkSet.numTms = *(data + offset) << 24 | *(data + offset + 1) << 16 | *(data + offset + 2) << 8 | + *(data + offset + 3); + offset += 4; + hkSet.socState = *(data + offset) << 24 | *(data + offset + 1) << 16 | *(data + offset + 2) << 8 | + *(data + offset + 3); + offset += 4; + hkSet.nvm0_1_state = *(data + offset); + offset += 1; + hkSet.nvm3_state = *(data + offset); + offset += 1; + hkSet.missionIoState = *(data + offset); + offset += 1; + hkSet.fmcState = *(data + offset); + offset += 1; + + hkSet.setValidity(true, true); + confirmReplyPacketReceived(supv::Apid::HK, static_cast(supv::tc::HkId::GET_REPORT)); + +#if OBSW_VERBOSE_LEVEL >= 1 && OBSW_DEBUG_PLOC_SUPERVISOR == 1 + sif::info << "PlocSupervisorHandler::handleHkReport: temp_ps: " << hkSet.tempPs << std::endl; + sif::info << "PlocSupervisorHandler::handleHkReport: temp_pl: " << hkSet.tempPl << std::endl; + sif::info << "PlocSupervisorHandler::handleHkReport: temp_sup: " << hkSet.tempSup << std::endl; + sif::info << "PlocSupervisorHandler::handleHkReport: uptime: " << hkSet.uptime << std::endl; + sif::info << "PlocSupervisorHandler::handleHkReport: cpu_load: " << hkSet.cpuLoad << std::endl; + sif::info << "PlocSupervisorHandler::handleHkReport: available_heap: " << hkSet.availableHeap + << std::endl; + sif::info << "PlocSupervisorHandler::handleHkReport: num_tcs: " << hkSet.numTcs << std::endl; + sif::info << "PlocSupervisorHandler::handleHkReport: num_tms: " << hkSet.numTms << std::endl; + sif::info << "PlocSupervisorHandler::handleHkReport: soc_state: " << hkSet.socState << std::endl; + sif::info << "PlocSupervisorHandler::handleHkReport: nvm0_1_state: " + << static_cast(hkSet.nvm0_1_state.value) << std::endl; + sif::info << "PlocSupervisorHandler::handleHkReport: nvm3_state: " + << static_cast(hkSet.nvm3_state.value) << std::endl; + sif::info << "PlocSupervisorHandler::handleHkReport: mission_io_state: " + << static_cast(hkSet.missionIoState.value) << std::endl; + sif::info << "PlocSupervisorHandler::handleHkReport: fmc_state: " + << static_cast(hkSet.fmcState.value) << std::endl; + +#endif + + return result; +} + +ReturnValue_t FreshSupvHandler::verifyPacket(const uint8_t* start, size_t foundLen) { + if (CRC::crc16ccitt(start, foundLen) != 0) { + return result::CRC_FAILURE; + } + return returnvalue::OK; +} + +ReturnValue_t FreshSupvHandler::handleBootStatusReport(const uint8_t* data) { + ReturnValue_t result = returnvalue::OK; + + result = verifyPacket(data, tmReader.getFullPacketLen()); + + if (result == result::CRC_FAILURE) { + sif::error << "PlocSupervisorHandler::handleBootStatusReport: Boot status report has invalid" + " crc" + << std::endl; + return result; + } + + const uint8_t* payloadStart = tmReader.getPayloadStart(); + uint16_t offset = 0; + bootStatusReport.socState = payloadStart[0]; + offset += 1; + bootStatusReport.powerCycles = payloadStart[1]; + offset += 1; + bootStatusReport.bootAfterMs = *(payloadStart + offset) << 24 | + *(payloadStart + offset + 1) << 16 | + *(payloadStart + offset + 2) << 8 | *(payloadStart + offset + 3); + offset += 4; + bootStatusReport.bootTimeoutMs = *(payloadStart + offset) << 24 | + *(payloadStart + offset + 1) << 16 | + *(payloadStart + offset + 2) << 8 | *(payloadStart + offset + 3); + offset += 4; + bootStatusReport.activeNvm = *(payloadStart + offset); + offset += 1; + bootStatusReport.bp0State = *(payloadStart + offset); + offset += 1; + bootStatusReport.bp1State = *(payloadStart + offset); + offset += 1; + bootStatusReport.bp2State = *(payloadStart + offset); + offset += 1; + bootStatusReport.bootState = *(payloadStart + offset); + offset += 1; + bootStatusReport.bootCycles = *(payloadStart + offset); + + bootStatusReport.setValidity(true, true); + confirmReplyPacketReceived(supv::Apid::BOOT_MAN, + static_cast(supv::tc::BootManId::GET_BOOT_STATUS_REPORT)); + +#if OBSW_VERBOSE_LEVEL >= 1 && OBSW_DEBUG_PLOC_SUPERVISOR == 1 + sif::info << "PlocSupervisorHandler::handleBootStatusReport: SoC State (0 - off, 1 - booting, 2 " + "- Update, 3 " + "- operating, 4 - Shutdown, 5 - Reset): " + << static_cast(bootStatusReport.socState.value) << std::endl; + sif::info << "PlocSupervisorHandler::handleBootStatusReport: Power Cycles: " + << static_cast(bootStatusReport.powerCycles.value) << std::endl; + sif::info << "PlocSupervisorHandler::handleBootStatusReport: BootAfterMs: " + << bootStatusReport.bootAfterMs << " ms" << std::endl; + sif::info << "PlocSupervisorHandler::handleBootStatusReport: BootTimeoutMs: " << std::dec + << bootStatusReport.bootTimeoutMs << " ms" << std::endl; + sif::info << "PlocSupervisorHandler::handleBootStatusReport: Active NVM: " + << static_cast(bootStatusReport.activeNvm.value) << std::endl; + sif::info << "PlocSupervisorHandler::handleBootStatusReport: BP0: " + << static_cast(bootStatusReport.bp0State.value) << std::endl; + sif::info << "PlocSupervisorHandler::handleBootStatusReport: BP1: " + << static_cast(bootStatusReport.bp1State.value) << std::endl; + sif::info << "PlocSupervisorHandler::handleBootStatusReport: BP2: " + << static_cast(bootStatusReport.bp2State.value) << std::endl; + sif::info << "PlocSupervisorHandler::handleBootStatusReport: Boot state: " + << static_cast(bootStatusReport.bootState.value) << std::endl; + sif::info << "PlocSupervisorHandler::handleBootStatusReport: Boot cycles: " + << static_cast(bootStatusReport.bootCycles.value) << std::endl; +#endif + + return result; +} + +ReturnValue_t FreshSupvHandler::handleLatchupStatusReport(const uint8_t* data) { + ReturnValue_t result = returnvalue::OK; + + result = verifyPacket(data, tmReader.getFullPacketLen()); + + if (result == result::CRC_FAILURE) { + sif::error << "PlocSupervisorHandler::handleLatchupStatusReport: Latchup status report has " + << "invalid crc" << std::endl; + return result; + } + + const uint8_t* payloadData = tmReader.getPayloadStart(); + uint16_t offset = 0; + latchupStatusReport.id = *(payloadData + offset); + offset += 1; + latchupStatusReport.cnt0 = *(payloadData + offset) << 8 | *(payloadData + offset + 1); + offset += 2; + latchupStatusReport.cnt1 = *(payloadData + offset) << 8 | *(payloadData + offset + 1); + offset += 2; + latchupStatusReport.cnt2 = *(payloadData + offset) << 8 | *(payloadData + offset + 1); + offset += 2; + latchupStatusReport.cnt3 = *(payloadData + offset) << 8 | *(payloadData + offset + 1); + offset += 2; + latchupStatusReport.cnt4 = *(payloadData + offset) << 8 | *(payloadData + offset + 1); + offset += 2; + latchupStatusReport.cnt5 = *(payloadData + offset) << 8 | *(payloadData + offset + 1); + offset += 2; + latchupStatusReport.cnt6 = *(payloadData + offset) << 8 | *(data + offset + 1); + offset += 2; + uint16_t msec = *(payloadData + offset) << 8 | *(payloadData + offset + 1); + latchupStatusReport.isSet = msec >> supv::LatchupStatusReport::IS_SET_BIT_POS; + latchupStatusReport.timeMsec = msec & (~(1 << latchupStatusReport.IS_SET_BIT_POS)); + offset += 2; + latchupStatusReport.timeSec = *(payloadData + offset); + offset += 1; + latchupStatusReport.timeMin = *(payloadData + offset); + offset += 1; + latchupStatusReport.timeHour = *(payloadData + offset); + offset += 1; + latchupStatusReport.timeDay = *(payloadData + offset); + offset += 1; + latchupStatusReport.timeMon = *(payloadData + offset); + offset += 1; + latchupStatusReport.timeYear = *(payloadData + offset); + + latchupStatusReport.setValidity(true, true); + confirmReplyPacketReceived(supv::Apid::LATCHUP_MON, + static_cast(supv::tc::LatchupMonId::GET_STATUS_REPORT)); +#if OBSW_VERBOSE_LEVEL >= 1 && OBSW_DEBUG_PLOC_SUPERVISOR == 1 + sif::info << "PlocSupervisorHandler::handleLatchupStatusReport: Latchup ID: " + << static_cast(latchupStatusReport.id.value) << std::endl; + sif::info << "PlocSupervisorHandler::handleLatchupStatusReport: CNT0: " + << latchupStatusReport.cnt0 << std::endl; + sif::info << "PlocSupervisorHandler::handleLatchupStatusReport: CNT1: " + << latchupStatusReport.cnt1 << std::endl; + sif::info << "PlocSupervisorHandler::handleLatchupStatusReport: CNT2: " + << latchupStatusReport.cnt2 << std::endl; + sif::info << "PlocSupervisorHandler::handleLatchupStatusReport: CNT3: " + << latchupStatusReport.cnt3 << std::endl; + sif::info << "PlocSupervisorHandler::handleLatchupStatusReport: CNT4: " + << latchupStatusReport.cnt4 << std::endl; + sif::info << "PlocSupervisorHandler::handleLatchupStatusReport: CNT5: " + << latchupStatusReport.cnt5 << std::endl; + sif::info << "PlocSupervisorHandler::handleLatchupStatusReport: CNT6: " + << latchupStatusReport.cnt6 << std::endl; + sif::info << "PlocSupervisorHandler::handleLatchupStatusReport: Sec: " + << static_cast(latchupStatusReport.timeSec.value) << std::endl; + sif::info << "PlocSupervisorHandler::handleLatchupStatusReport: Min: " + << static_cast(latchupStatusReport.timeMin.value) << std::endl; + sif::info << "PlocSupervisorHandler::handleLatchupStatusReport: Hour: " + << static_cast(latchupStatusReport.timeHour.value) << std::endl; + sif::info << "PlocSupervisorHandler::handleLatchupStatusReport: Day: " + << static_cast(latchupStatusReport.timeDay.value) << std::endl; + sif::info << "PlocSupervisorHandler::handleLatchupStatusReport: Mon: " + << static_cast(latchupStatusReport.timeMon.value) << std::endl; + sif::info << "PlocSupervisorHandler::handleLatchupStatusReport: Year: " + << static_cast(latchupStatusReport.timeYear.value) << std::endl; + sif::info << "PlocSupervisorHandler::handleLatchupStatusReport: Msec: " + << static_cast(latchupStatusReport.timeMsec.value) << std::endl; + sif::info << "PlocSupervisorHandler::handleLatchupStatusReport: isSet: " + << static_cast(latchupStatusReport.isSet.value) << std::endl; +#endif + + return result; +} + +ReturnValue_t FreshSupvHandler::genericHandleTm(const char* contextString, const uint8_t* data, + LocalPoolDataSetBase& set, supv::Apid apid, + uint8_t serviceId) { + ReturnValue_t result = returnvalue::OK; + + result = verifyPacket(data, tmReader.getFullPacketLen()); + + if (result == result::CRC_FAILURE) { + sif::warning << "PlocSupervisorHandler: " << contextString << " report has " + << "invalid CRC" << std::endl; + return result; + } + + const uint8_t* dataField = data + supv::PAYLOAD_OFFSET; + PoolReadGuard pg(&set); + if (pg.getReadResult() != returnvalue::OK) { + return result; + } + set.setValidityBufferGeneration(false); + size_t size = set.getSerializedSize(); + result = set.deSerialize(&dataField, &size, SerializeIF::Endianness::BIG); + if (result != returnvalue::OK) { + sif::warning << "PlocSupervisorHandler: Deserialization failed" << std::endl; + } + set.setValidityBufferGeneration(true); + set.setValidity(true, true); + confirmReplyPacketReceived(apid, serviceId); + return result; +} + +bool FreshSupvHandler::isCommandPending() const { + for (const auto& info : activeActionCmds) { + if (info.second.isPending) { + return true; + } + } + return false; +} diff --git a/linux/payload/FreshSupvHandler.h b/linux/payload/FreshSupvHandler.h new file mode 100644 index 00000000..2c700deb --- /dev/null +++ b/linux/payload/FreshSupvHandler.h @@ -0,0 +1,188 @@ +#ifndef LINUX_PAYLOAD_FRESHSUPVHANDLER_H_ +#define LINUX_PAYLOAD_FRESHSUPVHANDLER_H_ + +#include +#include + +#include + +#include "PlocSupvUartMan.h" +#include "fsfw/devicehandlers/FreshDeviceHandlerBase.h" +#include "fsfw/power/definitions.h" +#include "fsfw_hal/linux/gpio/Gpio.h" +#include "plocSupvDefs.h" + +using supv::TcBase; + +class FreshSupvHandler : public FreshDeviceHandlerBase { + public: + enum OpCode { DEFAULT_OPERATION = 0, PARSE_TM = 1 }; + + FreshSupvHandler(DhbConfig cfg, CookieIF* comCookie, Gpio uartIsolatorSwitch, + PowerSwitchIF& switchIF, power::Switch_t powerSwitch); + /** + * Periodic helper executed function, implemented by child class. + */ + void performDeviceOperation(uint8_t opCode) override; + + /** + * Implemented by child class. Handle all command messages which are + * not health, mode, action or housekeeping messages. + * @param message + * @return + */ + ReturnValue_t handleCommandMessage(CommandMessage* message) override; + + ReturnValue_t initialize() override; + + private: + // HK manager abstract functions. + LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; + ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) override; + + // Mode abstract functions + ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t* msToReachTheMode) override; + // Action override. Forward to user. + ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy, + const uint8_t* data, size_t size) override; + + /** + * @overload + * @param submode + */ + void startTransition(Mode_t newMode, Submode_t submode) override; + + ReturnValue_t performDeviceOperationPreQueueHandling(uint8_t opCode) override; + void handleTransitionToOn(); + void handleTransitionToOff(); + + private: + static constexpr bool SET_TIME_DURING_BOOT = true; + static const uint8_t SIZE_NULL_TERMINATOR = 1; + + enum class StartupState : uint8_t { + IDLE, + POWER_SWITCHING, + BOOTING, + SET_TIME, + WAIT_FOR_TIME_REPLY, + TIME_WAS_SET, + ON + }; + + StartupState startupState = StartupState::IDLE; + MessageQueueIF* eventQueue = nullptr; + supv::TmBase tmReader; + + enum class ShutdownState : uint8_t { IDLE, POWER_SWITCHING }; + ShutdownState shutdownState = ShutdownState::IDLE; + + PlocSupvUartManager* uartManager; + CookieIF* comCookie; + PowerSwitchIF& switchIF; + power::Switch_t switchId; + Gpio uartIsolatorSwitch; + + supv::HkSet hkSet; + supv::BootStatusReport bootStatusReport; + supv::LatchupStatusReport latchupStatusReport; + supv::CountersReport countersReport; + supv::AdcReport adcReport; + + bool transitionActive = false; + + Mode_t targetMode = HasModesIF::MODE_INVALID; + Submode_t targetSubmode = 0; + + Countdown switchTimeout = Countdown(2000); + // Vorago nees some time to boot properly + Countdown bootTimeout = Countdown(supv::BOOT_TIMEOUT_MS); + // Countdown interCmdCd = Countdown(supv::INTER_COMMAND_DELAY); + + PoolEntry adcRawEntry = PoolEntry(16); + PoolEntry adcEngEntry = PoolEntry(16); + PoolEntry latchupCounters = PoolEntry(7); + PoolEntry fmcStateEntry = PoolEntry(1); + PoolEntry bootStateEntry = PoolEntry(1); + PoolEntry bootCyclesEntry = PoolEntry(1); + PoolEntry tempSupEntry = PoolEntry(1); + + pwrctrl::EnablePl enablePl = pwrctrl::EnablePl(objects::POWER_CONTROLLER); + + struct ActiveCmdInfo { + ActiveCmdInfo(DeviceCommandId_t commandId, uint32_t cmdCountdownMs) + : commandId(commandId), cmdCountdown(cmdCountdownMs) {} + + DeviceCommandId_t commandId = DeviceHandlerIF::NO_COMMAND_ID; + bool isPending = false; + bool ackRecv = false; + bool ackExeRecv = false; + bool replyPacketExpected = false; + bool replyPacketReceived = false; + MessageQueueId_t commandedBy = MessageQueueIF::NO_QUEUE; + bool requiresActionReply = false; + Countdown cmdCountdown; + }; + + uint32_t buildActiveCmdKey(uint16_t moduleApid, uint8_t serviceId); + + // Map for Action commands. For normal commands, a separate static structure will be used. + std::map activeActionCmds; + + std::array commandBuffer{}; + SpacePacketCreator creator; + supv::TcParams spParams = supv::TcParams(creator); + DeviceCommandId_t commandedByCached = MessageQueueIF::NO_QUEUE; + + ReturnValue_t parseTmPackets(); + + ReturnValue_t sendCommand(DeviceCommandId_t commandId, TcBase& tc, bool replyPacketExpected, + uint32_t cmdCountdownMs = 1000); + ReturnValue_t sendEmptyCmd(DeviceCommandId_t commandId, uint16_t apid, uint8_t serviceId, + bool replyPacketExpected); + ReturnValue_t prepareSelBootImageCmd(const uint8_t* commandData); + ReturnValue_t prepareSetTimeRefCmd(); + ReturnValue_t prepareSetBootTimeoutCmd(const uint8_t* commandData, size_t cmdDataLen); + ReturnValue_t prepareRestartTriesCmd(const uint8_t* commandData, size_t cmdDataLen); + ReturnValue_t prepareDisableHk(); + ReturnValue_t prepareLatchupConfigCmd(const uint8_t* commandData, DeviceCommandId_t deviceCommand, + size_t cmdDataLen); + ReturnValue_t prepareSetAlertLimitCmd(const uint8_t* commandData, size_t cmdDataLen); + ReturnValue_t prepareFactoryResetCmd(const uint8_t* commandData, size_t len); + ReturnValue_t prepareSetShutdownTimeoutCmd(const uint8_t* commandData, size_t cmdDataLen); + ReturnValue_t prepareSetGpioCmd(const uint8_t* commandData, size_t commandDataLen); + ReturnValue_t prepareReadGpioCmd(const uint8_t* commandData, size_t commandDataLen); + ReturnValue_t prepareSetAdcEnabledChannelsCmd(const uint8_t* commandData); + ReturnValue_t prepareSetAdcWindowAndStrideCmd(const uint8_t* commandData); + ReturnValue_t prepareSetAdcThresholdCmd(const uint8_t* commandData); + ReturnValue_t prepareWipeMramCmd(const uint8_t* commandData, size_t cmdDataLen); + ReturnValue_t extractUpdateCommand(const uint8_t* commandData, size_t size, + supv::UpdateParams& params); + ReturnValue_t extractBaseParams(const uint8_t** commandData, size_t& remSize, + supv::UpdateParams& params); + void handleEvent(EventMessage* eventMessage); + + void handleBadApidServiceCombination(Event event, unsigned int apid, unsigned int serviceId); + ReturnValue_t eventSubscription(); + void handlePacketPrint(); + bool isCommandAlreadyActive(ActionId_t actionId) const; + ReturnValue_t handleAckReport(const uint8_t* data); + void printAckFailureInfo(uint16_t statusCode, DeviceCommandId_t commandId); + ReturnValue_t handleExecutionReport(const uint8_t* data); + ReturnValue_t handleExecutionSuccessReport(ActiveCmdInfo& info, supv::ExecutionReport& report); + void handleExecutionFailureReport(ActiveCmdInfo& info, supv::ExecutionReport& report); + ReturnValue_t handleHkReport(const uint8_t* data); + ReturnValue_t verifyPacket(const uint8_t* start, size_t foundLen); + void confirmReplyPacketReceived(supv::Apid apid, uint8_t serviceId); + void performCommandCompletionHandling(supv::Apid apid, uint8_t serviceId, ActiveCmdInfo& info); + ReturnValue_t handleBootStatusReport(const uint8_t* data); + ReturnValue_t genericHandleTm(const char* contextString, const uint8_t* data, + LocalPoolDataSetBase& set, supv::Apid apid, uint8_t serviceId); + ReturnValue_t handleLatchupStatusReport(const uint8_t* data); + + bool isCommandPending() const; +}; + +#endif /* LINUX_PAYLOAD_FRESHSUPVHANDLER_H_ */ diff --git a/linux/payload/PlocMpsocHandler.cpp b/linux/payload/PlocMpsocHandler.cpp index 34053c70..05b3a04e 100644 --- a/linux/payload/PlocMpsocHandler.cpp +++ b/linux/payload/PlocMpsocHandler.cpp @@ -20,9 +20,8 @@ PlocMpsocHandler::PlocMpsocHandler(object_id_t objectId, object_id_t uartComIFid if (comCookie == nullptr) { sif::error << "PlocMPSoCHandler: Invalid communication cookie" << std::endl; } - eventQueue = QueueFactory::instance()->createMessageQueue(EventMessage::EVENT_MESSAGE_SIZE * 5); - commandActionHelperQueue = - QueueFactory::instance()->createMessageQueue(EventMessage::EVENT_MESSAGE_SIZE * 5); + eventQueue = QueueFactory::instance()->createMessageQueue(10); + commandActionHelperQueue = QueueFactory::instance()->createMessageQueue(10); spParams.maxSize = sizeof(commandBuffer); spParams.buf = commandBuffer; } diff --git a/linux/payload/PlocMpsocSpecialComHelper.cpp b/linux/payload/PlocMpsocSpecialComHelper.cpp index acf88abd..66712a90 100644 --- a/linux/payload/PlocMpsocSpecialComHelper.cpp +++ b/linux/payload/PlocMpsocSpecialComHelper.cpp @@ -504,7 +504,7 @@ ReturnValue_t PlocMpsocSpecialComHelper::checkReceivedTm() { triggerEvent(MPSOC_TM_SIZE_ERROR); return result; } - spReader.checkCrc(); + result = spReader.checkCrc(); if (result != returnvalue::OK) { sif::warning << "PLOC MPSoC: CRC check failed" << std::endl; triggerEvent(MPSOC_TM_CRC_MISSMATCH, *sequenceCount); diff --git a/linux/payload/PlocSupvUartMan.cpp b/linux/payload/PlocSupvUartMan.cpp index 1a129927..f73ca560 100644 --- a/linux/payload/PlocSupvUartMan.cpp +++ b/linux/payload/PlocSupvUartMan.cpp @@ -24,6 +24,7 @@ #include "mission/utility/Filenaming.h" #include "mission/utility/ProgressPrinter.h" #include "mission/utility/Timestamp.h" +#include "tas/crc.h" using namespace returnvalue; using namespace supv; @@ -96,9 +97,10 @@ ReturnValue_t PlocSupvUartManager::initialize() { ReturnValue_t PlocSupvUartManager::performOperation(uint8_t operationCode) { bool putTaskToSleep = false; while (true) { - lock->lockMutex(); - state = InternalState::SLEEPING; - lock->unlockMutex(); + { + MutexGuard mg(lock); + state = InternalState::SLEEPING; + } semaphore->acquire(); putTaskToSleep = false; #if OBSW_THREAD_TRACING == 1 @@ -110,9 +112,11 @@ ReturnValue_t PlocSupvUartManager::performOperation(uint8_t operationCode) { break; } handleUartReception(); - lock->lockMutex(); - InternalState currentState = state; - lock->unlockMutex(); + InternalState currentState; + { + MutexGuard mg(lock); + currentState = state; + } switch (currentState) { case InternalState::SLEEPING: case InternalState::GO_TO_SLEEP: { @@ -156,7 +160,7 @@ ReturnValue_t PlocSupvUartManager::handleUartReception() { << " bytes" << std::endl; return FAILED; } else if (bytesRead > 0) { - if (debugMode) { + if (DEBUG_MODE) { sif::info << "Received " << bytesRead << " bytes from the PLOC Supervisor:" << std::endl; arrayprinter::print(recBuf.data(), bytesRead); } @@ -571,7 +575,7 @@ ReturnValue_t PlocSupvUartManager::handlePacketTransmissionNoReply( size_t packetLen = 0; decodedQueue.retrieve(&packetLen); decodedRingBuf.readData(decodedBuf.data(), packetLen, true); - tmReader.setData(decodedBuf.data(), packetLen); + tmReader.setReadOnlyData(decodedBuf.data(), packetLen); result = checkReceivedTm(); if (result != returnvalue::OK) { continue; @@ -617,7 +621,7 @@ int PlocSupvUartManager::handleAckReception(supv::TcBase& tc, size_t packetLen) if (serviceId == static_cast(supv::tm::TmtcId::ACK) or serviceId == static_cast(supv::tm::TmtcId::NAK)) { AcknowledgmentReport ackReport(tmReader); - ReturnValue_t result = ackReport.parse(); + ReturnValue_t result = ackReport.parse(false); if (result != returnvalue::OK) { triggerEvent(ACK_RECEPTION_FAILURE); return -1; @@ -627,7 +631,7 @@ int PlocSupvUartManager::handleAckReception(supv::TcBase& tc, size_t packetLen) if (serviceId == static_cast(supv::tm::TmtcId::ACK)) { return 1; } else if (serviceId == static_cast(supv::tm::TmtcId::NAK)) { - ackReport.printStatusInformation(); + ackReport.printStatusInformationAck(); triggerEvent( SUPV_ACK_FAILURE_REPORT, buildApidServiceParam1(ackReport.getRefModuleApid(), ackReport.getRefServiceId()), @@ -649,7 +653,7 @@ int PlocSupvUartManager::handleExeAckReception(supv::TcBase& tc, size_t packetLe if (serviceId == static_cast(supv::tm::TmtcId::EXEC_ACK) or serviceId == static_cast(supv::tm::TmtcId::EXEC_NAK)) { ExecutionReport exeReport(tmReader); - ReturnValue_t result = exeReport.parse(); + ReturnValue_t result = exeReport.parse(false); if (result != returnvalue::OK) { triggerEvent(EXE_RECEPTION_FAILURE); return -1; @@ -659,7 +663,7 @@ int PlocSupvUartManager::handleExeAckReception(supv::TcBase& tc, size_t packetLe if (serviceId == static_cast(supv::tm::TmtcId::EXEC_ACK)) { return 1; } else if (serviceId == static_cast(supv::tm::TmtcId::EXEC_NAK)) { - exeReport.printStatusInformation(); + exeReport.printStatusInformationExe(); triggerEvent( SUPV_EXE_FAILURE_REPORT, buildApidServiceParam1(exeReport.getRefModuleApid(), exeReport.getRefServiceId()), @@ -682,7 +686,7 @@ ReturnValue_t PlocSupvUartManager::checkReceivedTm() { triggerEvent(SUPV_REPLY_SIZE_MISSMATCH, rememberApid); return result; } - if (not tmReader.verifyCrc()) { + if (tmReader.checkCrc() != returnvalue::OK) { triggerEvent(SUPV_REPLY_CRC_MISSMATCH, rememberApid); return result; } @@ -758,7 +762,7 @@ ReturnValue_t PlocSupvUartManager::handleCheckMemoryCommand(uint8_t failStep) { size_t packetLen = 0; decodedQueue.retrieve(&packetLen); decodedRingBuf.readData(decodedBuf.data(), packetLen, true); - tmReader.setData(decodedBuf.data(), packetLen); + tmReader.setReadOnlyData(decodedBuf.data(), packetLen); result = checkReceivedTm(); if (result != returnvalue::OK) { continue; @@ -786,7 +790,7 @@ ReturnValue_t PlocSupvUartManager::handleCheckMemoryCommand(uint8_t failStep) { } else if (tmReader.getModuleApid() == Apid::MEM_MAN) { if (ackReceived) { supv::UpdateStatusReport report(tmReader); - result = report.parse(); + result = report.parse(false); if (result != returnvalue::OK) { return result; } @@ -962,7 +966,7 @@ ReturnValue_t PlocSupvUartManager::handleRunningLongerRequest() { ReturnValue_t PlocSupvUartManager::encodeAndSendPacket(const uint8_t* sendData, size_t sendLen) { size_t encodedLen = 0; addHdlcFraming(sendData, sendLen, encodedSendBuf.data(), &encodedLen, encodedSendBuf.size()); - if (printTc) { + if (PRINT_TC) { sif::debug << "Sending TC" << std::endl; arrayprinter::print(encodedSendBuf.data(), encodedLen); } @@ -984,6 +988,9 @@ ReturnValue_t PlocSupvUartManager::readReceivedMessage(CookieIF* cookie, uint8_t return OK; } ipcQueue.retrieve(size); + if (*size > ipcBuffer.size()) { + return FAILED; + } *buffer = ipcBuffer.data(); ReturnValue_t result = ipcRingBuf.readData(ipcBuffer.data(), *size, true); if (result != OK) { @@ -1054,6 +1061,7 @@ ReturnValue_t PlocSupvUartManager::parseRecRingBufForHdlc(size_t& readSize, size triggerEvent(HDLC_CRC_ERROR); } if (retval != 0) { + readSize = ++idx; return HDLC_ERROR; } return returnvalue::OK; @@ -1084,11 +1092,14 @@ void PlocSupvUartManager::performUartShutdown() { while (not decodedQueue.empty()) { decodedQueue.pop(); } - MutexGuard mg(ipcLock); - ipcRingBuf.clear(); - while (not ipcQueue.empty()) { - ipcQueue.pop(); + { + MutexGuard mg0(ipcLock); + ipcRingBuf.clear(); + while (not ipcQueue.empty()) { + ipcQueue.pop(); + } } + MutexGuard mg1(lock); state = InternalState::GO_TO_SLEEP; } diff --git a/linux/payload/PlocSupvUartMan.h b/linux/payload/PlocSupvUartMan.h index 61d4b284..562bd3bd 100644 --- a/linux/payload/PlocSupvUartMan.h +++ b/linux/payload/PlocSupvUartMan.h @@ -16,7 +16,6 @@ #include "fsfw/returnvalues/returnvalue.h" #include "fsfw/tasks/ExecutableObjectIF.h" #include "fsfw_hal/linux/serial/SerialComIF.h" -#include "tas/crc.h" #ifdef XIPHOS_Q7S #include "bsp_q7s/fs/SdCardManager.h" @@ -121,6 +120,32 @@ class PlocSupvUartManager : public DeviceCommunicationIF, PlocSupvUartManager(object_id_t objectId); virtual ~PlocSupvUartManager(); + /** + * @brief Device specific initialization, using the cookie. + * @details + * The cookie is already prepared in the factory. If the communication + * interface needs to be set up in some way and requires cookie information, + * this can be performed in this function, which is called on device handler + * initialization. + * @param cookie + * @return + * - @c returnvalue::OK if initialization was successfull + * - Everything else triggers failure event with returnvalue as parameter 1 + */ + ReturnValue_t initializeInterface(CookieIF* cookie) override; + /** + * Called by DHB in the SEND_WRITE doSendWrite(). + * This function is used to send data to the physical device + * by implementing and calling related drivers or wrapper functions. + * @param cookie + * @param data + * @param len If this is 0, nothing shall be sent. + * @return + * - @c returnvalue::OK for successfull send + * - Everything else triggers failure event with returnvalue as parameter 1 + */ + ReturnValue_t sendMessage(CookieIF* cookie, const uint8_t* sendData, size_t sendLen) override; + ReturnValue_t readReceivedMessage(CookieIF* cookie, uint8_t** buffer, size_t* size) override; ReturnValue_t initialize() override; ReturnValue_t performOperation(uint8_t operationCode = 0) override; @@ -206,11 +231,11 @@ class PlocSupvUartManager : public DeviceCommunicationIF, struct Update update; + int serialPort = 0; SemaphoreIF* semaphore; MutexIF* lock; MutexIF* ipcLock; supv::TmBase tmReader; - int serialPort = 0; struct termios tty = {}; #if OBSW_THREAD_TRACING == 1 uint32_t opCounter = 0; @@ -257,8 +282,8 @@ class PlocSupvUartManager : public DeviceCommunicationIF, std::array tmBuf{}; - bool printTc = false; - bool debugMode = false; + static constexpr bool PRINT_TC = false; + static constexpr bool DEBUG_MODE = false; bool timestamping = true; // Remembers APID to know at which command a procedure failed @@ -319,32 +344,6 @@ class PlocSupvUartManager : public DeviceCommunicationIF, void resetSpParams(); void pushIpcData(const uint8_t* data, size_t len); - /** - * @brief Device specific initialization, using the cookie. - * @details - * The cookie is already prepared in the factory. If the communication - * interface needs to be set up in some way and requires cookie information, - * this can be performed in this function, which is called on device handler - * initialization. - * @param cookie - * @return - * - @c returnvalue::OK if initialization was successfull - * - Everything else triggers failure event with returnvalue as parameter 1 - */ - ReturnValue_t initializeInterface(CookieIF* cookie) override; - - /** - * Called by DHB in the SEND_WRITE doSendWrite(). - * This function is used to send data to the physical device - * by implementing and calling related drivers or wrapper functions. - * @param cookie - * @param data - * @param len If this is 0, nothing shall be sent. - * @return - * - @c returnvalue::OK for successfull send - * - Everything else triggers failure event with returnvalue as parameter 1 - */ - ReturnValue_t sendMessage(CookieIF* cookie, const uint8_t* sendData, size_t sendLen) override; /** * Called by DHB in the GET_WRITE doGetWrite(). * Get send confirmation that the data in sendMessage() was sent successfully. @@ -369,7 +368,6 @@ class PlocSupvUartManager : public DeviceCommunicationIF, * returnvalue as parameter 1 */ ReturnValue_t requestReceiveMessage(CookieIF* cookie, size_t requestLen) override; - ReturnValue_t readReceivedMessage(CookieIF* cookie, uint8_t** buffer, size_t* size) override; void performUartShutdown(); void updateVtime(uint8_t vtime); diff --git a/linux/payload/plocSupvDefs.h b/linux/payload/plocSupvDefs.h index 115cfe60..a770fb49 100644 --- a/linux/payload/plocSupvDefs.h +++ b/linux/payload/plocSupvDefs.h @@ -11,13 +11,46 @@ #include #include -#include +#include "eive/eventSubsystemIds.h" #include "eive/resultClassIds.h" namespace supv { +static constexpr bool DEBUG_PLOC_SUPV = false; +static constexpr bool REDUCE_NORMAL_MODE_PRINTOUT = true; + +static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PLOC_SUPERVISOR_HANDLER; + +//! [EXPORT] : [COMMENT] PLOC supervisor crc failure in telemetry packet +static const Event SUPV_MEMORY_READ_RPT_CRC_FAILURE = MAKE_EVENT(1, severity::LOW); +//! [EXPORT] : [COMMENT] Unhandled event. P1: APID, P2: Service ID +static constexpr Event SUPV_UNKNOWN_TM = MAKE_EVENT(2, severity::LOW); +static constexpr Event SUPV_UNINIMPLEMENTED_TM = MAKE_EVENT(3, severity::LOW); +//! [EXPORT] : [COMMENT] PLOC supervisor received acknowledgment failure report +static const Event SUPV_ACK_FAILURE = MAKE_EVENT(4, severity::LOW); +//! [EXPORT] : [COMMENT] PLOC received execution failure report +//! P1: ID of command for which the execution failed +//! P2: Status code sent by the supervisor handler +static const Event SUPV_EXE_FAILURE = MAKE_EVENT(5, severity::LOW); +//! [EXPORT] : [COMMENT] PLOC supervisor reply has invalid crc +static const Event SUPV_CRC_FAILURE_EVENT = MAKE_EVENT(6, severity::LOW); +//! [EXPORT] : [COMMENT] Supervisor helper currently executing a command +static const Event SUPV_HELPER_EXECUTING = MAKE_EVENT(7, severity::LOW); +//! [EXPORT] : [COMMENT] Failed to build the command to shutdown the MPSoC +static const Event SUPV_MPSOC_SHUTDOWN_BUILD_FAILED = MAKE_EVENT(8, severity::LOW); +//! [EXPORT] : [COMMENT] Received ACK, but no related command is unknown or has not been sent +// by this software instance. P1: Module APID. P2: Service ID. +static const Event SUPV_ACK_UNKNOWN_COMMAND = MAKE_EVENT(9, severity::LOW); +//! [EXPORT] : [COMMENT] Received ACK EXE, but no related command is unknown or has not been sent +// by this software instance. P1: Module APID. P2: Service ID. +static const Event SUPV_EXE_ACK_UNKNOWN_COMMAND = MAKE_EVENT(10, severity::LOW); + extern std::atomic_bool SUPV_ON; +static constexpr uint32_t INTER_COMMAND_DELAY = 20; +static constexpr uint32_t BOOT_TIMEOUT_MS = 4000; +static constexpr uint32_t MAX_TRANSITION_TIME_TO_ON_MS = BOOT_TIMEOUT_MS + 2000; +static constexpr uint32_t MAX_TRANSITION_TIME_TO_OFF_MS = 1000; namespace result { static const uint8_t INTERFACE_ID = CLASS_ID::SUPV_RETURN_VALUES_IF; @@ -107,7 +140,7 @@ static const DeviceCommandId_t FIRST_MRAM_DUMP = 30; static const DeviceCommandId_t SET_GPIO = 34; static const DeviceCommandId_t READ_GPIO = 35; static const DeviceCommandId_t RESTART_SUPERVISOR = 36; -static const DeviceCommandId_t LOGGING_REQUEST_COUNTERS = 38; +static const DeviceCommandId_t REQUEST_LOGGING_COUNTERS = 38; static constexpr DeviceCommandId_t FACTORY_RESET = 39; static const DeviceCommandId_t CONSECUTIVE_MRAM_DUMP = 43; static const DeviceCommandId_t START_MPSOC_QUIET = 45; @@ -120,7 +153,7 @@ static const DeviceCommandId_t DISABLE_AUTO_TM = 51; static const DeviceCommandId_t LOGGING_REQUEST_EVENT_BUFFERS = 54; static const DeviceCommandId_t LOGGING_CLEAR_COUNTERS = 55; static const DeviceCommandId_t LOGGING_SET_TOPIC = 56; -static const DeviceCommandId_t REQUEST_ADC_REPORT = 57; +static constexpr DeviceCommandId_t REQUEST_ADC_REPORT = 57; static const DeviceCommandId_t RESET_PL = 58; static const DeviceCommandId_t ENABLE_NVMS = 59; static const DeviceCommandId_t CONTINUE_UPDATE = 60; @@ -134,7 +167,7 @@ enum ReplyId : DeviceCommandId_t { HK_REPORT = 102, BOOT_STATUS_REPORT = 103, LATCHUP_REPORT = 104, - LOGGING_REPORT = 105, + COUNTERS_REPORT = 105, ADC_REPORT = 106, UPDATE_STATUS_REPORT = 107, }; @@ -144,7 +177,7 @@ static const uint16_t SIZE_ACK_REPORT = 14; static const uint16_t SIZE_EXE_REPORT = 14; static const uint16_t SIZE_BOOT_STATUS_REPORT = 24; static const uint16_t SIZE_LATCHUP_STATUS_REPORT = 31; -static const uint16_t SIZE_LOGGING_REPORT = 73; +static const uint16_t SIZE_COUNTERS_REPORT = 120; static const uint16_t SIZE_ADC_REPORT = 72; // 2 bits APID SRC, 00 for OBC, 2 bits APID DEST, 01 for SUPV, 7 bits CMD ID -> Mask 0x080 @@ -207,12 +240,18 @@ enum class AdcMonId : uint8_t { SET_ENABLED_CHANNELS = 0x02, SET_WINDOW_STRIDE = 0x03, SET_ADC_THRESHOLD = 0x04, - COPY_ADC_DATA_TO_MRAM = 0x05 + COPY_ADC_DATA_TO_MRAM = 0x05, + REQUEST_ADC_SAMPLE = 0x06 }; enum class MemManId : uint8_t { ERASE = 0x01, WRITE = 0x02, CHECK = 0x03 }; enum class DataLoggerServiceId : uint8_t { + // Not implemented. + READ_MRAM_CFG_DATA_LOGGER = 0x00, + REQUEST_COUNTERS = 0x01, + // Not implemented. + EVENT_BUFFER_DOWNLOAD = 0x02, WIPE_MRAM = 0x05, DUMP_MRAM = 0x06, FACTORY_RESET = 0x07 @@ -231,10 +270,12 @@ enum class TmtcId : uint8_t { ACK = 0x01, NAK = 0x02, EXEC_ACK = 0x03, EXEC_NAK enum class HkId : uint8_t { REPORT = 0x01, HARDFAULTS = 0x02 }; enum class BootManId : uint8_t { BOOT_STATUS_REPORT = 0x01 }; +enum class AdcMonId : uint8_t { ADC_REPORT = 0x01 }; enum class MemManId : uint8_t { UPDATE_STATUS_REPORT = 0x01 }; enum class LatchupMonId : uint8_t { LATCHUP_STATUS_REPORT = 0x01 }; +enum class DataLoggerId : uint8_t { COUNTERS_REPORT = 0x01 }; } // namespace tm @@ -321,13 +362,13 @@ static const uint16_t SEQUENCE_COUNT_MASK = 0xFFF; static const uint8_t HK_SET_ENTRIES = 13; static const uint8_t BOOT_REPORT_SET_ENTRIES = 10; static const uint8_t LATCHUP_RPT_SET_ENTRIES = 16; -static const uint8_t LOGGING_RPT_SET_ENTRIES = 16; +static const uint8_t LOGGING_RPT_SET_ENTRIES = 30; static const uint8_t ADC_RPT_SET_ENTRIES = 32; static const uint32_t HK_SET_ID = HK_REPORT; static const uint32_t BOOT_REPORT_SET_ID = BOOT_STATUS_REPORT; static const uint32_t LATCHUP_RPT_ID = LATCHUP_REPORT; -static const uint32_t LOGGING_RPT_ID = LOGGING_REPORT; +static const uint32_t LOGGING_RPT_ID = COUNTERS_REPORT; static const uint32_t ADC_REPORT_SET_ID = ADC_REPORT; namespace timeout { @@ -392,7 +433,7 @@ enum PoolIds : lp_id_t { BR_SOC_STATE, POWER_CYCLES, BOOT_AFTER_MS, - BOOT_TIMEOUT_MS, + BOOT_TIMEOUT_POOL_VAR_MS, ACTIVE_NVM, BP0_STATE, BP1_STATE, @@ -417,13 +458,8 @@ enum PoolIds : lp_id_t { LATCHUP_RPT_TIME_MSEC, LATCHUP_RPT_IS_SET, - LATCHUP_HAPPENED_CNT_0, - LATCHUP_HAPPENED_CNT_1, - LATCHUP_HAPPENED_CNT_2, - LATCHUP_HAPPENED_CNT_3, - LATCHUP_HAPPENED_CNT_4, - LATCHUP_HAPPENED_CNT_5, - LATCHUP_HAPPENED_CNT_6, + SIGNATURE, + LATCHUP_HAPPENED_CNTS, ADC_DEVIATION_TRIGGERS_CNT, TC_RECEIVED_CNT, TM_AVAILABLE_CNT, @@ -432,40 +468,22 @@ enum PoolIds : lp_id_t { MPSOC_BOOT_FAILED_ATTEMPTS, MPSOC_POWER_UP, MPSOC_UPDATES, - LAST_RECVD_TC, + MPSOC_HEARTBEAT_RESETS, + CPU_WDT_RESETS, + PS_HEARTBEATS_LOST, + PL_HEARTBEATS_LOST, + EB_TASK_LOST, + BM_TASK_LOST, + LM_TASK_LOST, + AM_TASK_LOST, + TCTMM_TASK_LOST, + MM_TASK_LOST, + HK_TASK_LOST, + DL_TASK_LOST, + RWS_TASKS_LOST, - ADC_RAW_0, - ADC_RAW_1, - ADC_RAW_2, - ADC_RAW_3, - ADC_RAW_4, - ADC_RAW_5, - ADC_RAW_6, - ADC_RAW_7, - ADC_RAW_8, - ADC_RAW_9, - ADC_RAW_10, - ADC_RAW_11, - ADC_RAW_12, - ADC_RAW_13, - ADC_RAW_14, - ADC_RAW_15, - ADC_ENG_0, - ADC_ENG_1, - ADC_ENG_2, - ADC_ENG_3, - ADC_ENG_4, - ADC_ENG_5, - ADC_ENG_6, - ADC_ENG_7, - ADC_ENG_8, - ADC_ENG_9, - ADC_ENG_10, - ADC_ENG_11, - ADC_ENG_12, - ADC_ENG_13, - ADC_ENG_14, - ADC_ENG_15 + ADC_RAW, + ADC_ENG, }; struct TcParams : public ploc::SpTcParams { @@ -539,15 +557,6 @@ class TmBase : public ploc::SpTmReader { } } - bool verifyCrc() { - if (checkCrc() == returnvalue::OK) { - crcOk = true; - } - return crcOk; - } - - bool crcIsOk() const { return crcOk; } - uint8_t getServiceId() const { return getPacketData()[TIMESTAMP_LEN]; } uint16_t getModuleApid() const { return getApid() & APID_MODULE_MASK; } @@ -559,9 +568,6 @@ class TmBase : public ploc::SpTmReader { } return 0; } - - private: - bool crcOk = false; }; class NoPayloadPacket : public TcBase { @@ -769,8 +775,6 @@ class SetRestartTries : public TcBase { } private: - uint8_t restartTries = 0; - void initPacket(uint8_t restartTries) { payloadStart[0] = restartTries; } }; @@ -831,8 +835,6 @@ class LatchupAlert : public TcBase { } private: - uint8_t latchupId = 0; - void initPacket(uint8_t latchupId) { payloadStart[0] = latchupId; } }; @@ -862,9 +864,6 @@ class SetAlertlimit : public TcBase { } private: - uint8_t latchupId = 0; - uint32_t dutycycle = 0; - ReturnValue_t initPacket(uint8_t latchupId, uint32_t dutycycle) { payloadStart[0] = latchupId; size_t serLen = 0; @@ -1295,8 +1294,8 @@ class VerificationReport { virtual ~VerificationReport() = default; - virtual ReturnValue_t parse() { - if (not readerBase.crcIsOk()) { + virtual ReturnValue_t parse(bool checkCrc) { + if (checkCrc and readerBase.checkCrc() != returnvalue::OK) { return result::CRC_FAILURE; } if (readerBase.getModuleApid() != Apid::TMTC_MAN) { @@ -1313,27 +1312,27 @@ class VerificationReport { ReturnValue_t result = SerializeAdapter::deSerialize(&refApid, &payloadStart, &remLen, SerializeIF::Endianness::BIG); if (result != returnvalue::OK) { - sif::debug << "VerificationReport: Failed to deserialize reference APID field" << std::endl; + sif::warning << "VerificationReport: Failed to deserialize reference APID field" << std::endl; return result; } result = SerializeAdapter::deSerialize(&refServiceId, &payloadStart, &remLen, SerializeIF::Endianness::BIG); if (result != returnvalue::OK) { - sif::debug << "VerificationReport: Failed to deserialize reference Service ID field" - << std::endl; + sif::warning << "VerificationReport: Failed to deserialize reference Service ID field" + << std::endl; return result; } result = SerializeAdapter::deSerialize(&refSeqCount, &payloadStart, &remLen, SerializeIF::Endianness::BIG); if (result != returnvalue::OK) { - sif::debug << "VerificationReport: Failed to deserialize reference sequence count field" - << std::endl; + sif::warning << "VerificationReport: Failed to deserialize reference sequence count field" + << std::endl; return result; } result = SerializeAdapter::deSerialize(&statusCode, &payloadStart, &remLen, SerializeIF::Endianness::BIG); if (result != returnvalue::OK) { - sif::debug << "VerificationReport: Failed to deserialize status code field" << std::endl; + sif::warning << "VerificationReport: Failed to deserialize status code field" << std::endl; return result; } return returnvalue::OK; @@ -1350,7 +1349,7 @@ class VerificationReport { uint32_t getStatusCode() const { return statusCode; } - virtual void printStatusInformation(const char* prefix) { + virtual void printStatusInformation(const char* prefix) const { bool codeHandled = true; if (statusCode < 0x100) { GeneralStatusCode code = static_cast(getStatusCode()); @@ -1637,15 +1636,15 @@ class AcknowledgmentReport : public VerificationReport { public: AcknowledgmentReport(TmBase& readerBase) : VerificationReport(readerBase) {} - virtual ReturnValue_t parse() override { + ReturnValue_t parse(bool checkCrc) override { if (readerBase.getServiceId() != static_cast(tm::TmtcId::ACK) and readerBase.getServiceId() != static_cast(tm::TmtcId::NAK)) { return result::INVALID_SERVICE_ID; } - return VerificationReport::parse(); + return VerificationReport::parse(checkCrc); } - void printStatusInformation() { + void printStatusInformationAck() { VerificationReport::printStatusInformation(STATUS_PRINTOUT_PREFIX); } @@ -1659,15 +1658,15 @@ class ExecutionReport : public VerificationReport { TmBase& getReader() { return readerBase; } - ReturnValue_t parse() override { + ReturnValue_t parse(bool checkCrc) override { if (readerBase.getServiceId() != static_cast(tm::TmtcId::EXEC_ACK) and readerBase.getServiceId() != static_cast(tm::TmtcId::EXEC_NAK)) { return returnvalue::FAILED; } - return VerificationReport::parse(); + return VerificationReport::parse(checkCrc); } - void printStatusInformation() { + void printStatusInformationExe() { VerificationReport::printStatusInformation(STATUS_PRINTOUT_PREFIX); } @@ -1679,8 +1678,8 @@ class UpdateStatusReport { public: UpdateStatusReport(TmBase& tmReader) : tmReader(tmReader) {} - ReturnValue_t parse() { - if (not tmReader.crcIsOk()) { + ReturnValue_t parse(bool checkCrc) { + if (checkCrc and tmReader.checkCrc() != returnvalue::OK) { return result::CRC_FAILURE; } if (tmReader.getModuleApid() != Apid::MEM_MAN) { @@ -1742,7 +1741,7 @@ class BootStatusReport : public StaticLocalDataSet { lp_var_t bootAfterMs = lp_var_t(sid.objectId, PoolIds::BOOT_AFTER_MS, this); /** The currently set boot timeout */ lp_var_t bootTimeoutMs = - lp_var_t(sid.objectId, PoolIds::BOOT_TIMEOUT_MS, this); + lp_var_t(sid.objectId, PoolIds::BOOT_TIMEOUT_POOL_VAR_MS, this); lp_var_t activeNvm = lp_var_t(sid.objectId, PoolIds::ACTIVE_NVM, this); /** States of the boot partition pins */ lp_var_t bp0State = lp_var_t(sid.objectId, PoolIds::BP0_STATE, this); @@ -1814,26 +1813,16 @@ class LatchupStatusReport : public StaticLocalDataSet { /** * @brief This dataset stores the logging report. */ -class LoggingReport : public StaticLocalDataSet { +class CountersReport : public StaticLocalDataSet { public: - LoggingReport(HasLocalDataPoolIF* owner) : StaticLocalDataSet(owner, LOGGING_RPT_ID) {} + CountersReport(HasLocalDataPoolIF* owner) : StaticLocalDataSet(owner, LOGGING_RPT_ID) {} - LoggingReport(object_id_t objectId) : StaticLocalDataSet(sid_t(objectId, LOGGING_RPT_ID)) {} + CountersReport(object_id_t objectId) : StaticLocalDataSet(sid_t(objectId, LOGGING_RPT_ID)) {} - lp_var_t latchupHappenCnt0 = - lp_var_t(sid.objectId, PoolIds::LATCHUP_HAPPENED_CNT_0, this); - lp_var_t latchupHappenCnt1 = - lp_var_t(sid.objectId, PoolIds::LATCHUP_HAPPENED_CNT_1, this); - lp_var_t latchupHappenCnt2 = - lp_var_t(sid.objectId, PoolIds::LATCHUP_HAPPENED_CNT_2, this); - lp_var_t latchupHappenCnt3 = - lp_var_t(sid.objectId, PoolIds::LATCHUP_HAPPENED_CNT_3, this); - lp_var_t latchupHappenCnt4 = - lp_var_t(sid.objectId, PoolIds::LATCHUP_HAPPENED_CNT_4, this); - lp_var_t latchupHappenCnt5 = - lp_var_t(sid.objectId, PoolIds::LATCHUP_HAPPENED_CNT_5, this); - lp_var_t latchupHappenCnt6 = - lp_var_t(sid.objectId, PoolIds::LATCHUP_HAPPENED_CNT_6, this); + lp_var_t signature = + lp_var_t(sid.objectId, PoolIds::LATCHUP_HAPPENED_CNTS, this); + lp_vec_t latchupHappenCnts = + lp_vec_t(sid.objectId, PoolIds::LATCHUP_HAPPENED_CNTS, this); lp_var_t adcDeviationTriggersCnt = lp_var_t(sid.objectId, PoolIds::ADC_DEVIATION_TRIGGERS_CNT, this); lp_var_t tcReceivedCnt = @@ -1847,23 +1836,31 @@ class LoggingReport : public StaticLocalDataSet { lp_var_t(sid.objectId, PoolIds::MPSOC_BOOT_FAILED_ATTEMPTS, this); lp_var_t mpsocPowerup = lp_var_t(sid.objectId, PoolIds::MPSOC_POWER_UP, this); lp_var_t mpsocUpdates = lp_var_t(sid.objectId, PoolIds::MPSOC_UPDATES, this); - lp_var_t lastRecvdTc = lp_var_t(sid.objectId, PoolIds::LAST_RECVD_TC, this); + lp_var_t mpsocHeartbeatResets = + lp_var_t(sid.objectId, PoolIds::MPSOC_HEARTBEAT_RESETS, this); + lp_var_t cpuWdtResets = + lp_var_t(sid.objectId, PoolIds::MPSOC_HEARTBEAT_RESETS, this); + lp_var_t psHeartbeatsLost = + lp_var_t(sid.objectId, PoolIds::PS_HEARTBEATS_LOST, this); + lp_var_t plHeartbeatsLost = + lp_var_t(sid.objectId, PoolIds::PL_HEARTBEATS_LOST, this); + lp_var_t ebTaskLost = lp_var_t(sid.objectId, PoolIds::EB_TASK_LOST, this); + lp_var_t bmTaskLost = lp_var_t(sid.objectId, PoolIds::BM_TASK_LOST, this); + lp_var_t lmTaskLost = lp_var_t(sid.objectId, PoolIds::LM_TASK_LOST, this); + lp_var_t amTaskLost = lp_var_t(sid.objectId, PoolIds::AM_TASK_LOST, this); + lp_var_t tctmmTaskLost = + lp_var_t(sid.objectId, PoolIds::TCTMM_TASK_LOST, this); + lp_var_t mmTaskLost = lp_var_t(sid.objectId, PoolIds::MM_TASK_LOST, this); + lp_var_t hkTaskLost = lp_var_t(sid.objectId, PoolIds::HK_TASK_LOST, this); + lp_var_t dlTaskLost = lp_var_t(sid.objectId, PoolIds::DL_TASK_LOST, this); + lp_vec_t rwsTasksLost = + lp_vec_t(sid.objectId, PoolIds::RWS_TASKS_LOST, this); void printSet() { - sif::info << "LoggingReport: Latchup happened count 0: " << this->latchupHappenCnt0 - << std::endl; - sif::info << "LoggingReport: Latchup happened count 1: " << this->latchupHappenCnt1 - << std::endl; - sif::info << "LoggingReport: Latchup happened count 2: " << this->latchupHappenCnt2 - << std::endl; - sif::info << "LoggingReport: Latchup happened count 3: " << this->latchupHappenCnt3 - << std::endl; - sif::info << "LoggingReport: Latchup happened count 4: " << this->latchupHappenCnt4 - << std::endl; - sif::info << "LoggingReport: Latchup happened count 5: " << this->latchupHappenCnt5 - << std::endl; - sif::info << "LoggingReport: Latchup happened count 6: " << this->latchupHappenCnt6 - << std::endl; + for (unsigned i = 0; i < 7; i++) { + sif::info << "LoggingReport: Latchup happened count " << i << ": " + << this->latchupHappenCnts[i] << std::endl; + } sif::info << "LoggingReport: ADC deviation triggers count: " << this->adcDeviationTriggersCnt << std::endl; sif::info << "LoggingReport: TC received count: " << this->tcReceivedCnt << std::endl; @@ -1874,88 +1871,29 @@ class LoggingReport : public StaticLocalDataSet { << std::endl; sif::info << "LoggingReport: MPSoC power up: " << this->mpsocPowerup << std::endl; sif::info << "LoggingReport: MPSoC updates: " << this->mpsocUpdates << std::endl; - sif::info << "LoggingReport: APID of last received TC: 0x" << std::hex << this->lastRecvdTc - << std::endl; } }; /** * @brief This dataset stores the ADC report. */ -class AdcReport : public StaticLocalDataSet { +class AdcReport : public StaticLocalDataSet<3> { public: AdcReport(HasLocalDataPoolIF* owner) : StaticLocalDataSet(owner, ADC_REPORT_SET_ID) {} AdcReport(object_id_t objectId) : StaticLocalDataSet(sid_t(objectId, ADC_REPORT_SET_ID)) {} - lp_var_t adcRaw0 = lp_var_t(sid.objectId, PoolIds::ADC_RAW_0, this); - lp_var_t adcRaw1 = lp_var_t(sid.objectId, PoolIds::ADC_RAW_1, this); - lp_var_t adcRaw2 = lp_var_t(sid.objectId, PoolIds::ADC_RAW_2, this); - lp_var_t adcRaw3 = lp_var_t(sid.objectId, PoolIds::ADC_RAW_3, this); - lp_var_t adcRaw4 = lp_var_t(sid.objectId, PoolIds::ADC_RAW_4, this); - lp_var_t adcRaw5 = lp_var_t(sid.objectId, PoolIds::ADC_RAW_5, this); - lp_var_t adcRaw6 = lp_var_t(sid.objectId, PoolIds::ADC_RAW_6, this); - lp_var_t adcRaw7 = lp_var_t(sid.objectId, PoolIds::ADC_RAW_7, this); - lp_var_t adcRaw8 = lp_var_t(sid.objectId, PoolIds::ADC_RAW_8, this); - lp_var_t adcRaw9 = lp_var_t(sid.objectId, PoolIds::ADC_RAW_9, this); - lp_var_t adcRaw10 = lp_var_t(sid.objectId, PoolIds::ADC_RAW_10, this); - lp_var_t adcRaw11 = lp_var_t(sid.objectId, PoolIds::ADC_RAW_11, this); - lp_var_t adcRaw12 = lp_var_t(sid.objectId, PoolIds::ADC_RAW_12, this); - lp_var_t adcRaw13 = lp_var_t(sid.objectId, PoolIds::ADC_RAW_13, this); - lp_var_t adcRaw14 = lp_var_t(sid.objectId, PoolIds::ADC_RAW_14, this); - lp_var_t adcRaw15 = lp_var_t(sid.objectId, PoolIds::ADC_RAW_15, this); - lp_var_t adcEng0 = lp_var_t(sid.objectId, PoolIds::ADC_ENG_0, this); - lp_var_t adcEng1 = lp_var_t(sid.objectId, PoolIds::ADC_ENG_1, this); - lp_var_t adcEng2 = lp_var_t(sid.objectId, PoolIds::ADC_ENG_2, this); - lp_var_t adcEng3 = lp_var_t(sid.objectId, PoolIds::ADC_ENG_3, this); - lp_var_t adcEng4 = lp_var_t(sid.objectId, PoolIds::ADC_ENG_4, this); - lp_var_t adcEng5 = lp_var_t(sid.objectId, PoolIds::ADC_ENG_5, this); - lp_var_t adcEng6 = lp_var_t(sid.objectId, PoolIds::ADC_ENG_6, this); - lp_var_t adcEng7 = lp_var_t(sid.objectId, PoolIds::ADC_ENG_7, this); - lp_var_t adcEng8 = lp_var_t(sid.objectId, PoolIds::ADC_ENG_8, this); - lp_var_t adcEng9 = lp_var_t(sid.objectId, PoolIds::ADC_ENG_9, this); - lp_var_t adcEng10 = lp_var_t(sid.objectId, PoolIds::ADC_ENG_10, this); - lp_var_t adcEng11 = lp_var_t(sid.objectId, PoolIds::ADC_ENG_11, this); - lp_var_t adcEng12 = lp_var_t(sid.objectId, PoolIds::ADC_ENG_12, this); - lp_var_t adcEng13 = lp_var_t(sid.objectId, PoolIds::ADC_ENG_13, this); - lp_var_t adcEng14 = lp_var_t(sid.objectId, PoolIds::ADC_ENG_14, this); - lp_var_t adcEng15 = lp_var_t(sid.objectId, PoolIds::ADC_ENG_15, this); + lp_vec_t adcRaw = lp_vec_t(sid.objectId, PoolIds::ADC_RAW, this); + lp_vec_t adcEng = lp_vec_t(sid.objectId, PoolIds::ADC_ENG, this); void printSet() { sif::info << "---- Adc Report: Raw values ----" << std::endl; - sif::info << "AdcReport: ADC raw 0: " << std::dec << this->adcRaw0 << std::endl; - sif::info << "AdcReport: ADC raw 1: " << this->adcRaw1 << std::endl; - sif::info << "AdcReport: ADC raw 2: " << this->adcRaw2 << std::endl; - sif::info << "AdcReport: ADC raw 3: " << this->adcRaw3 << std::endl; - sif::info << "AdcReport: ADC raw 4: " << this->adcRaw4 << std::endl; - sif::info << "AdcReport: ADC raw 5: " << this->adcRaw5 << std::endl; - sif::info << "AdcReport: ADC raw 6: " << this->adcRaw6 << std::endl; - sif::info << "AdcReport: ADC raw 7: " << this->adcRaw7 << std::endl; - sif::info << "AdcReport: ADC raw 8: " << this->adcRaw8 << std::endl; - sif::info << "AdcReport: ADC raw 9: " << this->adcRaw9 << std::endl; - sif::info << "AdcReport: ADC raw 10: " << this->adcRaw10 << std::endl; - sif::info << "AdcReport: ADC raw 11: " << this->adcRaw11 << std::endl; - sif::info << "AdcReport: ADC raw 12: " << this->adcRaw12 << std::endl; - sif::info << "AdcReport: ADC raw 13: " << this->adcRaw13 << std::endl; - sif::info << "AdcReport: ADC raw 14: " << this->adcRaw14 << std::endl; - sif::info << "AdcReport: ADC raw 15: " << this->adcRaw15 << std::endl; - sif::info << "---- Adc Report: Engineering values ----" << std::endl; - sif::info << "AdcReport: ADC eng 0: " << this->adcEng0 << std::endl; - sif::info << "AdcReport: ADC eng 1: " << this->adcEng1 << std::endl; - sif::info << "AdcReport: ADC eng 2: " << this->adcEng2 << std::endl; - sif::info << "AdcReport: ADC eng 3: " << this->adcEng3 << std::endl; - sif::info << "AdcReport: ADC eng 4: " << this->adcEng4 << std::endl; - sif::info << "AdcReport: ADC eng 5: " << this->adcEng5 << std::endl; - sif::info << "AdcReport: ADC eng 6: " << this->adcEng6 << std::endl; - sif::info << "AdcReport: ADC eng 7: " << this->adcEng7 << std::endl; - sif::info << "AdcReport: ADC eng 8: " << this->adcEng8 << std::endl; - sif::info << "AdcReport: ADC eng 9: " << this->adcEng9 << std::endl; - sif::info << "AdcReport: ADC eng 10: " << this->adcEng10 << std::endl; - sif::info << "AdcReport: ADC eng 11: " << this->adcEng11 << std::endl; - sif::info << "AdcReport: ADC eng 12: " << this->adcEng12 << std::endl; - sif::info << "AdcReport: ADC eng 13: " << this->adcEng13 << std::endl; - sif::info << "AdcReport: ADC eng 14: " << this->adcEng14 << std::endl; - sif::info << "AdcReport: ADC eng 15: " << this->adcEng15 << std::endl; + for (unsigned i = 0; i < 16; i++) { + sif::info << "AdcReport: ADC raw " << i << ": " << std::dec << this->adcRaw[i] << std::endl; + } + for (unsigned i = 0; i < 16; i++) { + sif::info << "AdcReport: ADC eng " << i << ": " << std::dec << this->adcEng[i] << std::endl; + } } }; @@ -2045,11 +1983,7 @@ class EnableNvms : public TcBase { */ class EnableAutoTm : public TcBase { public: - EnableAutoTm(TcParams params) : TcBase(params) { - spParams.setFullPayloadLen(PAYLOAD_LENGTH + 2); - // spParams.creator.setApid(APID_AUTO_TM); - // spParams.creator.setSeqCount(DEFAULT_SEQUENCE_COUNT); - } + EnableAutoTm(TcParams params) : TcBase(params) { spParams.setFullPayloadLen(PAYLOAD_LENGTH + 2); } ReturnValue_t buildPacket() { auto res = checkSizeAndSerializeHeader(); diff --git a/mission/acs/str/ArcsecJsonParamBase.cpp b/mission/acs/str/ArcsecJsonParamBase.cpp index 58c54d30..704c23af 100644 --- a/mission/acs/str/ArcsecJsonParamBase.cpp +++ b/mission/acs/str/ArcsecJsonParamBase.cpp @@ -65,7 +65,7 @@ void ArcsecJsonParamBase::addSetParamHeader(uint8_t* buffer, uint8_t setId) { *(buffer + 1) = setId; } -ReturnValue_t ArcsecJsonParamBase::init(const std::string filename) { +ReturnValue_t ArcsecJsonParamBase::init(const std::string& filename) { ReturnValue_t result = returnvalue::OK; if (not std::filesystem::exists(filename)) { sif::warning << "ArcsecJsonParamBase::init: JSON file " << filename << " does not exist" diff --git a/mission/acs/str/ArcsecJsonParamBase.h b/mission/acs/str/ArcsecJsonParamBase.h index 4c4a7a90..b855a322 100644 --- a/mission/acs/str/ArcsecJsonParamBase.h +++ b/mission/acs/str/ArcsecJsonParamBase.h @@ -46,7 +46,7 @@ class ArcsecJsonParamBase { * @param return JSON_FILE_NOT_EXISTS if specified file does not exist, otherwise * returnvalue::OK */ - ReturnValue_t init(const std::string filename); + ReturnValue_t init(const std::string& filename); /** * @brief Fills a buffer with a parameter set diff --git a/mission/acs/str/StarTrackerHandler.cpp b/mission/acs/str/StarTrackerHandler.cpp index 541301f1..147c04d8 100644 --- a/mission/acs/str/StarTrackerHandler.cpp +++ b/mission/acs/str/StarTrackerHandler.cpp @@ -5,6 +5,8 @@ #include #include +#include "fsfw/ipc/MessageQueueIF.h" + extern "C" { #include #include @@ -24,8 +26,8 @@ extern "C" { std::atomic_bool JCFG_DONE(false); StarTrackerHandler::StarTrackerHandler(object_id_t objectId, object_id_t comIF, CookieIF* comCookie, - const char* jsonFileStr, StrComHandler* strHelper, - power::Switch_t powerSwitch) + StrComHandler* strHelper, power::Switch_t powerSwitch, + startracker::SdCardConfigPathGetter& cfgPathGetter) : DeviceHandlerBase(objectId, comIF, comCookie), temperatureSet(this), versionSet(this), @@ -57,8 +59,8 @@ StarTrackerHandler::StarTrackerHandler(object_id_t objectId, object_id_t comIF, centroidsSet(this), contrastSet(this), strHelper(strHelper), - paramJsonFile(jsonFileStr), - powerSwitch(powerSwitch) { + powerSwitch(powerSwitch), + cfgPathGetter(cfgPathGetter) { if (comCookie == nullptr) { sif::error << "StarTrackerHandler: Invalid com cookie" << std::endl; } @@ -82,17 +84,12 @@ void StarTrackerHandler::doStartUp() { // the device handler's submode to the star tracker's mode return; case StartupState::DONE: - if (jcfgCountdown.isBusy()) { + if (!JCFG_DONE) { startupState = StartupState::WAIT_JCFG; return; } - startupState = StartupState::IDLE; break; case StartupState::WAIT_JCFG: { - if (jcfgCountdown.hasTimedOut()) { - startupState = StartupState::IDLE; - break; - } return; } default: @@ -139,8 +136,7 @@ ReturnValue_t StarTrackerHandler::initialize() { // 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()}; + reloadJsonCfgFile(); EventManagerIF* manager = ObjectManager::instance()->get(objects::EVENT_MANAGER); if (manager == nullptr) { @@ -169,6 +165,20 @@ ReturnValue_t StarTrackerHandler::initialize() { return returnvalue::OK; } +bool StarTrackerHandler::reloadJsonCfgFile() { + jcfgCountdown.resetTimer(); + auto strCfgPath = cfgPathGetter.getCfgPath(); + if (strCfgPath.has_value()) { + jcfgPending = true; + JCFG_DONE = false; + jsonCfgTask = std::thread{setUpJsonCfgs, std::ref(jcfgs), strCfgPath.value()}; + return true; + } + // Simplified FDIR: Just continue as usual.. + JCFG_DONE = true; + return false; +} + ReturnValue_t StarTrackerHandler::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy, const uint8_t* data, size_t size) { ReturnValue_t result = returnvalue::OK; @@ -335,6 +345,24 @@ void StarTrackerHandler::performOperationHook() { break; } } + if (jcfgPending) { + if (JCFG_DONE) { + if (startupState == StartupState::WAIT_JCFG) { + startupState = StartupState::DONE; + } + jsonCfgTask.join(); + jcfgPending = false; + auto iter = deviceCommandMap.find(startracker::RELOAD_JSON_CFG_FILE); + if (iter != deviceCommandMap.end() and iter->second.sendReplyTo != MessageQueueIF::NO_QUEUE) { + actionHelper.finish(true, iter->second.sendReplyTo, startracker::RELOAD_JSON_CFG_FILE); + } + } else if (jcfgCountdown.hasTimedOut()) { + auto iter = deviceCommandMap.find(startracker::RELOAD_JSON_CFG_FILE); + if (iter != deviceCommandMap.end() and iter->second.sendReplyTo != MessageQueueIF::NO_QUEUE) { + actionHelper.finish(false, iter->second.sendReplyTo, startracker::RELOAD_JSON_CFG_FILE); + } + } + } } Submode_t StarTrackerHandler::getInitialSubmode() { return startracker::SUBMODE_BOOTLOADER; } @@ -499,6 +527,16 @@ ReturnValue_t StarTrackerHandler::buildCommandFromCommand(DeviceCommandId_t devi preparePingRequest(); return returnvalue::OK; } + case (startracker::RELOAD_JSON_CFG_FILE): { + if (jcfgPending) { + return HasActionsIF::IS_BUSY; + } + // It should be noted that this just reloads the JSON config structure in memory from the + // JSON file. The configuration still needs to be sent to the STR. The easiest way to achieve + // this is to simply reboot the device after a reload. + reloadJsonCfgFile(); + return returnvalue::OK; + } case (startracker::SET_TIME_FROM_SYS_TIME): { SetTimeActionRequest setTimeRequest{}; timeval tv; @@ -513,6 +551,7 @@ ReturnValue_t StarTrackerHandler::buildCommandFromCommand(DeviceCommandId_t devi rawPacket = commandBuffer; return returnvalue::OK; } + case (startracker::REQ_TIME): { prepareTimeRequest(); return returnvalue::OK; @@ -726,6 +765,7 @@ void StarTrackerHandler::fillCommandAndReplyMap() { startracker::MAX_FRAME_SIZE * 2 + 2); this->insertInCommandMap(startracker::UPLOAD_IMAGE); this->insertInCommandMap(startracker::DOWNLOAD_IMAGE); + this->insertInCommandMap(startracker::RELOAD_JSON_CFG_FILE); this->insertInCommandAndReplyMap(startracker::REQ_POWER, 3, &powerSet, startracker::MAX_FRAME_SIZE * 2 + 2); this->insertInCommandAndReplyMap(startracker::REQ_INTERFACE, 3, &interfaceSet, @@ -928,7 +968,7 @@ void StarTrackerHandler::bootFirmware(Mode_t toMode) { } } -void StarTrackerHandler::setUpJsonCfgs(JsonConfigs& cfgs, const char* paramJsonFile) { +void StarTrackerHandler::setUpJsonCfgs(JsonConfigs& cfgs, std::string paramJsonFile) { cfgs.tracking.init(paramJsonFile); cfgs.logLevel.init(paramJsonFile); cfgs.logSubscription.init(paramJsonFile); @@ -2811,3 +2851,5 @@ ReturnValue_t StarTrackerHandler::checkCommand(ActionId_t actionId) { } return returnvalue::OK; } + +ReturnValue_t StarTrackerHandler::acceptExternalDeviceCommands() { return returnvalue::OK; } diff --git a/mission/acs/str/StarTrackerHandler.h b/mission/acs/str/StarTrackerHandler.h index 3bfdc8fd..6bc1ff09 100644 --- a/mission/acs/str/StarTrackerHandler.h +++ b/mission/acs/str/StarTrackerHandler.h @@ -27,7 +27,9 @@ extern "C" { * @details Datasheet: https://eive-cloud.irs.uni-stuttgart.de/index.php/apps/files/?dir=/EIVE_IRS/ * Arbeitsdaten/08_Used%20Components/ArcSec_KULeuven_Startracker/ * Sagitta%201.0%20Datapack&fileid=659181 - * @author J. Meier + * @note The STR code is a chaotic inconsistent mess and should be re-written with a simpler base + * class. DO NOT USE THIS AS REFERENCE. Stay away from it. + * @author J. Meier, R. Mueller */ class StarTrackerHandler : public DeviceHandlerBase { public: @@ -42,8 +44,8 @@ class StarTrackerHandler : public DeviceHandlerBase { * to high to enable the device. */ StarTrackerHandler(object_id_t objectId, object_id_t comIF, CookieIF* comCookie, - const char* jsonFileStr, StrComHandler* strHelper, - power::Switch_t powerSwitch); + StrComHandler* strHelper, power::Switch_t powerSwitch, + startracker::SdCardConfigPathGetter& cfgPathGetter); virtual ~StarTrackerHandler(); ReturnValue_t initialize() override; @@ -240,11 +242,12 @@ class StarTrackerHandler : public DeviceHandlerBase { Subscription subscription; AutoThreshold autoThreshold; }; + bool jcfgPending = false; JsonConfigs jcfgs; - Countdown jcfgCountdown = Countdown(250); + Countdown jcfgCountdown = Countdown(1000); bool commandExecuted = false; std::thread jsonCfgTask; - static void setUpJsonCfgs(JsonConfigs& cfgs, const char* paramJsonFile); + static void setUpJsonCfgs(JsonConfigs& cfgs, std::string paramJsonFile); std::string paramJsonFile; @@ -311,6 +314,8 @@ class StarTrackerHandler : public DeviceHandlerBase { std::set additionalRequestedTm{}; std::set::iterator currentSecondaryTmIter; + startracker::SdCardConfigPathGetter& cfgPathGetter; + /** * @brief Handles internal state */ @@ -542,6 +547,8 @@ class StarTrackerHandler : public DeviceHandlerBase { void doNormalTransition(Mode_t modeFrom, Submode_t subModeFrom); void bootFirmware(Mode_t toMode); void bootBootloader(); + bool reloadJsonCfgFile(); + ReturnValue_t acceptExternalDeviceCommands() override; }; #endif /* MISSION_DEVICES_STARTRACKERHANDLER_H_ */ diff --git a/mission/acs/str/strHelpers.h b/mission/acs/str/strHelpers.h index 808d6060..8f83331d 100644 --- a/mission/acs/str/strHelpers.h +++ b/mission/acs/str/strHelpers.h @@ -14,6 +14,12 @@ namespace startracker { static const Submode_t SUBMODE_BOOTLOADER = 1; static const Submode_t SUBMODE_FIRMWARE = 2; +class SdCardConfigPathGetter { + public: + virtual ~SdCardConfigPathGetter() = default; + virtual std::optional getCfgPath() = 0; +}; + /** * @brief Returns the frame type field of a decoded frame. */ @@ -381,6 +387,7 @@ static constexpr DeviceCommandId_t REQ_CENTROIDS = 94; static constexpr DeviceCommandId_t ADD_SECONDARY_TM_TO_NORMAL_MODE = 95; static constexpr DeviceCommandId_t RESET_SECONDARY_TM_SET = 96; static constexpr DeviceCommandId_t READ_SECONDARY_TM_SET = 97; +static constexpr DeviceCommandId_t RELOAD_JSON_CFG_FILE = 100; static const DeviceCommandId_t NONE = 0xFFFFFFFF; static const uint32_t VERSION_SET_ID = REQ_VERSION; diff --git a/mission/com/LiveTmTask.cpp b/mission/com/LiveTmTask.cpp index 56fe5a51..33b9322a 100644 --- a/mission/com/LiveTmTask.cpp +++ b/mission/com/LiveTmTask.cpp @@ -54,8 +54,13 @@ ReturnValue_t LiveTmTask::performOperation(uint8_t opCode) { } } } else if (result != MessageQueueIF::EMPTY) { - sif::warning << "LiveTmTask: TM queue failure, returncode 0x" << std::hex << std::setw(4) - << result << std::dec << std::endl; + const char* contextStr = "Regular TM queue"; + if (isCfdp) { + contextStr = "CFDP TM queue"; + } + sif::warning << "LiveTmTask: " << contextStr << " handling failure, returncode 0x" + << std::setfill('0') << std::hex << std::setw(4) << result << std::dec + << std::endl; } } @@ -173,15 +178,16 @@ ReturnValue_t LiveTmTask::handleGenericTmQueue(MessageQueueIF& queue, bool isCfd size_t writtenSize = 0; result = channel.write(data, size, writtenSize); if (result == DirectTmSinkIF::PARTIALLY_WRITTEN) { - result = channel.handleWriteCompletionSynchronously(writtenSize, 200); + result = channel.handleWriteCompletionSynchronously(writtenSize, 400); if (result != returnvalue::OK) { // TODO: Event? Might lead to dangerous spam though.. sif::warning << "LiveTmTask: Synchronous write of last segment failed with code 0x" - << std::setw(4) << std::hex << result << std::dec << std::endl; + << std::setfill('0') << std::setw(4) << std::hex << result << std::dec + << std::endl; } } else if (result != returnvalue::OK) { - sif::error << "LiveTmTask: Channel write failed with code 0x" << std::hex << std::setw(4) - << result << std::dec << std::endl; + sif::error << "LiveTmTask: Channel write failed with code 0x" << std::setfill('0') << std::hex + << std::setw(4) << result << std::dec << std::endl; } } // Try delete in any case, ignore failures (which should not happen), it is more important to diff --git a/mission/com/TmStoreTaskBase.cpp b/mission/com/TmStoreTaskBase.cpp index 215cef08..9e86ba08 100644 --- a/mission/com/TmStoreTaskBase.cpp +++ b/mission/com/TmStoreTaskBase.cpp @@ -141,11 +141,12 @@ ReturnValue_t TmStoreTaskBase::performDump(PersistentTmStoreWithTmQueue& store, size_t writtenSize = 0; result = channel.write(tmReader.getFullData(), dumpedLen, writtenSize); if (result == VirtualChannelIF::PARTIALLY_WRITTEN) { - result = channel.handleWriteCompletionSynchronously(writtenSize, 200); + result = channel.handleWriteCompletionSynchronously(writtenSize, 400); if (result != returnvalue::OK) { // TODO: Event? Might lead to dangerous spam though.. - sif::warning << "PersistentTmStore: Synchronous write of last segment failed with code 0x" - << std::setw(4) << std::hex << result << std::dec << std::endl; + sif::warning << "LiveTmTask: Synchronous write of last segment failed with code 0x" + << std::setfill('0') << std::setw(4) << std::hex << result << std::dec + << std::endl; } } else if (result == DirectTmSinkIF::IS_BUSY) { sif::warning << "PersistentTmStore: Unexpected VC channel busy" << std::endl; diff --git a/mission/com/VirtualChannel.cpp b/mission/com/VirtualChannel.cpp index e531727e..a75959e6 100644 --- a/mission/com/VirtualChannel.cpp +++ b/mission/com/VirtualChannel.cpp @@ -74,5 +74,7 @@ ReturnValue_t VirtualChannel::handleWriteCompletionSynchronously(size_t& written return result; } } - return returnvalue::FAILED; + // Timeout. Cancel the transfer + cancelTransfer(); + return TIMEOUT; } diff --git a/mission/com/VirtualChannelWithQueue.cpp b/mission/com/VirtualChannelWithQueue.cpp index 0d9e4d11..fb3375dc 100644 --- a/mission/com/VirtualChannelWithQueue.cpp +++ b/mission/com/VirtualChannelWithQueue.cpp @@ -41,7 +41,7 @@ ReturnValue_t VirtualChannelWithQueue::handleNextTm(bool performWriteOp) { if (performWriteOp) { result = write(data, size, writtenSize); if (result == PARTIALLY_WRITTEN) { - result = handleWriteCompletionSynchronously(writtenSize, 200); + result = handleWriteCompletionSynchronously(writtenSize, 400); if (result != returnvalue::OK) { // TODO: Event? Might lead to dangerous spam though.. sif::warning diff --git a/mission/payload/PayloadPcduHandler.cpp b/mission/payload/PayloadPcduHandler.cpp index b3b71aea..1fc3fa99 100644 --- a/mission/payload/PayloadPcduHandler.cpp +++ b/mission/payload/PayloadPcduHandler.cpp @@ -4,6 +4,7 @@ #include "OBSWConfig.h" #include "fsfw/thermal/tcsDefinitions.h" +#include "mission/payload/payloadPcduDefinitions.h" #ifdef XIPHOS_Q7S #include @@ -428,20 +429,20 @@ void PayloadPcduHandler::checkAdcValues() { params.getValue(PARAM_KEY_MAP[NEG_V_UPPER_BOUND], upperBound); if (not checkVoltage(adcSet.processed[U_NEG_V_FB], lowerBound, upperBound, NEG_V_OUT_OF_BOUNDS)) { + sif::warning << "Negative voltage was out of bounds, went back to OFF" << std::endl; return; } params.getValue(PARAM_KEY_MAP[DRO_U_LOWER_BOUND], lowerBound); params.getValue(PARAM_KEY_MAP[DRO_U_UPPER_BOUND], upperBound); if (not checkVoltage(adcSet.processed[U_DRO_DIV_6], lowerBound, upperBound, U_DRO_OUT_OF_BOUNDS)) { + sif::warning << "DRO voltage was out of bounds, went back to OFF" << std::endl; return; } params.getValue(PARAM_KEY_MAP[DRO_I_UPPER_BOUND], upperBound); if (not checkCurrent(adcSet.processed[I_DRO], upperBound, I_DRO_OUT_OF_BOUNDS)) { -#if OBSW_VERBOSE_LEVEL >= 1 sif::warning << "Detected out of bounds current for DRO: " << adcSet.processed[I_DRO] << ", Raw: " << adcSet.channels[I_DRO] << std::endl; -#endif return; } } @@ -455,10 +456,12 @@ void PayloadPcduHandler::checkAdcValues() { params.getValue(PARAM_KEY_MAP[X8_U_UPPER_BOUND], upperBound); if (not checkVoltage(adcSet.processed[U_X8_DIV_6], lowerBound, upperBound, U_X8_OUT_OF_BOUNDS)) { + sif::warning << "X8 voltage was out of bounds, went back to OFF" << std::endl; return; } params.getValue(PARAM_KEY_MAP[X8_I_UPPER_BOUND], upperBound); if (not checkCurrent(adcSet.processed[I_X8], upperBound, I_X8_OUT_OF_BOUNDS)) { + sif::warning << "X8 current was out of bounds, went back to OFF" << std::endl; return; } } @@ -472,10 +475,12 @@ void PayloadPcduHandler::checkAdcValues() { params.getValue(PARAM_KEY_MAP[TX_U_UPPER_BOUND], upperBound); if (not checkVoltage(adcSet.processed[U_TX_DIV_6], lowerBound, upperBound, U_TX_OUT_OF_BOUNDS)) { + sif::warning << "TX voltage was out of bounds, went back to OFF" << std::endl; return; } params.getValue(PARAM_KEY_MAP[TX_I_UPPER_BOUND], upperBound); if (not checkCurrent(adcSet.processed[I_TX], upperBound, I_TX_OUT_OF_BOUNDS)) { + sif::warning << "TX current was out of bounds, went back to OFF" << std::endl; return; } } @@ -489,10 +494,12 @@ void PayloadPcduHandler::checkAdcValues() { params.getValue(PARAM_KEY_MAP[MPA_U_UPPER_BOUND], upperBound); if (not checkVoltage(adcSet.processed[U_MPA_DIV_6], lowerBound, upperBound, U_MPA_OUT_OF_BOUNDS)) { + sif::warning << "MPA voltage was out of bounds, went back to OFF" << std::endl; return; } params.getValue(PARAM_KEY_MAP[MPA_I_UPPER_BOUND], upperBound); if (not checkCurrent(adcSet.processed[I_MPA], upperBound, I_MPA_OUT_OF_BOUNDS)) { + sif::warning << "MPA current was out of bounds, went back to OFF" << std::endl; return; } } @@ -506,6 +513,7 @@ void PayloadPcduHandler::checkAdcValues() { params.getValue(PARAM_KEY_MAP[HPA_U_UPPER_BOUND], upperBound); if (not checkVoltage(adcSet.processed[U_HPA_DIV_6], lowerBound, upperBound, U_HPA_OUT_OF_BOUNDS)) { + sif::warning << "HPA voltage was out of bounds, went back to OFF" << std::endl; return; } params.getValue(PARAM_KEY_MAP[HPA_I_UPPER_BOUND], upperBound); @@ -576,6 +584,7 @@ void PayloadPcduHandler::performOperationHook() { checkJsonFileInit(); } ReturnValue_t PayloadPcduHandler::checkModeCommand(Mode_t commandedMode, Submode_t commandedSubmode, uint32_t* msToReachTheMode) { + using namespace plpcdu; if (commandedMode != MODE_OFF) { PoolReadGuard pg(&enablePl); if (pg.getReadResult() == returnvalue::OK) { @@ -584,45 +593,59 @@ ReturnValue_t PayloadPcduHandler::checkModeCommand(Mode_t commandedMode, Submode } } } - return DeviceHandlerBase::checkModeCommand(commandedMode, commandedSubmode, msToReachTheMode); -} - -ReturnValue_t PayloadPcduHandler::isModeCombinationValid(Mode_t mode, Submode_t submode) { - using namespace plpcdu; - if (mode == MODE_NORMAL) { + if (commandedMode == MODE_NORMAL) { uint8_t dhbSubmode = getSubmode(); - diffMask = submode ^ dhbSubmode; - // Also deals with the case where the mode is MODE_ON, submode should be 0 here - if ((((submode >> SOLID_STATE_RELAYS_ADC_ON) & 0b1) == SOLID_STATE_RELAYS_ADC_ON) and - (getMode() == MODE_NORMAL and dhbSubmode != ALL_OFF_SUBMODE)) { + diffMask = commandedSubmode ^ dhbSubmode; + // For all higher level modes, SSR needs to be on. This is to ensure we have valid ADC + // measurements + if ((droOnForSubmode(commandedSubmode) or x8OnForSubmode(commandedSubmode) or + txOnForSubmode(commandedSubmode) or mpaOnForSubmode(commandedSubmode) or + hpaOnForSubmode(commandedSubmode)) and + not ssrOnForSubmode(dhbSubmode)) { return TRANS_NOT_ALLOWED; } - if (((((submode >> DRO_ON) & 1) == 1) and - ((dhbSubmode & 0b1) != (1 << SOLID_STATE_RELAYS_ADC_ON)))) { + if (disableChannelOrderCheck) { + return returnvalue::OK; + } + if (x8OnForSubmode(commandedSubmode) and not droOnForSubmode(dhbSubmode)) { return TRANS_NOT_ALLOWED; } - if ((((submode >> X8_ON) & 1) == 1) and - ((dhbSubmode & 0b11) != ((1 << SOLID_STATE_RELAYS_ADC_ON) | (1 << DRO_ON)))) { + if (txOnForSubmode(commandedSubmode) and + (not droOnForSubmode(dhbSubmode) or not x8OnForSubmode(dhbSubmode))) { return TRANS_NOT_ALLOWED; } - if (((((submode >> TX_ON) & 1) == 1) and - ((dhbSubmode & 0b111) != - ((1 << X8_ON) | (1 << DRO_ON) | (1 << SOLID_STATE_RELAYS_ADC_ON))))) { + if (mpaOnForSubmode(commandedSubmode) and + (not droOnForSubmode(dhbSubmode) or not x8OnForSubmode(dhbSubmode) or + not txOnForSubmode(dhbSubmode))) { return TRANS_NOT_ALLOWED; } - if ((((submode >> MPA_ON) & 1) == 1 and - ((dhbSubmode & 0b1111) != - ((1 << TX_ON) | (1 << X8_ON) | (1 << DRO_ON) | (1 << SOLID_STATE_RELAYS_ADC_ON))))) { - return TRANS_NOT_ALLOWED; - } - if ((((submode >> HPA_ON) & 1) == 1 and - ((dhbSubmode & 0b11111) != ((1 << MPA_ON) | (1 << TX_ON) | (1 << X8_ON) | (1 << DRO_ON) | - (1 << SOLID_STATE_RELAYS_ADC_ON))))) { + if (hpaOnForSubmode(commandedSubmode) and + (not droOnForSubmode(dhbSubmode) or not x8OnForSubmode(dhbSubmode) or + not txOnForSubmode(dhbSubmode) or not mpaOnForSubmode(dhbSubmode))) { return TRANS_NOT_ALLOWED; } return returnvalue::OK; } - return DeviceHandlerBase::isModeCombinationValid(mode, submode); + return DeviceHandlerBase::checkModeCommand(commandedMode, commandedSubmode, msToReachTheMode); +} + +bool PayloadPcduHandler::ssrOnForSubmode(uint8_t submode) { + return submode & (1 << plpcdu::SOLID_STATE_RELAYS_ADC_ON); +} +bool PayloadPcduHandler::droOnForSubmode(uint8_t submode) { + return submode & (1 << plpcdu::DRO_ON); +} + +bool PayloadPcduHandler::x8OnForSubmode(uint8_t submode) { return submode & (1 << plpcdu::X8_ON); } + +bool PayloadPcduHandler::txOnForSubmode(uint8_t submode) { return submode & (1 << plpcdu::TX_ON); } + +bool PayloadPcduHandler::mpaOnForSubmode(uint8_t submode) { + return submode & (1 << plpcdu::MPA_ON); +} + +bool PayloadPcduHandler::hpaOnForSubmode(uint8_t submode) { + return submode & (1 << plpcdu::HPA_ON); } ReturnValue_t PayloadPcduHandler::serializeFloat(uint32_t& param, float val) { @@ -637,56 +660,68 @@ ReturnValue_t PayloadPcduHandler::getParameter(uint8_t domainId, uint8_t uniqueI uint16_t startAtIndex) { using namespace plpcdu; switch (uniqueId) { - case (PlPcduParamIds::NEG_V_LOWER_BOUND): - case (PlPcduParamIds::NEG_V_UPPER_BOUND): - case (PlPcduParamIds::DRO_U_LOWER_BOUND): - case (PlPcduParamIds::DRO_U_UPPER_BOUND): - case (PlPcduParamIds::DRO_I_UPPER_BOUND): - case (PlPcduParamIds::X8_U_LOWER_BOUND): - case (PlPcduParamIds::X8_U_UPPER_BOUND): - case (PlPcduParamIds::X8_I_UPPER_BOUND): - case (PlPcduParamIds::TX_U_LOWER_BOUND): - case (PlPcduParamIds::TX_U_UPPER_BOUND): - case (PlPcduParamIds::TX_I_UPPER_BOUND): - case (PlPcduParamIds::MPA_U_LOWER_BOUND): - case (PlPcduParamIds::MPA_U_UPPER_BOUND): - case (PlPcduParamIds::MPA_I_UPPER_BOUND): - case (PlPcduParamIds::HPA_U_LOWER_BOUND): - case (PlPcduParamIds::HPA_U_UPPER_BOUND): - case (PlPcduParamIds::HPA_I_UPPER_BOUND): - case (PlPcduParamIds::SSR_TO_DRO_WAIT_TIME): - case (PlPcduParamIds::DRO_TO_X8_WAIT_TIME): - case (PlPcduParamIds::X8_TO_TX_WAIT_TIME): - case (PlPcduParamIds::TX_TO_MPA_WAIT_TIME): - case (PlPcduParamIds::MPA_TO_HPA_WAIT_TIME): { - handleDoubleParamUpdate(PARAM_KEY_MAP[static_cast(uniqueId)], - parameterWrapper, newValues); + case (PlPcduParamId::NEG_V_LOWER_BOUND): + case (PlPcduParamId::NEG_V_UPPER_BOUND): + case (PlPcduParamId::DRO_U_LOWER_BOUND): + case (PlPcduParamId::DRO_U_UPPER_BOUND): + case (PlPcduParamId::DRO_I_UPPER_BOUND): + case (PlPcduParamId::X8_U_LOWER_BOUND): + case (PlPcduParamId::X8_U_UPPER_BOUND): + case (PlPcduParamId::X8_I_UPPER_BOUND): + case (PlPcduParamId::TX_U_LOWER_BOUND): + case (PlPcduParamId::TX_U_UPPER_BOUND): + case (PlPcduParamId::TX_I_UPPER_BOUND): + case (PlPcduParamId::MPA_U_LOWER_BOUND): + case (PlPcduParamId::MPA_U_UPPER_BOUND): + case (PlPcduParamId::MPA_I_UPPER_BOUND): + case (PlPcduParamId::HPA_U_LOWER_BOUND): + case (PlPcduParamId::HPA_U_UPPER_BOUND): + case (PlPcduParamId::HPA_I_UPPER_BOUND): + case (PlPcduParamId::SSR_TO_DRO_WAIT_TIME): + case (PlPcduParamId::DRO_TO_X8_WAIT_TIME): + case (PlPcduParamId::X8_TO_TX_WAIT_TIME): + case (PlPcduParamId::TX_TO_MPA_WAIT_TIME): + case (PlPcduParamId::MPA_TO_HPA_WAIT_TIME): { + handleDoubleParamUpdate(PARAM_KEY_MAP[static_cast(uniqueId)], parameterWrapper, + newValues); break; } - case (PlPcduParamIds::INJECT_SSR_TO_DRO_FAILURE): { + case (PlPcduParamId::INJECT_SSR_TO_DRO_FAILURE): { ssrToDroInjectionRequested = true; break; } - case (PlPcduParamIds::INJECT_DRO_TO_X8_FAILURE): { + case (PlPcduParamId::INJECT_DRO_TO_X8_FAILURE): { droToX8InjectionRequested = true; break; } - case (PlPcduParamIds::INJECT_X8_TO_TX_FAILURE): { + case (PlPcduParamId::INJECT_X8_TO_TX_FAILURE): { x8ToTxInjectionRequested = true; break; } - case (PlPcduParamIds::INJECT_TX_TO_MPA_FAILURE): { + case (PlPcduParamId::INJECT_TX_TO_MPA_FAILURE): { txToMpaInjectionRequested = true; break; } - case (PlPcduParamIds::INJECT_MPA_TO_HPA_FAILURE): { + case (PlPcduParamId::INJECT_MPA_TO_HPA_FAILURE): { mpaToHpaInjectionRequested = true; break; } - case (PlPcduParamIds::INJECT_ALL_ON_FAILURE): { + case (PlPcduParamId::INJECT_ALL_ON_FAILURE): { allOnInjectRequested = true; break; } + case (PlPcduParamId::DISABLE_ORDER_CHECK_CHANNELS): { + uint8_t newValue = 0; + ReturnValue_t result = newValues->getElement(&newValue); + if (result != returnvalue::OK) { + return result; + } + if (newValue > 1) { + return HasParametersIF::INVALID_VALUE; + } + parameterWrapper->set(disableChannelOrderCheck); + break; + } default: { return DeviceHandlerBase::getParameter(domainId, uniqueId, parameterWrapper, newValues, startAtIndex); diff --git a/mission/payload/PayloadPcduHandler.h b/mission/payload/PayloadPcduHandler.h index d48d0f89..da9da1e1 100644 --- a/mission/payload/PayloadPcduHandler.h +++ b/mission/payload/PayloadPcduHandler.h @@ -137,6 +137,12 @@ class PayloadPcduHandler : public DeviceHandlerBase { PoolEntry({0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}); PoolEntry tempC = PoolEntry({0.0}); + /** + * This parameter disables all checks for the channels except the SSR on check. The SSR on check + * is kept to ensure that there is a common start point where the ADC is enabled. + */ + uint8_t disableChannelOrderCheck = false; + void updateSwitchGpio(gpioId_t id, gpio::Levels level); void doTransition(Mode_t modeFrom, Submode_t subModeFrom) override; @@ -155,7 +161,6 @@ class PayloadPcduHandler : public DeviceHandlerBase { uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) override; ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, LocalDataPoolManager& poolManager) override; - ReturnValue_t isModeCombinationValid(Mode_t mode, Submode_t submode) override; ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId, ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, uint16_t startAtIndex) override; @@ -177,6 +182,12 @@ class PayloadPcduHandler : public DeviceHandlerBase { pwrctrl::EnablePl enablePl = pwrctrl::EnablePl(objects::POWER_CONTROLLER); ReturnValue_t checkModeCommand(Mode_t commandedMode, Submode_t commandedSubmode, uint32_t* msToReachTheMode) override; + static bool ssrOnForSubmode(uint8_t submode); + static bool droOnForSubmode(uint8_t submode); + static bool x8OnForSubmode(uint8_t submode); + static bool txOnForSubmode(uint8_t submode); + static bool mpaOnForSubmode(uint8_t submode); + static bool hpaOnForSubmode(uint8_t submode); }; #endif /* LINUX_DEVICES_PLPCDUHANDLER_H_ */ diff --git a/mission/payload/payloadPcduDefinitions.h b/mission/payload/payloadPcduDefinitions.h index e6c7b653..dbd38a9d 100644 --- a/mission/payload/payloadPcduDefinitions.h +++ b/mission/payload/payloadPcduDefinitions.h @@ -35,7 +35,7 @@ enum PlPcduAdcChannels : uint8_t { NUM_CHANNELS = 12 }; -enum PlPcduParamIds : uint8_t { +enum PlPcduParamId : uint8_t { NEG_V_LOWER_BOUND = 0, NEG_V_UPPER_BOUND = 1, DRO_U_LOWER_BOUND = 2, @@ -65,10 +65,12 @@ enum PlPcduParamIds : uint8_t { INJECT_X8_TO_TX_FAILURE = 32, INJECT_TX_TO_MPA_FAILURE = 33, INJECT_MPA_TO_HPA_FAILURE = 34, - INJECT_ALL_ON_FAILURE = 35 + INJECT_ALL_ON_FAILURE = 35, + + DISABLE_ORDER_CHECK_CHANNELS = 40 }; -static std::map PARAM_KEY_MAP = { +static std::map PARAM_KEY_MAP = { {NEG_V_LOWER_BOUND, "negVoltLowerBound"}, {NEG_V_UPPER_BOUND, "negVoltUpperBound"}, {DRO_U_LOWER_BOUND, "droVoltLowerBound"}, {DRO_U_UPPER_BOUND, "droVoltUpperBound"}, {DRO_I_UPPER_BOUND, "droCurrUpperBound"}, {X8_U_LOWER_BOUND, "x8VoltLowerBound"}, diff --git a/mission/payload/plocSpBase.h b/mission/payload/plocSpBase.h index e754c7e8..96de0526 100644 --- a/mission/payload/plocSpBase.h +++ b/mission/payload/plocSpBase.h @@ -104,10 +104,6 @@ class SpTmReader : public SpacePacketReader { */ SpTmReader(const uint8_t* buf, size_t maxSize) : SpacePacketReader(buf, maxSize) {} - ReturnValue_t setData(const uint8_t* buf, size_t maxSize) { - return setReadOnlyData(buf, maxSize); - } - ReturnValue_t checkCrc() const { if (CRC::crc16ccitt(getFullData(), getFullPacketLen()) != 0) { return returnvalue::FAILED; diff --git a/mission/pollingSeqTables.cpp b/mission/pollingSeqTables.cpp index e9adf83b..1b369292 100644 --- a/mission/pollingSeqTables.cpp +++ b/mission/pollingSeqTables.cpp @@ -9,6 +9,8 @@ #include "OBSWConfig.h" #include "eive/definitions.h" +#include "eive/objects.h" +#include "linux/payload/FreshSupvHandler.h" #ifndef RPI_TEST_ADIS16507 #define RPI_TEST_ADIS16507 0 @@ -608,3 +610,25 @@ ReturnValue_t pst::pstTcsAndAcs(FixedTimeslotTaskIF *thisSequence, AcsPstCfg cfg 0); return returnvalue::OK; } +ReturnValue_t pst::pstPayload(FixedTimeslotTaskIF *thisSequence) { + uint32_t length = thisSequence->getPeriodMs(); + + thisSequence->addSlot(objects::CAM_SWITCHER, length * 0, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::PLOC_MPSOC_HANDLER, length * 0, + DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::PLOC_MPSOC_HANDLER, length * 0, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::PLOC_MPSOC_HANDLER, length * 0, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::PLOC_MPSOC_HANDLER, length * 0, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::PLOC_MPSOC_HANDLER, length * 0, DeviceHandlerIF::GET_READ); + + thisSequence->addSlot(objects::PLOC_SUPERVISOR_HANDLER, length * 0, + FreshSupvHandler::OpCode::DEFAULT_OPERATION); + // Two COM TM steps, which might cover telemetry which takes a bit longer to be sent. + thisSequence->addSlot(objects::PLOC_SUPERVISOR_HANDLER, length * 0.1, + FreshSupvHandler::OpCode::PARSE_TM); + thisSequence->addSlot(objects::PLOC_SUPERVISOR_HANDLER, length * 0.2, + FreshSupvHandler::OpCode::PARSE_TM); + static_cast(length); + + return thisSequence->checkSequence(); +} diff --git a/mission/pollingSeqTables.h b/mission/pollingSeqTables.h index 5df3c954..db75de88 100644 --- a/mission/pollingSeqTables.h +++ b/mission/pollingSeqTables.h @@ -63,6 +63,8 @@ ReturnValue_t pstTcsAndAcs(FixedTimeslotTaskIF* thisSequence, AcsPstCfg cfg); ReturnValue_t pstI2c(TmpSchedConfig schedConf, FixedTimeslotTaskIF* thisSequence); +ReturnValue_t pstPayload(FixedTimeslotTaskIF* thisSequence); + /** * Generic test PST * @param thisSequence diff --git a/mission/tmtc/DirectTmSinkIF.h b/mission/tmtc/DirectTmSinkIF.h index ff8ab6fe..546b293e 100644 --- a/mission/tmtc/DirectTmSinkIF.h +++ b/mission/tmtc/DirectTmSinkIF.h @@ -15,6 +15,7 @@ class DirectTmSinkIF { static constexpr ReturnValue_t IS_BUSY = returnvalue::makeCode(CLASS_ID, 0); static constexpr ReturnValue_t PARTIALLY_WRITTEN = returnvalue::makeCode(CLASS_ID, 1); static constexpr ReturnValue_t NO_WRITE_ACTIVE = returnvalue::makeCode(CLASS_ID, 2); + static constexpr ReturnValue_t TIMEOUT = returnvalue::makeCode(CLASS_ID, 3); /** * @brief Implements the functionality to write to a TM sink directly. diff --git a/mission/tmtc/PersistentTmStore.cpp b/mission/tmtc/PersistentTmStore.cpp index 160348cd..0ba690c2 100644 --- a/mission/tmtc/PersistentTmStore.cpp +++ b/mission/tmtc/PersistentTmStore.cpp @@ -137,40 +137,68 @@ ReturnValue_t PersistentTmStore::handleCommandQueue(StorageManagerIF& ipcStore, if (cmdMessage.getMessageType() == messagetypes::TM_STORE) { Command_t cmd = cmdMessage.getCommand(); if (cmd == TmStoreMessage::DELETE_STORE_CONTENT_TIME) { - Clock::getClock_timeval(¤tTv); - store_address_t storeId = TmStoreMessage::getStoreId(&cmdMessage); - auto accessor = ipcStore.getData(storeId); - uint32_t deleteUpToUnixSeconds = 0; - size_t size = accessor.second.size(); - SerializeAdapter::deSerialize(&deleteUpToUnixSeconds, accessor.second.data(), &size, - SerializeIF::Endianness::NETWORK); + result = handleDeletionCmd(ipcStore, cmdMessage); execCmd = cmd; - deleteUpTo(deleteUpToUnixSeconds); } else if (cmd == TmStoreMessage::DOWNLINK_STORE_CONTENT_TIME) { - Clock::getClock_timeval(¤tTv); - store_address_t storeId = TmStoreMessage::getStoreId(&cmdMessage); - auto accessor = ipcStore.getData(storeId); - if (accessor.second.size() < 8) { - return returnvalue::FAILED; - } - uint32_t dumpFromUnixSeconds = 0; - uint32_t dumpUntilUnixSeconds = 0; - size_t size = 8; - SerializeAdapter::deSerialize(&dumpFromUnixSeconds, accessor.second.data(), &size, - SerializeIF::Endianness::NETWORK); - SerializeAdapter::deSerialize(&dumpUntilUnixSeconds, accessor.second.data() + 4, &size, - SerializeIF::Endianness::NETWORK); - result = startDumpFromUpTo(dumpFromUnixSeconds, dumpUntilUnixSeconds); - if (result == BUSY_DUMPING) { - triggerEvent(persTmStore::BUSY_DUMPING_EVENT); - return result; - } + result = handleDumpCmd(ipcStore, cmdMessage); execCmd = cmd; } } return result; } +ReturnValue_t PersistentTmStore::handleDeletionCmd(StorageManagerIF& ipcStore, + CommandMessage& cmdMessage) { + Clock::getClock_timeval(¤tTv); + store_address_t storeId = TmStoreMessage::getStoreId(&cmdMessage); + auto accessor = ipcStore.getData(storeId); + size_t size = accessor.second.size(); + if (size < 4) { + return returnvalue::FAILED; + } + const uint8_t* data = accessor.second.data(); + uint32_t deleteUpToUnixSeconds = 0; + if (size == 4) { + SerializeAdapter::deSerialize(&deleteUpToUnixSeconds, &data, &size, + SerializeIF::Endianness::NETWORK); + deleteUpTo(deleteUpToUnixSeconds); + } else if (size == 8) { + uint32_t deleteFromUnixSeconds = 0; + SerializeAdapter::deSerialize(&deleteFromUnixSeconds, &data, &size, + SerializeIF::Endianness::NETWORK); + SerializeAdapter::deSerialize(&deleteUpToUnixSeconds, &data, &size, + SerializeIF::Endianness::NETWORK); + deleteFromUpTo(deleteFromUnixSeconds, deleteUpToUnixSeconds); + } else { + sif::warning << "PersistentTmStore: Unknown deletion time specification" << std::endl; + return returnvalue::FAILED; + } + return returnvalue::OK; +} + +ReturnValue_t PersistentTmStore::handleDumpCmd(StorageManagerIF& ipcStore, + CommandMessage& cmdMessage) { + Clock::getClock_timeval(¤tTv); + store_address_t storeId = TmStoreMessage::getStoreId(&cmdMessage); + auto accessor = ipcStore.getData(storeId); + if (accessor.second.size() < 8) { + return returnvalue::FAILED; + } + uint32_t dumpFromUnixSeconds = 0; + uint32_t dumpUntilUnixSeconds = 0; + size_t size = 8; + SerializeAdapter::deSerialize(&dumpFromUnixSeconds, accessor.second.data(), &size, + SerializeIF::Endianness::NETWORK); + SerializeAdapter::deSerialize(&dumpUntilUnixSeconds, accessor.second.data() + 4, &size, + SerializeIF::Endianness::NETWORK); + ReturnValue_t result = startDumpFromUpTo(dumpFromUnixSeconds, dumpUntilUnixSeconds); + if (result == BUSY_DUMPING) { + triggerEvent(persTmStore::BUSY_DUMPING_EVENT); + return result; + } + return returnvalue::OK; +} + ReturnValue_t PersistentTmStore::startDumpFrom(uint32_t fromUnixSeconds) { return startDumpFromUpTo(fromUnixSeconds, currentTv.tv_sec); } @@ -257,7 +285,9 @@ bool PersistentTmStore::updateBaseDir() { return true; } -void PersistentTmStore::deleteUpTo(uint32_t unixSeconds) { +void PersistentTmStore::deleteUpTo(uint32_t unixSeconds) { deleteFromUpTo(0, unixSeconds); } + +void PersistentTmStore::deleteFromUpTo(uint32_t startUnixTime, uint32_t endUnixTime) { using namespace std::filesystem; for (auto const& file : directory_iterator(basePath)) { if (file.is_directory() or (activeFile.has_value() and (activeFile.value() == file.path()))) { @@ -270,7 +300,8 @@ void PersistentTmStore::deleteUpTo(uint32_t unixSeconds) { continue; } time_t fileEpoch = timegm(&fileTime); - if (fileEpoch + rolloverDiffSeconds < unixSeconds) { + if (fileEpoch + rolloverDiffSeconds < endUnixTime and + static_cast(fileEpoch) >= startUnixTime) { std::error_code e; std::filesystem::remove(file.path(), e); } diff --git a/mission/tmtc/PersistentTmStore.h b/mission/tmtc/PersistentTmStore.h index e86acaaf..ccd6cbe6 100644 --- a/mission/tmtc/PersistentTmStore.h +++ b/mission/tmtc/PersistentTmStore.h @@ -14,6 +14,7 @@ #include "eive/eventSubsystemIds.h" #include "eive/resultClassIds.h" +#include "fsfw/ipc/CommandMessage.h" enum class RolloverInterval { MINUTELY, HOURLY, DAILY }; @@ -60,6 +61,7 @@ class PersistentTmStore : public TmStoreFrontendSimpleIF, public SystemObject { ReturnValue_t handleCommandQueue(StorageManagerIF& ipcStore, Command_t& execCmd); void deleteUpTo(uint32_t unixSeconds); + void deleteFromUpTo(uint32_t startUnixTime, uint32_t endUnixTime); ReturnValue_t startDumpFrom(uint32_t fromUnixSeconds); ReturnValue_t startDumpFromUpTo(uint32_t fromUnixSeconds, uint32_t upToUnixSeconds); /** @@ -145,6 +147,8 @@ class PersistentTmStore : public TmStoreFrontendSimpleIF, public SystemObject { std::optional extractSuffix(const std::string& pathStr); bool updateBaseDir(); ReturnValue_t assignAndOrCreateMostRecentFile(); + ReturnValue_t handleDeletionCmd(StorageManagerIF& ipcStore, CommandMessage& cmdMessage); + ReturnValue_t handleDumpCmd(StorageManagerIF& ipcStore, CommandMessage& cmdMessage); }; #endif /* MISSION_TMTC_TMSTOREBACKEND_H_ */ diff --git a/mission/tmtc/Service15TmStorage.cpp b/mission/tmtc/Service15TmStorage.cpp index 1c9b8611..efc9f2a6 100644 --- a/mission/tmtc/Service15TmStorage.cpp +++ b/mission/tmtc/Service15TmStorage.cpp @@ -16,8 +16,9 @@ Service15TmStorage::Service15TmStorage(object_id_t objectId, uint16_t apid, ReturnValue_t Service15TmStorage::isValidSubservice(uint8_t subservice) { switch (subservice) { - case (Subservices::DELETE_UP_TO): - case (Subservices::START_BY_TIME_RANGE_RETRIEVAL): { + case (Subservice::DELETE_UP_TO): + case (Subservice::DELETE_BY_TIME_RANGE): + case (Subservice::START_BY_TIME_RANGE_RETRIEVAL): { return OK; } default: { @@ -45,34 +46,55 @@ ReturnValue_t Service15TmStorage::getMessageQueueAndObject(uint8_t subservice, ReturnValue_t Service15TmStorage::prepareCommand(CommandMessage *message, uint8_t subservice, const uint8_t *tcData, size_t tcDataLen, uint32_t *state, object_id_t objectId) { - if (subservice == Subservices::START_BY_TIME_RANGE_RETRIEVAL) { - // TODO: Hardcoded to UNIX timestamps.. Should allow arbitrary timestamp and let receiver - // to time reading and reply handling - if (tcDataLen != 12) { - return INVALID_TC; + switch (subservice) { + case (Subservice::START_BY_TIME_RANGE_RETRIEVAL): { + // TODO: Hardcoded to UNIX timestamps.. Should allow arbitrary timestamp and let receiver + // to time reading and reply handling + if (tcDataLen != 12) { + return INVALID_TC; + } + store_address_t storeId; + ReturnValue_t result = ipcStore->addData(&storeId, tcData + 4, tcDataLen - 4); + if (result != OK) { + return result; + } + // Store timestamps + TmStoreMessage::setDownlinkContentTimeMessage(message, storeId); + return CommandingServiceBase::EXECUTION_COMPLETE; } - store_address_t storeId; - ReturnValue_t result = ipcStore->addData(&storeId, tcData + 4, tcDataLen - 4); - if (result != OK) { - return result; + case (Subservice::DELETE_UP_TO): { + // TODO: Hardcoded to UNIX timestamps.. Should allow arbitrary timestamp and let receiver + // to time reading and reply handling + if (tcDataLen != 8) { + return INVALID_TC; + } + store_address_t storeId; + ReturnValue_t result = ipcStore->addData(&storeId, tcData + 4, tcDataLen - 4); + if (result != OK) { + return result; + } + // Store timestamps + TmStoreMessage::setDeleteContentTimeMessage(message, storeId); + return CommandingServiceBase::EXECUTION_COMPLETE; } - // Store timestamps - TmStoreMessage::setDownlinkContentTimeMessage(message, storeId); - return CommandingServiceBase::EXECUTION_COMPLETE; - } else if (subservice == Subservices::DELETE_UP_TO) { - // TODO: Hardcoded to UNIX timestamps.. Should allow arbitrary timestamp and let receiver - // to time reading and reply handling - if (tcDataLen != 8) { - return INVALID_TC; + case (Subservice::DELETE_BY_TIME_RANGE): { + // TODO: Hardcoded two UNIX timestamps.. Should allow arbitrary timestamp and let receiver + // to time reading and reply handling + if (tcDataLen != 12) { + return INVALID_TC; + } + store_address_t storeId; + ReturnValue_t result = ipcStore->addData(&storeId, tcData + 4, tcDataLen - 4); + if (result != OK) { + return result; + } + // Store timestamps + TmStoreMessage::setDeleteContentTimeMessage(message, storeId); + return CommandingServiceBase::EXECUTION_COMPLETE; } - store_address_t storeId; - ReturnValue_t result = ipcStore->addData(&storeId, tcData + 4, tcDataLen - 4); - if (result != OK) { - return result; + default: { + return CommandingServiceBase::INVALID_SUBSERVICE; } - // Store timestamps - TmStoreMessage::setDeleteContentTimeMessage(message, storeId); - return CommandingServiceBase::EXECUTION_COMPLETE; } return OK; } diff --git a/mission/tmtc/Service15TmStorage.h b/mission/tmtc/Service15TmStorage.h index 33be0634..6da381ee 100644 --- a/mission/tmtc/Service15TmStorage.h +++ b/mission/tmtc/Service15TmStorage.h @@ -5,7 +5,11 @@ class Service15TmStorage : public CommandingServiceBase { public: - enum Subservices : uint8_t { START_BY_TIME_RANGE_RETRIEVAL = 9, DELETE_UP_TO = 11 }; + enum Subservice : uint8_t { + START_BY_TIME_RANGE_RETRIEVAL = 9, + DELETE_UP_TO = 11, + DELETE_BY_TIME_RANGE = 128 + }; explicit Service15TmStorage(object_id_t objectId, uint16_t apid, uint8_t numParallelCommands, uint16_t commandTimeoutSecs = 60, size_t queueDepth = 10); diff --git a/tmtc b/tmtc index 99c6c8bb..098843a7 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 99c6c8bbd0d791d8b17720de481c6142091a54a4 +Subproject commit 098843a74f93a7ec94500bc0fc9faa1abb165508