From 3898e2d66f16cf0753ad523bec2fb2be9fa9a474 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 14 Nov 2023 18:20:52 +0100 Subject: [PATCH] almost there.. I think --- bsp_q7s/objectFactory.cpp | 7 + bsp_q7s/scheduling.cpp | 2 +- linux/payload/CMakeLists.txt | 1 + linux/payload/FreshSupvHandler.cpp | 40 +- linux/payload/FreshSupvHandler.h | 2 - linux/payload/PlocSupervisorHandler.cpp | 2027 +++++++++++++++++++++++ linux/payload/PlocSupervisorHandler.h | 386 +++++ linux/payload/PlocSupvUartMan.cpp | 9 +- linux/payload/PlocSupvUartMan.h | 2 +- linux/payload/plocSupvDefs.h | 3 + mission/pollingSeqTables.cpp | 7 + 11 files changed, 2454 insertions(+), 32 deletions(-) create mode 100644 linux/payload/PlocSupervisorHandler.cpp create mode 100644 linux/payload/PlocSupervisorHandler.h diff --git a/bsp_q7s/objectFactory.cpp b/bsp_q7s/objectFactory.cpp index 258703c9..4a9d3080 100644 --- a/bsp_q7s/objectFactory.cpp +++ b/bsp_q7s/objectFactory.cpp @@ -60,6 +60,7 @@ #include "linux/ipcore/Ptme.h" #include "linux/ipcore/PtmeConfig.h" #include "linux/payload/FreshSupvHandler.h" +#include "linux/payload/PlocSupervisorHandler.h" #include "mission/config/configfile.h" #include "mission/system/acs/AcsBoardFdir.h" #include "mission/system/acs/AcsSubsystem.h" @@ -656,6 +657,12 @@ void ObjectFactory::createPayloadComponents(LinuxLibgpioIF* gpioComIF, PowerSwit auto* supvHandler = new FreshSupvHandler(dhbConf, supervisorCookie, Gpio(gpioIds::ENABLE_SUPV_UART, gpioComIF), pwrSwitch, power::PDU1_CH6_PLOC_12V, *supvHelper); + /* + auto* supvHandler = new PlocSupervisorHandler(objects::PLOC_SUPERVISOR_HANDLER, supervisorCookie, + Gpio(gpioIds::ENABLE_SUPV_UART, gpioComIF), + power::PDU1_CH6_PLOC_12V, *supvHelper); + supvHandler->setPowerSwitcher(&pwrSwitch); + */ supvHandler->connectModeTreeParent(satsystem::payload::SUBSYSTEM); #endif /* OBSW_ADD_PLOC_SUPERVISOR == 1 */ static_cast(consumer); diff --git a/bsp_q7s/scheduling.cpp b/bsp_q7s/scheduling.cpp index 31ccd140..fd99ab3f 100644 --- a/bsp_q7s/scheduling.cpp +++ b/bsp_q7s/scheduling.cpp @@ -384,7 +384,7 @@ void scheduling::initTasks() { #endif /* OBSW_ADD_PLOC_SUPERVISOR */ FixedTimeslotTaskIF* plTask = factory->createFixedTimeslotTask( - "PL_TASK", 25, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.5, missedDeadlineFunc, &RR_SCHEDULING); + "PL_TASK", 25, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.5, missedDeadlineFunc); pst::pstPayload(plTask); #if OBSW_ADD_SCEX_DEVICE == 1 diff --git a/linux/payload/CMakeLists.txt b/linux/payload/CMakeLists.txt index 48fb9d96..2def0752 100644 --- a/linux/payload/CMakeLists.txt +++ b/linux/payload/CMakeLists.txt @@ -3,6 +3,7 @@ target_sources( PUBLIC PlocMemoryDumper.cpp PlocMpsocHandler.cpp FreshSupvHandler.cpp + PlocSupervisorHandler.cpp PlocMpsocSpecialComHelper.cpp plocMpsocHelpers.cpp PlocSupvUartMan.cpp diff --git a/linux/payload/FreshSupvHandler.cpp b/linux/payload/FreshSupvHandler.cpp index bd964540..581dd348 100644 --- a/linux/payload/FreshSupvHandler.cpp +++ b/linux/payload/FreshSupvHandler.cpp @@ -10,6 +10,7 @@ #include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/ipc/QueueFactory.h" #include "fsfw/returnvalues/returnvalue.h" +#include "fsfw/tasks/TaskFactory.h" #include "linux/payload/plocSupvDefs.h" using namespace supv; @@ -33,7 +34,7 @@ FreshSupvHandler::FreshSupvHandler(DhbConfig cfg, CookieIF* comCookie, Gpio uart adcReport(this) { spParams.buf = commandBuffer.data(); spParams.maxSize = commandBuffer.size(); - eventQueue = QueueFactory::instance()->createMessageQueue(EventMessage::EVENT_MESSAGE_SIZE * 5); + eventQueue = QueueFactory::instance()->createMessageQueue(10); } void FreshSupvHandler::performDeviceOperation(uint8_t opCode) { @@ -70,16 +71,9 @@ void FreshSupvHandler::performDeviceOperation(uint8_t opCode) { } } else { if (mode == MODE_NORMAL) { - if (hkRequestCmdInfo.isPending and hkRequestCmdInfo.cmdCountdown.hasTimedOut()) { - // trigger event? might lead to spam... - sif::warning << "FreshSupvHandler: No reply received for HK set request" << std::endl; - hkRequestCmdInfo.isPending = false; - } - // Normal mode handling. Request normal data sets and add them to command map. - if (not hkRequestCmdInfo.isPending) { - hkRequestCmdInfo.cmdCountdown.resetTimer(); - hkRequestCmdInfo.ackExeRecv = false; - hkRequestCmdInfo.ackRecv = false; + auto cmdIter = activeActionCmds.find( + buildActiveCmdKey(Apid::HK, static_cast(tc::HkId::GET_REPORT))); + if (cmdIter == activeActionCmds.end() or not cmdIter->second.isPending) { sendEmptyCmd(Apid::HK, static_cast(tc::HkId::GET_REPORT), true); } } @@ -436,7 +430,7 @@ ReturnValue_t FreshSupvHandler::prepareSelBootImageCmd(const uint8_t* commandDat } void FreshSupvHandler::startTransition(Mode_t newMode, Submode_t newSubmode) { - if (newMode == mode) { + if (newMode == mode or (mode == MODE_ON and newMode == MODE_NORMAL)) { // Can finish immediately. setMode(newMode, newSubmode); return; @@ -453,9 +447,7 @@ void FreshSupvHandler::startTransition(Mode_t newMode, Submode_t newSubmode) { } void FreshSupvHandler::handleTransitionToOn() { - sif::debug << "psupv: trans to on" << std::endl; if (startupState == StartupState::IDLE) { - bootTimeout.resetTimer(); startupState = StartupState::POWER_SWITCHING; switchIF.sendSwitchCommand(switchId, PowerSwitchIF::SWITCH_ON); switchTimeout.resetTimer(); @@ -468,6 +460,7 @@ void FreshSupvHandler::handleTransitionToOn() { 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; @@ -489,8 +482,9 @@ void FreshSupvHandler::handleTransitionToOn() { if (result != returnvalue::OK) { sif::error << "FreshSupvHandler: Setting time command prepration failed" << std::endl; startupState = StartupState::ON; + } else { + startupState = StartupState::WAIT_FOR_TIME_REPLY; } - startupState = StartupState::WAIT_FOR_TIME_REPLY; } if (startupState == StartupState::TIME_WAS_SET) { startupState = StartupState::ON; @@ -498,7 +492,6 @@ void FreshSupvHandler::handleTransitionToOn() { if (startupState == StartupState::ON) { hkSet.setReportingEnabled(true); supv::SUPV_ON = true; - sif::debug << "psupv: going on" << std::endl; transitionActive = false; setMode(targetMode); } @@ -515,7 +508,6 @@ void FreshSupvHandler::handleTransitionToOff() { } if (shutdownState == ShutdownState::POWER_SWITCHING) { if (switchIF.getSwitchState(switchId) == PowerSwitchIF::SWITCH_OFF or modeHelper.isTimedOut()) { - sif::debug << "psupv: going off" << std::endl; supv::SUPV_ON = false; transitionActive = false; setMode(MODE_OFF); @@ -525,7 +517,7 @@ void FreshSupvHandler::handleTransitionToOff() { ReturnValue_t FreshSupvHandler::sendCommand(TcBase& tc, bool replyExpected, uint32_t cmdCountdownMs) { - if (DEBUG_PLOC_SUPV) { + if (supv::DEBUG_PLOC_SUPV) { sif::debug << "PLOC SUPV: SEND PACKET Size " << tc.getFullPacketLen() << " Module APID " << (int)tc.getModuleApid() << " Service ID " << (int)tc.getServiceId() << std::endl; } @@ -557,7 +549,9 @@ ReturnValue_t FreshSupvHandler::initialize() { if (result != returnvalue::OK) { return result; } - return FreshDeviceHandlerBase::initialize(); + result = FreshDeviceHandlerBase::initialize(); + sif::debug << "serial port: " << uartManager.serialPort << std::endl; + return result; } ReturnValue_t FreshSupvHandler::sendEmptyCmd(uint16_t apid, uint8_t serviceId, bool replyExpected) { @@ -812,7 +806,7 @@ ReturnValue_t FreshSupvHandler::parseTmPackets() { } tmReader.setData(receivedData, receivedSize); uint16_t apid = tmReader.getModuleApid(); - if (DEBUG_PLOC_SUPV) { + if (supv::DEBUG_PLOC_SUPV) { handlePacketPrint(); } switch (apid) { @@ -904,7 +898,8 @@ void FreshSupvHandler::handlePacketPrint() { 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 + if (supv::REDUCE_NORMAL_MODE_PRINTOUT and + ack.getRefModuleApid() == (uint8_t)supv::Apid::HK and ack.getRefServiceId() == (uint8_t)supv::tc::HkId::GET_REPORT) { return; } @@ -927,7 +922,8 @@ void FreshSupvHandler::handlePacketPrint() { 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 + if (supv::REDUCE_NORMAL_MODE_PRINTOUT and + exe.getRefModuleApid() == (uint8_t)supv::Apid::HK and exe.getRefServiceId() == (uint8_t)supv::tc::HkId::GET_REPORT) { return; } diff --git a/linux/payload/FreshSupvHandler.h b/linux/payload/FreshSupvHandler.h index 2efd5d9d..0cf56487 100644 --- a/linux/payload/FreshSupvHandler.h +++ b/linux/payload/FreshSupvHandler.h @@ -132,8 +132,6 @@ class FreshSupvHandler : public FreshDeviceHandlerBase { // Map for Action commands. For normal commands, a separate static structure will be used. std::map activeActionCmds; - ActiveCmdInfo hkRequestCmdInfo = ActiveCmdInfo(500); - std::array commandBuffer; SpacePacketCreator creator; supv::TcParams spParams = supv::TcParams(creator); diff --git a/linux/payload/PlocSupervisorHandler.cpp b/linux/payload/PlocSupervisorHandler.cpp new file mode 100644 index 00000000..67ec707f --- /dev/null +++ b/linux/payload/PlocSupervisorHandler.cpp @@ -0,0 +1,2027 @@ +#include "PlocSupervisorHandler.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "OBSWConfig.h" +#include "eive/definitions.h" +#include "fsfw/datapool/PoolReadGuard.h" +#include "fsfw/globalfunctions/CRC.h" +#include "fsfw/ipc/QueueFactory.h" +#include "fsfw/timemanager/Clock.h" + +using namespace supv; +using namespace returnvalue; + +PlocSupervisorHandler::PlocSupervisorHandler(object_id_t objectId, CookieIF* comCookie, + Gpio uartIsolatorSwitch, power::Switch_t powerSwitch, + PlocSupvUartManager& supvHelper) + : DeviceHandlerBase(objectId, supvHelper.getObjectId(), comCookie), + uartIsolatorSwitch(uartIsolatorSwitch), + hkset(this), + bootStatusReport(this), + latchupStatusReport(this), + countersReport(this), + adcReport(this), + powerSwitch(powerSwitch), + uartManager(supvHelper) { + if (comCookie == nullptr) { + sif::error << "PlocSupervisorHandler: Invalid com cookie" << std::endl; + } + spParams.buf = commandBuffer; + spParams.maxSize = sizeof(commandBuffer); + eventQueue = QueueFactory::instance()->createMessageQueue(EventMessage::EVENT_MESSAGE_SIZE * 5); +} + +PlocSupervisorHandler::~PlocSupervisorHandler() {} + +ReturnValue_t PlocSupervisorHandler::initialize() { + ReturnValue_t result = returnvalue::OK; + result = DeviceHandlerBase::initialize(); + if (result != returnvalue::OK) { + return result; + } +#ifdef XIPHOS_Q7S + sdcMan = SdCardManager::instance(); +#endif /* TE0720_1CFA */ + + result = eventSubscription(); + if (result != returnvalue::OK) { + return result; + } + return result; +} + +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)) { + 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; + } + } +} + +ReturnValue_t PlocSupervisorHandler::executeAction(ActionId_t actionId, + MessageQueueId_t commandedBy, + const uint8_t* data, size_t size) { + using namespace supv; + ReturnValue_t result = returnvalue::OK; + + switch (actionId) { + default: + break; + } + + if (uartManager.longerRequestActive()) { + return result::SUPV_HELPER_EXECUTING; + } + + result = acceptExternalDeviceCommands(); + if (result != returnvalue::OK) { + return result; + } + + switch (actionId) { + case PERFORM_UPDATE: { + if (size > config::MAX_PATH_SIZE + config::MAX_FILENAME_SIZE) { + return result::FILENAME_TOO_LONG; + } + shutdownCmdSent = false; + 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: { + shutdownCmdSent = false; + uartManager.initiateUpdateContinuation(); + return EXECUTION_FINISHED; + } + case MEMORY_CHECK_WITH_FILE: { + shutdownCmdSent = false; + 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; + } + return DeviceHandlerBase::executeAction(actionId, commandedBy, data, size); +} + +void PlocSupervisorHandler::doStartUp() { + if (startupState == StartupState::OFF) { + bootTimeout.resetTimer(); + startupState = StartupState::BOOTING; + } + if (startupState == StartupState::BOOTING) { + if (bootTimeout.hasTimedOut()) { + uartIsolatorSwitch.pullHigh(); + uartManager.start(); + if (SET_TIME_DURING_BOOT) { + startupState = StartupState::SET_TIME; + } else { + startupState = StartupState::ON; + } + } + } + if (startupState == StartupState::TIME_WAS_SET) { + startupState = StartupState::ON; + } + if (startupState == StartupState::ON) { + hkset.setReportingEnabled(true); + supv::SUPV_ON = true; + setMode(_MODE_TO_ON); + } +} + +void PlocSupervisorHandler::doShutDown() { + setMode(_MODE_POWER_DOWN); + hkset.setReportingEnabled(false); + hkset.setValidity(false, true); + shutdownCmdSent = false; + packetInBuffer = false; + nextReplyId = supv::NONE; + uartManager.stop(); + uartIsolatorSwitch.pullLow(); + disableAllReplies(); + supv::SUPV_ON = false; + startupState = StartupState::OFF; +} + +ReturnValue_t PlocSupervisorHandler::buildNormalDeviceCommand(DeviceCommandId_t* id) { + if (not normalCommandIsPending) { + *id = GET_HK_REPORT; + normalCommandIsPending = true; + normalCmdCd.resetTimer(); + return buildCommandFromCommand(*id, nullptr, 0); + } + return NOTHING_TO_SEND; +} + +ReturnValue_t PlocSupervisorHandler::buildTransitionDeviceCommand(DeviceCommandId_t* id) { + if (startupState == StartupState::SET_TIME) { + *id = supv::SET_TIME_REF; + startupState = StartupState::WAIT_FOR_TIME_REPLY; + return buildCommandFromCommand(*id, nullptr, 0); + } + return NOTHING_TO_SEND; +} + +ReturnValue_t PlocSupervisorHandler::buildCommandFromCommand(DeviceCommandId_t deviceCommand, + const uint8_t* commandData, + size_t commandDataLen) { + using namespace supv; + ReturnValue_t result = returnvalue::FAILED; + spParams.buf = commandBuffer; + switch (deviceCommand) { + case GET_HK_REPORT: { + prepareEmptyCmd(Apid::HK, static_cast(tc::HkId::GET_REPORT)); + result = returnvalue::OK; + break; + } + case START_MPSOC: { + sif::info << "PLOC SUPV: Starting MPSoC" << std::endl; + prepareEmptyCmd(Apid::BOOT_MAN, static_cast(tc::BootManId::START_MPSOC)); + result = returnvalue::OK; + break; + } + case SHUTDOWN_MPSOC: { + sif::info << "PLOC SUPV: Shutting down MPSoC" << std::endl; + prepareEmptyCmd(Apid::BOOT_MAN, static_cast(tc::BootManId::SHUTDOWN_MPSOC)); + result = returnvalue::OK; + break; + } + case SEL_MPSOC_BOOT_IMAGE: { + prepareSelBootImageCmd(commandData); + result = returnvalue::OK; + break; + } + case RESET_MPSOC: { + sif::info << "PLOC SUPV: Resetting MPSoC" << std::endl; + prepareEmptyCmd(Apid::BOOT_MAN, static_cast(tc::BootManId::RESET_MPSOC)); + result = returnvalue::OK; + break; + } + case SET_TIME_REF: { + result = prepareSetTimeRefCmd(); + break; + } + case SET_BOOT_TIMEOUT: { + prepareSetBootTimeoutCmd(commandData); + result = returnvalue::OK; + break; + } + case SET_MAX_RESTART_TRIES: { + prepareRestartTriesCmd(commandData); + result = returnvalue::OK; + break; + } + case DISABLE_PERIOIC_HK_TRANSMISSION: { + prepareDisableHk(); + result = returnvalue::OK; + break; + } + case GET_BOOT_STATUS_REPORT: { + prepareEmptyCmd(Apid::BOOT_MAN, static_cast(tc::BootManId::GET_BOOT_STATUS_REPORT)); + result = returnvalue::OK; + break; + } + case ENABLE_LATCHUP_ALERT: { + result = prepareLatchupConfigCmd(commandData, deviceCommand); + break; + } + case DISABLE_LATCHUP_ALERT: { + result = prepareLatchupConfigCmd(commandData, deviceCommand); + break; + } + case SET_ALERT_LIMIT: { + result = prepareSetAlertLimitCmd(commandData); + break; + } + case GET_LATCHUP_STATUS_REPORT: { + prepareEmptyCmd(Apid::LATCHUP_MON, static_cast(tc::LatchupMonId::GET_STATUS_REPORT)); + result = returnvalue::OK; + break; + } + case RUN_AUTO_EM_TESTS: { + result = prepareRunAutoEmTest(commandData); + break; + } + case SET_GPIO: { + result = prepareSetGpioCmd(commandData, commandDataLen); + break; + } + case FACTORY_RESET: { + result = prepareFactoryResetCmd(commandData, commandDataLen); + break; + } + case READ_GPIO: { + result = prepareReadGpioCmd(commandData, commandDataLen); + break; + } + case SET_SHUTDOWN_TIMEOUT: { + prepareSetShutdownTimeoutCmd(commandData); + result = returnvalue::OK; + break; + } + case FACTORY_FLASH: { + prepareEmptyCmd(Apid::BOOT_MAN, static_cast(tc::BootManId::FACTORY_FLASH)); + result = returnvalue::OK; + break; + } + case RESET_PL: { + prepareEmptyCmd(Apid::BOOT_MAN, static_cast(tc::BootManId::RESET_PL)); + result = returnvalue::OK; + break; + } + case SET_ADC_ENABLED_CHANNELS: { + prepareSetAdcEnabledChannelsCmd(commandData); + result = returnvalue::OK; + break; + } + case SET_ADC_WINDOW_AND_STRIDE: { + prepareSetAdcWindowAndStrideCmd(commandData); + result = returnvalue::OK; + break; + } + case SET_ADC_THRESHOLD: { + prepareSetAdcThresholdCmd(commandData); + result = returnvalue::OK; + break; + } + case WIPE_MRAM: { + 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; +} + +void PlocSupervisorHandler::fillCommandAndReplyMap() { + // Command only + insertInCommandMap(GET_HK_REPORT); + insertInCommandMap(START_MPSOC); + insertInCommandMap(SHUTDOWN_MPSOC); + insertInCommandMap(SEL_MPSOC_BOOT_IMAGE); + insertInCommandMap(SET_BOOT_TIMEOUT); + insertInCommandMap(SET_MAX_RESTART_TRIES); + insertInCommandMap(RESET_MPSOC); + insertInCommandMap(WIPE_MRAM); + insertInCommandMap(SET_TIME_REF); + insertInCommandMap(DISABLE_PERIOIC_HK_TRANSMISSION); + insertInCommandMap(GET_BOOT_STATUS_REPORT); + insertInCommandMap(ENABLE_LATCHUP_ALERT); + insertInCommandMap(DISABLE_LATCHUP_ALERT); + insertInCommandMap(SET_ALERT_LIMIT); + insertInCommandMap(GET_LATCHUP_STATUS_REPORT); + insertInCommandMap(RUN_AUTO_EM_TESTS); + insertInCommandMap(SET_GPIO); + insertInCommandMap(READ_GPIO); + insertInCommandMap(FACTORY_RESET); + insertInCommandMap(MEMORY_CHECK); + insertInCommandMap(SET_SHUTDOWN_TIMEOUT); + insertInCommandMap(FACTORY_FLASH); + insertInCommandMap(SET_ADC_ENABLED_CHANNELS); + 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); + insertInReplyMap(EXE_REPORT, 0, nullptr, SIZE_EXE_REPORT, false, &executionReportTimeout); + insertInReplyMap(MEMORY_CHECK, 5, nullptr, 0, false); + + // TM replies + 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(COUNTERS_REPORT, 3, &countersReport, SIZE_COUNTERS_REPORT); + insertInReplyMap(ADC_REPORT, 3, &adcReport, SIZE_ADC_REPORT); +} + +ReturnValue_t PlocSupervisorHandler::enableReplyInReplyMap(DeviceCommandMap::iterator command, + uint8_t expectedReplies, + bool useAlternateId, + DeviceCommandId_t alternateReplyID) { + ReturnValue_t result = OK; + + uint8_t enabledReplies = 0; + + switch (command->first) { + case GET_HK_REPORT: { + enabledReplies = 3; + result = DeviceHandlerBase::enableReplyInReplyMap(command, enabledReplies, true, HK_REPORT); + if (result != returnvalue::OK) { + sif::debug << "PlocSupervisorHandler::enableReplyInReplyMap: Reply with id " << HK_REPORT + << " not in replyMap" << std::endl; + } + break; + } + case GET_BOOT_STATUS_REPORT: { + enabledReplies = 3; + result = DeviceHandlerBase::enableReplyInReplyMap(command, enabledReplies, true, + BOOT_STATUS_REPORT); + if (result != returnvalue::OK) { + sif::debug << "PlocSupervisorHandler::enableReplyInReplyMap: Reply with id " + << BOOT_STATUS_REPORT << " not in replyMap" << std::endl; + } + break; + } + case GET_LATCHUP_STATUS_REPORT: { + enabledReplies = 3; + result = + DeviceHandlerBase::enableReplyInReplyMap(command, enabledReplies, true, LATCHUP_REPORT); + if (result != returnvalue::OK) { + sif::debug << "PlocSupervisorHandler::enableReplyInReplyMap: Reply with id " + << LATCHUP_REPORT << " not in replyMap" << std::endl; + } + break; + } + case REQUEST_LOGGING_COUNTERS: { + enabledReplies = 3; + result = + DeviceHandlerBase::enableReplyInReplyMap(command, enabledReplies, true, COUNTERS_REPORT); + if (result != returnvalue::OK) { + sif::debug << "PlocSupervisorHandler::enableReplyInReplyMap: Reply with id " + << COUNTERS_REPORT << " not in replyMap" << std::endl; + } + break; + } + case REQUEST_ADC_REPORT: { + enabledReplies = 3; + result = DeviceHandlerBase::enableReplyInReplyMap(command, enabledReplies, true, ADC_REPORT); + if (result != returnvalue::OK) { + sif::debug << "PlocSupervisorHandler::enableReplyInReplyMap: Reply with id " << ADC_REPORT + << " not in replyMap" << std::endl; + } + break; + } + case FIRST_MRAM_DUMP: { + enabledReplies = 2; // expected replies will be increased in handleMramDumpPacket + result = + DeviceHandlerBase::enableReplyInReplyMap(command, enabledReplies, true, FIRST_MRAM_DUMP); + if (result != returnvalue::OK) { + sif::debug << "PlocSupervisorHandler::enableReplyInReplyMap: Reply with id " + << FIRST_MRAM_DUMP << " not in replyMap" << std::endl; + } + break; + } + case CONSECUTIVE_MRAM_DUMP: { + enabledReplies = 2; // expected replies will be increased in handleMramDumpPacket + result = DeviceHandlerBase::enableReplyInReplyMap(command, enabledReplies, true, + CONSECUTIVE_MRAM_DUMP); + if (result != returnvalue::OK) { + sif::debug << "PlocSupervisorHandler::enableReplyInReplyMap: Reply with id " + << CONSECUTIVE_MRAM_DUMP << " not in replyMap" << std::endl; + } + break; + } + case MEMORY_CHECK: { + enabledReplies = 3; + result = + DeviceHandlerBase::enableReplyInReplyMap(command, enabledReplies, true, MEMORY_CHECK); + if (result != returnvalue::OK) { + sif::debug << "PlocSupervisorHandler::enableReplyInReplyMap: Reply with id " << MEMORY_CHECK + << " not in replyMap" << std::endl; + } + break; + } + case START_MPSOC: + case SHUTDOWN_MPSOC: + case SEL_MPSOC_BOOT_IMAGE: + case SET_BOOT_TIMEOUT: + case SET_MAX_RESTART_TRIES: + case RESET_MPSOC: + case SET_TIME_REF: + case ENABLE_LATCHUP_ALERT: + case DISABLE_LATCHUP_ALERT: + case SET_ALERT_LIMIT: + case SET_ADC_ENABLED_CHANNELS: + case SET_ADC_WINDOW_AND_STRIDE: + case SET_ADC_THRESHOLD: + case RUN_AUTO_EM_TESTS: + case WIPE_MRAM: + case SET_GPIO: + case FACTORY_RESET: + case READ_GPIO: + case DISABLE_PERIOIC_HK_TRANSMISSION: + case SET_SHUTDOWN_TIMEOUT: + case FACTORY_FLASH: + case ENABLE_AUTO_TM: + case DISABLE_AUTO_TM: + case RESET_PL: + enabledReplies = 2; + break; + default: + sif::debug << "PlocSupervisorHandler::enableReplyInReplyMap: Unknown command id" << std::endl; + break; + } + + /** + * Every command causes at least one acknowledgment and one execution report. Therefore both + * replies will be enabled here. + */ + result = DeviceHandlerBase::enableReplyInReplyMap(command, enabledReplies, true, ACK_REPORT); + if (result != returnvalue::OK) { + sif::debug << "PlocSupervisorHandler::enableReplyInReplyMap: Reply with id " << ACK_REPORT + << " not in replyMap" << std::endl; + } + + setExecutionTimeout(command->first); + + result = DeviceHandlerBase::enableReplyInReplyMap(command, enabledReplies, true, EXE_REPORT); + if (result != returnvalue::OK) { + sif::debug << "PlocSupervisorHandler::enableReplyInReplyMap: Reply with id " << EXE_REPORT + << " not in replyMap" << std::endl; + } + + return returnvalue::OK; +} + +ReturnValue_t PlocSupervisorHandler::scanForReply(const uint8_t* start, size_t remainingSize, + DeviceCommandId_t* foundId, size_t* foundLen) { + using namespace supv; + + tmReader.setData(start, remainingSize); + uint16_t apid = tmReader.getModuleApid(); + if (DEBUG_PLOC_SUPV) { + handlePacketPrint(); + } + + switch (apid) { + case (Apid::TMTC_MAN): { + switch (tmReader.getServiceId()) { + case (static_cast(supv::tm::TmtcId::ACK)): + case (static_cast(supv::tm::TmtcId::NAK)): { + *foundLen = tmReader.getFullPacketLen(); + *foundId = ReplyId::ACK_REPORT; + return OK; + } + case (static_cast(supv::tm::TmtcId::EXEC_ACK)): + case (static_cast(supv::tm::TmtcId::EXEC_NAK)): { + *foundLen = tmReader.getFullPacketLen(); + *foundId = EXE_REPORT; + return OK; + } + } + break; + } + 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; + } 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)) { + *foundLen = tmReader.getFullPacketLen(); + *foundId = ReplyId::BOOT_STATUS_REPORT; + return OK; + } + 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)) { + *foundLen = tmReader.getFullPacketLen(); + *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()); + *foundLen = remainingSize; + return INVALID_DATA; +} + +void PlocSupervisorHandler::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(); + 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"; + + } 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(); + 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"; + + } 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; + } + } + sif::debug << "PlocSupervisorHandler: RECV PACKET Size " << tmReader.getFullPacketLen() + << " Module APID " << (int)tmReader.getModuleApid() << " Service ID " + << (int)tmReader.getServiceId() << std::endl; +} +ReturnValue_t PlocSupervisorHandler::interpretDeviceReply(DeviceCommandId_t id, + const uint8_t* packet) { + using namespace supv; + ReturnValue_t result = returnvalue::OK; + + switch (id) { + case ACK_REPORT: { + result = handleAckReport(packet); + break; + } + case (HK_REPORT): { + result = handleHkReport(packet); + break; + } + case (BOOT_STATUS_REPORT): { + 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 = genericHandleTm("ADC", packet, adcReport); +#if OBSW_VERBOSE_LEVEL >= 1 && OBSW_DEBUG_PLOC_SUPERVISOR == 1 + adcReport.printSet(); +#endif + break; + } + case (EXE_REPORT): { + result = handleExecutionReport(packet); + break; + } + case (UPDATE_STATUS_REPORT): { + // TODO: handle status report here + break; + } + default: { + sif::debug << "PlocSupervisorHandler::interpretDeviceReply: Unknown device reply id" + << std::endl; + return DeviceHandlerIF::UNKNOWN_DEVICE_REPLY; + } + } + + return result; +} + +ReturnValue_t PlocSupervisorHandler::initializeLocalDataPool(localpool::DataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) { + 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_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; +} + +void PlocSupervisorHandler::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) { + // Wait for a short period for the uart state machine to adjust + // TaskFactory::delayTask(5); + if (not shutdownCmdSent) { + shutdownCmdSent = true; + result = this->executeAction(supv::SHUTDOWN_MPSOC, NO_COMMANDER, nullptr, 0); + if (result != returnvalue::OK) { + triggerEvent(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; + } +} + +void PlocSupervisorHandler::setExecutionTimeout(DeviceCommandId_t command) { + using namespace supv; + switch (command) { + case FIRST_MRAM_DUMP: + case CONSECUTIVE_MRAM_DUMP: + executionReportTimeout.setTimeout(MRAM_DUMP_EXECUTION_TIMEOUT); + break; + case COPY_ADC_DATA_TO_MRAM: + executionReportTimeout.setTimeout(COPY_ADC_TO_MRAM_TIMEOUT); + break; + default: + executionReportTimeout.setTimeout(EXECUTION_DEFAULT_TIMEOUT); + break; + } +} + +ReturnValue_t PlocSupervisorHandler::verifyPacket(const uint8_t* start, size_t foundLen) { + if (CRC::crc16ccitt(start, foundLen) != 0) { + return result::CRC_FAILURE; + } + return returnvalue::OK; +} + +ReturnValue_t PlocSupervisorHandler::handleAckReport(const uint8_t* data) { + using namespace supv; + ReturnValue_t result = returnvalue::OK; + + if (not tmReader.verifyCrc()) { + sif::error << "PlocSupervisorHandler::handleAckReport: CRC failure" << std::endl; + nextReplyId = supv::NONE; + replyRawReplyIfnotWiretapped(data, supv::SIZE_ACK_REPORT); + triggerEvent(SUPV_CRC_FAILURE_EVENT); + sendFailureReport(supv::ACK_REPORT, result::CRC_FAILURE); + disableAllReplies(); + return returnvalue::OK; + } + AcknowledgmentReport ack(tmReader); + result = ack.parse(); + if (result != returnvalue::OK) { + nextReplyId = supv::NONE; + replyRawReplyIfnotWiretapped(data, supv::SIZE_ACK_REPORT); + triggerEvent(SUPV_CRC_FAILURE_EVENT); + sendFailureReport(supv::ACK_REPORT, result); + disableAllReplies(); + return result; + } + if (tmReader.getServiceId() == static_cast(supv::tm::TmtcId::NAK)) { + DeviceCommandId_t commandId = getPendingCommand(); + if (commandId != DeviceHandlerIF::NO_COMMAND_ID) { + triggerEvent(SUPV_ACK_FAILURE, commandId, static_cast(ack.getStatusCode())); + } + ack.printStatusInformation(); + printAckFailureInfo(ack.getStatusCode(), commandId); + sendFailureReport(supv::ACK_REPORT, result::RECEIVED_ACK_FAILURE); + disableAllReplies(); + nextReplyId = supv::NONE; + result = IGNORE_REPLY_DATA; + } else if (tmReader.getServiceId() == static_cast(supv::tm::TmtcId::ACK)) { + setNextReplyId(); + } + return result; +} + +ReturnValue_t PlocSupervisorHandler::handleExecutionReport(const uint8_t* data) { + using namespace supv; + ReturnValue_t result = returnvalue::OK; + + if (not tmReader.verifyCrc()) { + nextReplyId = supv::NONE; + return result::CRC_FAILURE; + } + ExecutionReport report(tmReader); + result = report.parse(); + if (result != OK) { + nextReplyId = supv::NONE; + return result; + } + if (tmReader.getServiceId() == static_cast(supv::tm::TmtcId::EXEC_ACK)) { + result = handleExecutionSuccessReport(report); + } else if (tmReader.getServiceId() == static_cast(supv::tm::TmtcId::EXEC_NAK)) { + handleExecutionFailureReport(report); + } + commandIsPending = false; + nextReplyId = supv::NONE; + return result; +} + +ReturnValue_t PlocSupervisorHandler::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; + + nextReplyId = supv::EXE_REPORT; + hkset.setValidity(true, true); + +#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 PlocSupervisorHandler::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); + + nextReplyId = supv::EXE_REPORT; + bootStatusReport.setValidity(true, true); + +#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 PlocSupervisorHandler::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); + + nextReplyId = supv::EXE_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 PlocSupervisorHandler::genericHandleTm(const char* contextString, const uint8_t* data, + LocalPoolDataSetBase& set) { + 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); + nextReplyId = supv::EXE_REPORT; + return result; +} + +void PlocSupervisorHandler::setNextReplyId() { + switch (getPendingCommand()) { + case supv::GET_HK_REPORT: + nextReplyId = supv::HK_REPORT; + break; + case supv::GET_BOOT_STATUS_REPORT: + nextReplyId = supv::BOOT_STATUS_REPORT; + break; + case supv::GET_LATCHUP_STATUS_REPORT: + nextReplyId = supv::LATCHUP_REPORT; + break; + case supv::FIRST_MRAM_DUMP: + nextReplyId = supv::FIRST_MRAM_DUMP; + break; + case supv::CONSECUTIVE_MRAM_DUMP: + nextReplyId = supv::CONSECUTIVE_MRAM_DUMP; + break; + case supv::REQUEST_LOGGING_COUNTERS: + nextReplyId = supv::COUNTERS_REPORT; + break; + case supv::REQUEST_ADC_REPORT: + nextReplyId = supv::ADC_REPORT; + break; + default: + /* If no telemetry is expected the next reply is always the execution report */ + nextReplyId = supv::EXE_REPORT; + break; + } +} + +size_t PlocSupervisorHandler::getNextReplyLength(DeviceCommandId_t commandId) { + size_t replyLen = 0; + + if (nextReplyId == supv::NONE) { + return replyLen; + } + + if (nextReplyId == supv::FIRST_MRAM_DUMP || nextReplyId == supv::CONSECUTIVE_MRAM_DUMP) { + /** + * Try to read 20 MRAM packets. If reply is larger, the packets will be read with the + * next doSendRead call. The command will be as long active as the packet with the sequence + * count indicating the last packet has not been received. + */ + replyLen = supv::MAX_PACKET_SIZE * 20; + return replyLen; + } + + DeviceReplyIter iter = deviceReplyMap.find(nextReplyId); + if (iter != deviceReplyMap.end()) { + if ((iter->second.delayCycles == 0 && iter->second.countdown == nullptr) || + (not iter->second.active && iter->second.countdown != nullptr)) { + /* Reply inactive */ + return replyLen; + } + replyLen = iter->second.replyLen; + } else { + sif::debug << "PlocSupervisorHandler::getNextReplyLength: No entry for reply with reply id " + << std::hex << nextReplyId << " in deviceReplyMap" << std::endl; + } + + return replyLen; +} + +void PlocSupervisorHandler::doOffActivity() {} + +void PlocSupervisorHandler::handleDeviceTm(const uint8_t* data, size_t dataSize, + DeviceCommandId_t replyId) { + ReturnValue_t result = returnvalue::OK; + + if (wiretappingMode == RAW) { + /* Data already sent in doGetRead() */ + return; + } + + DeviceReplyMap::iterator iter = deviceReplyMap.find(replyId); + if (iter == deviceReplyMap.end()) { + sif::debug << "PlocSupervisorHandler::handleDeviceTM: Unknown reply id" << std::endl; + return; + } + MessageQueueId_t queueId = iter->second.command->second.sendReplyTo; + + if (queueId == NO_COMMANDER) { + return; + } + + result = actionHelper.reportData(queueId, replyId, data, dataSize); + if (result != returnvalue::OK) { + sif::debug << "PlocSupervisorHandler::handleDeviceTM: Failed to report data" << std::endl; + } +} + +ReturnValue_t PlocSupervisorHandler::prepareEmptyCmd(uint16_t apid, uint8_t serviceId) { + supv::NoPayloadPacket packet(spParams, apid, serviceId); + ReturnValue_t result = packet.buildPacket(); + if (result != returnvalue::OK) { + return result; + } + finishTcPrep(packet); + return returnvalue::OK; +} + +ReturnValue_t PlocSupervisorHandler::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; + } + finishTcPrep(packet); + return returnvalue::OK; +} + +ReturnValue_t PlocSupervisorHandler::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; + } + finishTcPrep(packet); + return returnvalue::OK; +} + +ReturnValue_t PlocSupervisorHandler::prepareDisableHk() { + supv::DisablePeriodicHkTransmission packet(spParams); + ReturnValue_t result = packet.buildPacket(); + if (result != returnvalue::OK) { + return result; + } + finishTcPrep(packet); + return returnvalue::OK; +} + +ReturnValue_t PlocSupervisorHandler::prepareSetBootTimeoutCmd(const uint8_t* commandData) { + 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; + } + finishTcPrep(packet); + return returnvalue::OK; +} + +ReturnValue_t PlocSupervisorHandler::prepareRestartTriesCmd(const uint8_t* commandData) { + uint8_t restartTries = *(commandData); + supv::SetRestartTries packet(spParams); + ReturnValue_t result = packet.buildPacket(restartTries); + if (result != returnvalue::OK) { + return result; + } + finishTcPrep(packet); + return returnvalue::OK; +} + +ReturnValue_t PlocSupervisorHandler::prepareLatchupConfigCmd(const uint8_t* commandData, + DeviceCommandId_t deviceCommand) { + ReturnValue_t result = returnvalue::OK; + 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; + } + finishTcPrep(packet); + break; + } + case (supv::DISABLE_LATCHUP_ALERT): { + supv::LatchupAlert packet(spParams); + result = packet.buildPacket(false, latchupId); + if (result != returnvalue::OK) { + return result; + } + finishTcPrep(packet); + break; + } + default: { + sif::debug << "PlocSupervisorHandler::prepareLatchupConfigCmd: Invalid command id" + << std::endl; + result = returnvalue::FAILED; + break; + } + } + return result; +} + +ReturnValue_t PlocSupervisorHandler::prepareSetAlertLimitCmd(const uint8_t* commandData) { + 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; + } + finishTcPrep(packet); + return returnvalue::OK; +} + +ReturnValue_t PlocSupervisorHandler::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; + } + finishTcPrep(packet); + return returnvalue::OK; +} + +ReturnValue_t PlocSupervisorHandler::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; + } + finishTcPrep(packet); + return returnvalue::OK; +} + +ReturnValue_t PlocSupervisorHandler::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; + } + finishTcPrep(packet); + return returnvalue::OK; +} + +ReturnValue_t PlocSupervisorHandler::prepareRunAutoEmTest(const uint8_t* commandData) { + uint8_t test = *commandData; + if (test != 1 && test != 2) { + return result::INVALID_TEST_PARAM; + } + supv::RunAutoEmTests packet(spParams); + ReturnValue_t result = packet.buildPacket(test); + if (result != returnvalue::OK) { + return result; + } + finishTcPrep(packet); + return returnvalue::OK; +} + +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); + supv::SetGpio packet(spParams); + ReturnValue_t result = packet.buildPacket(port, pin, val); + if (result != returnvalue::OK) { + return result; + } + finishTcPrep(packet); + return returnvalue::OK; +} + +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); + ReturnValue_t result = packet.buildPacket(port, pin); + if (result != returnvalue::OK) { + return result; + } + finishTcPrep(packet); + return returnvalue::OK; +} + +ReturnValue_t PlocSupervisorHandler::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; + } + finishTcPrep(resetCmd); + return returnvalue::OK; +} + +void PlocSupervisorHandler::finishTcPrep(TcBase& tc) { + nextReplyId = supv::ACK_REPORT; + rawPacket = commandBuffer; + rawPacketLen = tc.getFullPacketLen(); + if (DEBUG_PLOC_SUPV) { + sif::debug << "PLOC SUPV: SEND PACKET Size " << tc.getFullPacketLen() << " Module APID " + << (int)tc.getModuleApid() << " Service ID " << (int)tc.getServiceId() << std::endl; + } +} + +ReturnValue_t PlocSupervisorHandler::prepareSetShutdownTimeoutCmd(const uint8_t* commandData) { + 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; + } + finishTcPrep(packet); + return returnvalue::OK; +} + +void PlocSupervisorHandler::disableAllReplies() { + using namespace supv; + DeviceReplyMap::iterator iter; + + /* Disable ack reply */ + iter = deviceReplyMap.find(ACK_REPORT); + if (iter == deviceReplyMap.end()) { + return; + } + DeviceReplyInfo* info = &(iter->second); + if (info == nullptr) { + return; + } + info->delayCycles = 0; + info->command = deviceCommandMap.end(); + + DeviceCommandId_t commandId = getPendingCommand(); + + /* If the command expects a telemetry packet the appropriate tm reply will be disabled here */ + switch (commandId) { + case GET_HK_REPORT: { + disableReply(GET_HK_REPORT); + break; + } + case FIRST_MRAM_DUMP: + case CONSECUTIVE_MRAM_DUMP: { + disableReply(commandId); + break; + } + case REQUEST_ADC_REPORT: { + disableReply(ADC_REPORT); + break; + } + case GET_BOOT_STATUS_REPORT: { + disableReply(BOOT_STATUS_REPORT); + break; + } + case GET_LATCHUP_STATUS_REPORT: { + disableReply(LATCHUP_REPORT); + break; + } + case REQUEST_LOGGING_COUNTERS: { + disableReply(COUNTERS_REPORT); + break; + } + default: { + break; + } + } + + /* We must always disable the execution report reply here */ + disableExeReportReply(); +} + +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; + info->command = deviceCommandMap.end(); +} + +void PlocSupervisorHandler::sendFailureReport(DeviceCommandId_t replyId, ReturnValue_t status) { + DeviceReplyIter iter = deviceReplyMap.find(replyId); + + if (iter == deviceReplyMap.end()) { + sif::debug << "PlocSupervisorHandler::sendFailureReport: Reply not in reply map" << std::endl; + return; + } + + DeviceCommandInfo* info = &(iter->second.command->second); + + if (info == nullptr) { + sif::debug << "PlocSupervisorHandler::sendFailureReport: Reply has no active command" + << std::endl; + return; + } + + if (info->sendReplyTo != NO_COMMANDER) { + actionHelper.finish(false, info->sendReplyTo, iter->first, status); + } + info->isExecuting = false; +} + +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(); + info->active = false; + /* Expected replies is set to one here. The value will set to 0 in replyToReply() */ + info->command->second.expectedReplies = 1; +} + +ReturnValue_t PlocSupervisorHandler::handleMramDumpPacket(DeviceCommandId_t id) { + ReturnValue_t result = returnvalue::FAILED; + + // Prepare packet for downlink + if (packetInBuffer) { + uint16_t packetLen = readSpacePacketLength(spacePacketBuffer); + result = verifyPacket(spacePacketBuffer, ccsds::HEADER_LEN + packetLen + 1); + if (result != returnvalue::OK) { + sif::warning << "PlocSupervisorHandler::handleMramDumpPacket: CRC failure" << std::endl; + return result; + } + result = handleMramDumpFile(id); + if (result != returnvalue::OK) { + DeviceCommandMap::iterator iter = deviceCommandMap.find(id); + if (iter != deviceCommandMap.end()) { + actionHelper.finish(false, iter->second.sendReplyTo, id, result); + } + disableAllReplies(); + nextReplyId = supv::NONE; + return result; + } + packetInBuffer = false; + receivedMramDumpPackets++; + if (expectedMramDumpPackets == receivedMramDumpPackets) { + nextReplyId = supv::EXE_REPORT; + } + increaseExpectedMramReplies(id); + return returnvalue::OK; + } + return result; +} + +void PlocSupervisorHandler::increaseExpectedMramReplies(DeviceCommandId_t id) { + DeviceReplyMap::iterator mramDumpIter = deviceReplyMap.find(id); + DeviceReplyMap::iterator exeReportIter = deviceReplyMap.find(supv::EXE_REPORT); + if (mramDumpIter == deviceReplyMap.end()) { + sif::debug << "PlocSupervisorHandler::increaseExpectedMramReplies: Dump MRAM reply not " + << "in reply map" << std::endl; + return; + } + if (exeReportIter == deviceReplyMap.end()) { + sif::debug << "PlocSupervisorHandler::increaseExpectedMramReplies: Execution report not " + << "in reply map" << std::endl; + return; + } + DeviceReplyInfo* mramReplyInfo = &(mramDumpIter->second); + if (mramReplyInfo == nullptr) { + sif::debug << "PlocSupervisorHandler::increaseExpectedReplies: MRAM reply info nullptr" + << std::endl; + return; + } + DeviceReplyInfo* exeReplyInfo = &(exeReportIter->second); + if (exeReplyInfo == nullptr) { + sif::debug << "PlocSupervisorHandler::increaseExpectedReplies: Execution reply info" + << " nullptr" << std::endl; + return; + } + DeviceCommandInfo* info = &(mramReplyInfo->command->second); + if (info == nullptr) { + sif::debug << "PlocSupervisorHandler::increaseExpectedReplies: Command info nullptr" + << std::endl; + return; + } + uint8_t sequenceFlags = spacePacketBuffer[2] >> 6; + if (sequenceFlags != static_cast(ccsds::SequenceFlags::LAST_SEGMENT) && + (sequenceFlags != static_cast(ccsds::SequenceFlags::UNSEGMENTED))) { + // Command expects at least one MRAM packet more and the execution report + info->expectedReplies = 2; + mramReplyInfo->countdown->resetTimer(); + } else { + // Command expects the execution report + info->expectedReplies = 1; + mramReplyInfo->active = false; + } + exeReplyInfo->countdown->resetTimer(); + return; +} + +ReturnValue_t PlocSupervisorHandler::handleMramDumpFile(DeviceCommandId_t id) { +#ifdef XIPHOS_Q7S + if (not sdcMan->getActiveSdCard()) { + return HasFileSystemIF::FILESYSTEM_INACTIVE; + } +#endif + ReturnValue_t result = returnvalue::OK; + uint16_t packetLen = readSpacePacketLength(spacePacketBuffer); + uint8_t sequenceFlags = readSequenceFlags(spacePacketBuffer); + if (id == supv::FIRST_MRAM_DUMP) { + if (sequenceFlags == static_cast(ccsds::SequenceFlags::FIRST_SEGMENT) || + (sequenceFlags == static_cast(ccsds::SequenceFlags::UNSEGMENTED))) { + result = createMramDumpFile(); + if (result != returnvalue::OK) { + return result; + } + } + } + if (not std::filesystem::exists(activeMramFile)) { + sif::warning << "PlocSupervisorHandler::handleMramDumpFile: MRAM file does not exist" + << std::endl; + return result::MRAM_FILE_NOT_EXISTS; + } + std::ofstream file(activeMramFile, std::ios_base::app | std::ios_base::out); + file.write(reinterpret_cast(spacePacketBuffer + ccsds::HEADER_LEN), packetLen - 1); + file.close(); + return returnvalue::OK; +} + +ReturnValue_t PlocSupervisorHandler::prepareWipeMramCmd(const uint8_t* commandData) { + 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; + } + finishTcPrep(packet); + return returnvalue::OK; +} + +uint16_t PlocSupervisorHandler::readSpacePacketLength(uint8_t* spacePacket) { + return spacePacket[4] << 8 | spacePacket[5]; +} + +uint8_t PlocSupervisorHandler::readSequenceFlags(uint8_t* spacePacket) { + return spacePacketBuffer[2] >> 6; +} + +ReturnValue_t PlocSupervisorHandler::createMramDumpFile() { + ReturnValue_t result = returnvalue::OK; + std::string timeStamp; + result = getTimeStampString(timeStamp); + if (result != returnvalue::OK) { + return result; + } + + std::string filename = "mram-dump--" + timeStamp + ".bin"; + +#ifdef XIPHOS_Q7S + const char* currentMountPrefix = sdcMan->getCurrentMountPrefix(); +#else + const char* currentMountPrefix = "/mnt/sd0"; +#endif /* BOARD_TE0720 == 0 */ + if (currentMountPrefix == nullptr) { + return returnvalue::FAILED; + } + + // Check if path to PLOC directory exists + if (not std::filesystem::exists(std::string(currentMountPrefix) + "/" + supervisorFilePath)) { + sif::warning << "PlocSupervisorHandler::createMramDumpFile: Supervisor path does not exist" + << std::endl; + return result::PATH_DOES_NOT_EXIST; + } + activeMramFile = std::string(currentMountPrefix) + "/" + supervisorFilePath + "/" + filename; + // Create new file + std::ofstream file(activeMramFile, std::ios_base::out); + file.close(); + + return returnvalue::OK; +} + +ReturnValue_t PlocSupervisorHandler::getTimeStampString(std::string& timeStamp) { + Clock::TimeOfDay_t time; + ReturnValue_t result = Clock::getDateAndTime(&time); + if (result != returnvalue::OK) { + sif::warning << "PlocSupervisorHandler::getTimeStampString: Failed to get current time" + << std::endl; + return result::GET_TIME_FAILURE; + } + timeStamp = std::to_string(time.year) + "-" + std::to_string(time.month) + "-" + + std::to_string(time.day) + "--" + std::to_string(time.hour) + "-" + + std::to_string(time.minute) + "-" + std::to_string(time.second); + return returnvalue::OK; +} + +ReturnValue_t PlocSupervisorHandler::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 PlocSupervisorHandler::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; +} + +ReturnValue_t PlocSupervisorHandler::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 PlocSupervisorHandler::handleExecutionSuccessReport(ExecutionReport& report) { + DeviceCommandId_t commandId = getPendingCommand(); + 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 + 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 */ + if (iter != deviceCommandMap.end() and iter->second.sendReplyTo == NO_COMMAND_ID) { + return returnvalue::OK; + } + 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(iter->second.sendReplyTo, 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: { + // We could only allow proper bootup when the time was set successfully, but + // this makes debugging difficult. + + if (startupState == StartupState::WAIT_FOR_TIME_REPLY) { + startupState = StartupState::TIME_WAS_SET; + } + break; + } + default: + break; + } + return returnvalue::OK; +} + +void PlocSupervisorHandler::handleExecutionFailureReport(ExecutionReport& report) { + using namespace supv; + DeviceCommandId_t commandId = getPendingCommand(); + report.printStatusInformation(); + if (commandId != DeviceHandlerIF::NO_COMMAND_ID) { + triggerEvent(SUPV_EXE_FAILURE, commandId, static_cast(report.getStatusCode())); + } + sendFailureReport(EXE_REPORT, result::RECEIVED_EXE_FAILURE); + disableExeReportReply(); +} + +void PlocSupervisorHandler::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 PlocSupervisorHandler::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; + } +} + +ReturnValue_t PlocSupervisorHandler::getSwitches(const uint8_t** switches, + uint8_t* numberOfSwitches) { + if (powerSwitch == power::NO_SWITCH) { + return DeviceHandlerBase::NO_SWITCH; + } + *numberOfSwitches = 1; + *switches = &powerSwitch; + return returnvalue::OK; +} + +uint32_t PlocSupervisorHandler::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) { + 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) { + 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; + } + } + } + return DeviceHandlerBase::checkModeCommand(commandedMode, commandedSubmode, msToReachTheMode); +} diff --git a/linux/payload/PlocSupervisorHandler.h b/linux/payload/PlocSupervisorHandler.h new file mode 100644 index 00000000..14051c22 --- /dev/null +++ b/linux/payload/PlocSupervisorHandler.h @@ -0,0 +1,386 @@ +#ifndef MISSION_DEVICES_PLOCSUPERVISORHANDLER_H_ +#define MISSION_DEVICES_PLOCSUPERVISORHANDLER_H_ + +#include +#include +#include + +#include "OBSWConfig.h" +#include "devices/powerSwitcherList.h" +#include "fsfw/devicehandlers/DeviceHandlerBase.h" +#include "fsfw/timemanager/Countdown.h" +#include "fsfw_hal/linux/gpio/Gpio.h" +#include "fsfw_hal/linux/gpio/LinuxLibgpioIF.h" +#include "fsfw_hal/linux/serial/SerialComIF.h" + +#ifdef XIPHOS_Q7S +#include "bsp_q7s/fs/SdCardManager.h" +#endif + +using supv::ExecutionReport; +using supv::TcBase; + +/** + * @brief This is the device handler for the supervisor of the PLOC which is programmed by + * Thales. + * + * @details The PLOC uses the space packet protocol for communication. On each command the PLOC + * answers with at least one acknowledgment and one execution report. + * Flight manual: + * https://egit.irs.uni-stuttgart.de/redmine/projects/eive-flight-manual/wiki/PLOC_Commands + * ILH ICD: https://eive-cloud.irs.uni-stuttgart.de/index.php/apps/files/?dir=/EIVE_IRS/ + * Arbeitsdaten/08_Used%20Components/PLOC&fileid=940960 + * @author J. Meier + */ +class PlocSupervisorHandler : public DeviceHandlerBase { + public: + PlocSupervisorHandler(object_id_t objectId, CookieIF* comCookie, Gpio uartIsolatorSwitch, + power::Switch_t powerSwitch, PlocSupvUartManager& supvHelper); + virtual ~PlocSupervisorHandler(); + + virtual ReturnValue_t initialize() override; + void performOperationHook() override; + ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy, + const uint8_t* data, size_t size) override; + + protected: + void doStartUp() override; + void doShutDown() override; + ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t* id) override; + ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t* id) override; + void fillCommandAndReplyMap() override; + ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, const uint8_t* commandData, + size_t commandDataLen) override; + ReturnValue_t scanForReply(const uint8_t* start, size_t remainingSize, DeviceCommandId_t* foundId, + size_t* foundLen) override; + ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t* packet) override; + uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) override; + ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) override; + ReturnValue_t enableReplyInReplyMap(DeviceCommandMap::iterator command, + uint8_t expectedReplies = 1, bool useAlternateId = false, + DeviceCommandId_t alternateReplyID = 0) override; + size_t getNextReplyLength(DeviceCommandId_t deviceCommand) override; + // ReturnValue_t doSendReadHook() override; + void doOffActivity() override; + + private: + static const uint16_t APID_MASK = 0x7FF; + static const uint16_t PACKET_SEQUENCE_COUNT_MASK = 0x3FFF; + static const uint8_t EXE_STATUS_OFFSET = 10; + static const uint8_t SIZE_NULL_TERMINATOR = 1; + // 5 s + static const uint32_t EXECUTION_DEFAULT_TIMEOUT = 5000; + // 70 S + 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; + + enum class StartupState : uint8_t { + OFF, + BOOTING, + SET_TIME, + WAIT_FOR_TIME_REPLY, + TIME_WAS_SET, + ON + }; + + static constexpr bool SET_TIME_DURING_BOOT = true; + + StartupState startupState = StartupState::OFF; + + uint8_t commandBuffer[supv::MAX_COMMAND_SIZE]; + SpacePacketCreator creator; + supv::TcParams spParams = supv::TcParams(creator); + + /** + * This variable is used to store the id of the next reply to receive. This is necessary + * because the PLOC sends as reply to each command at least one acknowledgment and execution + * report. + */ + DeviceCommandId_t nextReplyId = supv::NONE; + + SerialComIF* uartComIf = nullptr; + 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::CountersReport countersReport; + supv::AdcReport adcReport; + + const power::Switch_t powerSwitch = power::NO_SWITCH; + supv::TmBase tmReader; + + PlocSupvUartManager& uartManager; + MessageQueueIF* eventQueue = nullptr; + + /** Number of expected replies following the MRAM dump command */ + uint32_t expectedMramDumpPackets = 0; + uint32_t receivedMramDumpPackets = 0; + /** Set to true as soon as a complete space packet is present in the spacePacketBuffer */ + bool packetInBuffer = false; + + /** This buffer is used to concatenate space packets received in two different read steps */ + uint8_t spacePacketBuffer[supv::MAX_PACKET_SIZE]; + +#ifdef XIPHOS_Q7S + SdCardManager* sdcMan = nullptr; +#endif + + // Path to supervisor specific files on SD card + std::string supervisorFilePath = "ploc/supervisor"; + std::string activeMramFile; + + Countdown executionReportTimeout = Countdown(EXECUTION_DEFAULT_TIMEOUT, false); + Countdown acknowledgementReportTimeout = Countdown(ACKNOWLEDGE_DEFAULT_TIMEOUT, false); + // Vorago nees some time to boot properly + 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); + PoolEntry tempSupEntry = PoolEntry(1); + + /** + * @brief Adjusts the timeout of the execution report dependent on command + */ + void setExecutionTimeout(DeviceCommandId_t command); + + void handlePacketPrint(); + + /** + * @brief Handles event messages received from the supervisor helper + */ + void handleEvent(EventMessage* eventMessage); + + ReturnValue_t getSwitches(const uint8_t** switches, uint8_t* numberOfSwitches); + + /** + * @brief This function checks the crc of the received PLOC reply. + * + * @param start Pointer to the first byte of the reply. + * @param foundLen Pointer to the length of the whole packet. + * + * @return returnvalue::OK if CRC is ok, otherwise CRC_FAILURE. + */ + ReturnValue_t verifyPacket(const uint8_t* start, size_t foundLen); + + /** + * @brief This function handles the acknowledgment report. + * + * @param data Pointer to the data holding the acknowledgment report. + * + * @return returnvalue::OK if successful, otherwise an error code. + */ + ReturnValue_t handleAckReport(const uint8_t* data); + + /** + * @brief This function handles the data of a execution report. + * + * @param data Pointer to the received data packet. + * + * @return returnvalue::OK if successful, otherwise an error code. + */ + ReturnValue_t handleExecutionReport(const uint8_t* data); + + /** + * @brief This function handles the housekeeping report. This means verifying the CRC of the + * reply and filling the appropriate dataset. + * + * @param data Pointer to the data buffer holding the housekeeping read report. + * + * @return returnvalue::OK if successful, otherwise an error code. + */ + ReturnValue_t handleHkReport(const uint8_t* data); + + /** + * @brief This function calls the function to check the CRC of the received boot status report + * and fills the associated dataset with the boot status information. + */ + 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 + * next reply after a successful acknowledgment report has been received. This is + * required by the function getNextReplyLength() to identify the length of the next + * reply to read. + */ + void setNextReplyId(); + + /** + * @brief This function handles action message replies in case the telemetry has been + * requested by another object. + * + * @param data Pointer to the telemetry data. + * @param dataSize Size of telemetry in bytes. + * @param replyId Id of the reply. This will be added to the ActionMessage. + */ + void handleDeviceTm(const uint8_t* data, size_t dataSize, DeviceCommandId_t replyId); + + /** + * @brief This function prepares a space packet which does not transport any data in the + * packet data field apart from the crc. + */ + ReturnValue_t prepareEmptyCmd(uint16_t apid, uint8_t serviceId); + + /** + * @brief This function initializes the space packet to select the boot image of the MPSoC. + */ + ReturnValue_t prepareSelBootImageCmd(const uint8_t* commandData); + + ReturnValue_t prepareDisableHk(); + + /** + * @brief This function fills the commandBuffer with the data to update the time of the + * PLOC supervisor. + */ + ReturnValue_t prepareSetTimeRefCmd(); + + /** + * @brief This function fills the commandBuffer with the data to change the boot timeout + * value in the PLOC supervisor. + */ + ReturnValue_t prepareSetBootTimeoutCmd(const uint8_t* commandData); + + ReturnValue_t prepareRestartTriesCmd(const uint8_t* commandData); + + ReturnValue_t prepareFactoryResetCmd(const uint8_t* commandData, size_t len); + + /** + * @brief This function fills the command buffer with the packet to enable or disable the + * watchdogs on the PLOC. + */ + void prepareWatchdogsEnableCmd(const uint8_t* commandData); + + /** + * @brief This function fills the command buffer with the packet to set the watchdog timer + * of one of the three watchdogs (PS, PL, INT). + */ + ReturnValue_t prepareWatchdogsConfigTimeoutCmd(const uint8_t* commandData); + + ReturnValue_t prepareLatchupConfigCmd(const uint8_t* commandData, + DeviceCommandId_t deviceCommand); + ReturnValue_t prepareSetAlertLimitCmd(const uint8_t* commandData); + ReturnValue_t prepareSetAdcEnabledChannelsCmd(const uint8_t* commandData); + ReturnValue_t prepareSetAdcWindowAndStrideCmd(const uint8_t* commandData); + 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, 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. + */ + void finishTcPrep(TcBase& tc); + + /** + * @brief In case an acknowledgment failure reply has been received this function disables + * all previously enabled commands and resets the exepected replies variable of an + * active command. + */ + void disableAllReplies(); + + void disableReply(DeviceCommandId_t replyId); + + /** + * @brief This function sends a failure report if the active action was commanded by an other + * object. + * + * @param replyId The id of the reply which signals a failure. + * @param status A status byte which gives information about the failure type. + */ + void sendFailureReport(DeviceCommandId_t replyId, ReturnValue_t status); + + /** + * @brief This function disables the execution report reply. Within this function also the + * the variable expectedReplies of an active command will be set to 0. + */ + void disableExeReportReply(); + + /** + * @brief This function generates the Service 8 packets for the MRAM dump data. + */ + ReturnValue_t handleMramDumpPacket(DeviceCommandId_t id); + + /** + * @brief With this function the number of expected replies following an MRAM dump command + * will be increased. This is necessary to release the command in case not all replies + * have been received. + */ + void increaseExpectedMramReplies(DeviceCommandId_t id); + + /** + * @brief Writes the data of the MRAM dump to a file. The file will be created when receiving + * the first packet. + */ + ReturnValue_t handleMramDumpFile(DeviceCommandId_t id); + + /** + * @brief Extracts the length field of a spacePacket referenced by the spacePacket pointer. + * + * @param spacePacket Pointer to the buffer holding the space packet. + * + * @return The value stored in the length field of the data field. + */ + uint16_t readSpacePacketLength(uint8_t* spacePacket); + + /** + * @brief Extracts the sequence flags from a space packet referenced by the spacePacket + * pointer. + * + * @param spacePacket Pointer to the buffer holding the space packet. + * + * @return uint8_t where the two least significant bits hold the sequence flags. + */ + uint8_t readSequenceFlags(uint8_t* spacePacket); + + ReturnValue_t createMramDumpFile(); + ReturnValue_t getTimeStampString(std::string& timeStamp); + + ReturnValue_t prepareSetShutdownTimeoutCmd(const uint8_t* commandData); + + 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); + ReturnValue_t eventSubscription(); + + ReturnValue_t handleExecutionSuccessReport(ExecutionReport& report); + void handleExecutionFailureReport(ExecutionReport& report); + + void printAckFailureInfo(uint16_t statusCode, DeviceCommandId_t commandId); + + pwrctrl::EnablePl enablePl = pwrctrl::EnablePl(objects::POWER_CONTROLLER); + ReturnValue_t checkModeCommand(Mode_t commandedMode, Submode_t commandedSubmode, + uint32_t* msToReachTheMode) override; +}; + +#endif /* MISSION_DEVICES_PLOCSUPERVISORHANDLER_H_ */ diff --git a/linux/payload/PlocSupvUartMan.cpp b/linux/payload/PlocSupvUartMan.cpp index b53a5f32..dc5aab27 100644 --- a/linux/payload/PlocSupvUartMan.cpp +++ b/linux/payload/PlocSupvUartMan.cpp @@ -45,12 +45,10 @@ PlocSupvUartManager::PlocSupvUartManager(object_id_t objectId) PlocSupvUartManager::~PlocSupvUartManager() = default; ReturnValue_t PlocSupvUartManager::initializeInterface(CookieIF* cookie) { - sif::debug << "init ploc supv uart IF" << std::endl; auto* uartCookie = dynamic_cast(cookie); if (uartCookie == nullptr) { return FAILED; } - sif::debug << "hello blub" << std::endl; std::string devname = uartCookie->getDeviceFile(); /* Get file descriptor */ serialPort = open(devname.c_str(), O_RDWR); @@ -72,7 +70,7 @@ ReturnValue_t PlocSupvUartManager::initializeInterface(CookieIF* cookie) { tty.c_lflag &= ~(ICANON | ECHO); // Blocking mode, 0.2 seconds timeout - tty.c_cc[VTIME] = 0; + tty.c_cc[VTIME] = 2; tty.c_cc[VMIN] = 0; serial::setBaudrate(tty, uartCookie->getBaudrate()); @@ -82,7 +80,7 @@ ReturnValue_t PlocSupvUartManager::initializeInterface(CookieIF* cookie) { } // Flush received and unread data tcflush(serialPort, TCIOFLUSH); - sif::debug << "ploc supv cfg complete" << std::endl; + sif::debug << "piece of shit port " << serialPort << std::endl; return OK; } @@ -117,7 +115,6 @@ ReturnValue_t PlocSupvUartManager::performOperation(uint8_t operationCode) { lock->lockMutex(); InternalState currentState = state; lock->unlockMutex(); - sif::debug << "supv uart man post-lock" << std::endl; switch (currentState) { case InternalState::SLEEPING: case InternalState::GO_TO_SLEEP: { @@ -143,7 +140,7 @@ ReturnValue_t PlocSupvUartManager::performOperation(uint8_t operationCode) { ReturnValue_t PlocSupvUartManager::handleUartReception() { ReturnValue_t result = OK; ReturnValue_t status = OK; - sif::debug << "handling uart reception" << std::endl; + sif::debug << "reading port " << serialPort << std::endl; ssize_t bytesRead = read(serialPort, reinterpret_cast(recBuf.data()), static_cast(recBuf.size())); if (bytesRead == 0) { diff --git a/linux/payload/PlocSupvUartMan.h b/linux/payload/PlocSupvUartMan.h index e5d01f70..69f938b0 100644 --- a/linux/payload/PlocSupvUartMan.h +++ b/linux/payload/PlocSupvUartMan.h @@ -231,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; diff --git a/linux/payload/plocSupvDefs.h b/linux/payload/plocSupvDefs.h index c7fa3ae7..a87d25a3 100644 --- a/linux/payload/plocSupvDefs.h +++ b/linux/payload/plocSupvDefs.h @@ -17,6 +17,9 @@ namespace supv { +static constexpr bool DEBUG_PLOC_SUPV = true; +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 diff --git a/mission/pollingSeqTables.cpp b/mission/pollingSeqTables.cpp index 8bd0bb86..7c953461 100644 --- a/mission/pollingSeqTables.cpp +++ b/mission/pollingSeqTables.cpp @@ -627,6 +627,13 @@ ReturnValue_t pst::pstPayload(FixedTimeslotTaskIF *thisSequence) { FreshSupvHandler::OpCode::PARSE_TM); thisSequence->addSlot(objects::PLOC_SUPERVISOR_HANDLER, length * 0.2, FreshSupvHandler::OpCode::PARSE_TM); + + /* + thisSequence->addSlot(objects::PLOC_SUPERVISOR_HANDLER, length * 0, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::PLOC_SUPERVISOR_HANDLER, length * 0, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::PLOC_SUPERVISOR_HANDLER, length * 0, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::PLOC_SUPERVISOR_HANDLER, length * 0, DeviceHandlerIF::GET_READ); + */ static_cast(length); return thisSequence->checkSequence();