#include "FreshSupvHandler.h" #include #include #include #include #include "eive/definitions.h" #include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/ipc/QueueFactory.h" #include "fsfw/returnvalues/returnvalue.h" using namespace supv; using namespace returnvalue; std::atomic_bool supv::SUPV_ON = false; FreshSupvHandler::FreshSupvHandler(DhbConfig cfg, CookieIF* comCookie, Gpio uartIsolatorSwitch, PowerSwitchIF& switchIF, power::Switch_t powerSwitch, PlocSupvUartManager& supvHelper) : FreshDeviceHandlerBase(cfg), uartManager(supvHelper), comCookie(comCookie), switchIF(switchIF), switchId(powerSwitch), uartIsolatorSwitch(uartIsolatorSwitch), hkSet(this), bootStatusReport(this), latchupStatusReport(this), countersReport(this), adcReport(this) { eventQueue = QueueFactory::instance()->createMessageQueue(EventMessage::EVENT_MESSAGE_SIZE * 5); } void FreshSupvHandler::performDeviceOperation(uint8_t opCode) { if (not transitionActive and mode == MODE_OFF) { // Nothing to do for now. return; } if (opCode == OpCode::DEFAULT_OPERATION) { EventMessage event; for (ReturnValue_t result = eventQueue->receiveMessage(&event); result == returnvalue::OK; result = eventQueue->receiveMessage(&event)) { switch (event.getMessageId()) { case EventMessage::EVENT_MESSAGE: handleEvent(&event); break; default: sif::debug << "PlocSupervisorHandler::performOperationHook: Did not subscribe to this event" << " message" << std::endl; break; } } if (transitionActive) { if (targetMode == MODE_ON or targetMode == MODE_NORMAL) { handleTransitionToOn(); } else if (targetMode == MODE_OFF) { handleTransitionToOff(); } else { // This should never happen. sif::error << "FreshSupvHandler: Invalid transition mode: " << targetMode << std::endl; targetMode = MODE_OFF; targetSubmode = 0; handleTransitionToOff(); } } else { 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; sendEmptyCmd(Apid::HK, static_cast(tc::HkId::GET_REPORT)); } } } } else if (opCode == OpCode::HANDLE_ACTIVE_CMDS) { std::vector cmdsToRemove; for (auto& activeCmd : activeActionCmds) { if (activeCmd.second.cmdCountdown.hasTimedOut()) { if (activeCmd.second.commandedBy != MessageQueueIF::NO_QUEUE) { actionHelper.finish(false, activeCmd.second.commandedBy, activeCmd.first, DeviceHandlerIF::TIMEOUT); } activeCmd.second.isPending = false; } } parseTmPackets(); } } ReturnValue_t FreshSupvHandler::handleCommandMessage(CommandMessage* message) { // No custom messages. return returnvalue::FAILED; } LocalPoolDataSetBase* FreshSupvHandler::getDataSetHandle(sid_t sid) { if (sid == hkSet.getSid()) { return &hkSet; } else if (sid == bootStatusReport.getSid()) { return &bootStatusReport; } else if (sid == latchupStatusReport.getSid()) { return &latchupStatusReport; } else if (sid == countersReport.getSid()) { return &countersReport; } else if (sid == adcReport.getSid()) { return &adcReport; } return nullptr; } ReturnValue_t FreshSupvHandler::initializeLocalDataPool(localpool::DataPool& localDataPoolMap, LocalDataPoolManager& poolManager) { // TODO: Copy code from god handler here. localDataPoolMap.emplace(supv::NUM_TMS, new PoolEntry({0})); localDataPoolMap.emplace(supv::TEMP_PS, new PoolEntry({0})); localDataPoolMap.emplace(supv::TEMP_PL, new PoolEntry({0})); localDataPoolMap.emplace(supv::HK_SOC_STATE, new PoolEntry({0})); localDataPoolMap.emplace(supv::NVM0_1_STATE, new PoolEntry({0})); localDataPoolMap.emplace(supv::NVM3_STATE, new PoolEntry({0})); localDataPoolMap.emplace(supv::MISSION_IO_STATE, new PoolEntry({0})); localDataPoolMap.emplace(supv::FMC_STATE, &fmcStateEntry); localDataPoolMap.emplace(supv::NUM_TCS, new PoolEntry({0})); localDataPoolMap.emplace(supv::TEMP_SUP, &tempSupEntry); localDataPoolMap.emplace(supv::UPTIME, new PoolEntry({0})); localDataPoolMap.emplace(supv::CPULOAD, new PoolEntry({0})); localDataPoolMap.emplace(supv::AVAILABLEHEAP, new PoolEntry({0})); localDataPoolMap.emplace(supv::BR_SOC_STATE, new PoolEntry({0})); localDataPoolMap.emplace(supv::POWER_CYCLES, new PoolEntry({0})); localDataPoolMap.emplace(supv::BOOT_AFTER_MS, new PoolEntry({0})); localDataPoolMap.emplace(supv::BOOT_TIMEOUT_POOL_VAR_MS, new PoolEntry({0})); localDataPoolMap.emplace(supv::ACTIVE_NVM, new PoolEntry({0})); localDataPoolMap.emplace(supv::BP0_STATE, new PoolEntry({0})); localDataPoolMap.emplace(supv::BP1_STATE, new PoolEntry({0})); localDataPoolMap.emplace(supv::BP2_STATE, new PoolEntry({0})); localDataPoolMap.emplace(supv::BOOT_STATE, &bootStateEntry); localDataPoolMap.emplace(supv::BOOT_CYCLES, &bootCyclesEntry); localDataPoolMap.emplace(supv::LATCHUP_ID, new PoolEntry({0})); localDataPoolMap.emplace(supv::CNT0, new PoolEntry({0})); localDataPoolMap.emplace(supv::CNT1, new PoolEntry({0})); localDataPoolMap.emplace(supv::CNT2, new PoolEntry({0})); localDataPoolMap.emplace(supv::CNT3, new PoolEntry({0})); localDataPoolMap.emplace(supv::CNT4, new PoolEntry({0})); localDataPoolMap.emplace(supv::CNT5, new PoolEntry({0})); localDataPoolMap.emplace(supv::CNT6, new PoolEntry({0})); localDataPoolMap.emplace(supv::LATCHUP_RPT_TIME_MSEC, new PoolEntry({0})); localDataPoolMap.emplace(supv::LATCHUP_RPT_TIME_SEC, new PoolEntry({0})); localDataPoolMap.emplace(supv::LATCHUP_RPT_TIME_MIN, new PoolEntry({0})); localDataPoolMap.emplace(supv::LATCHUP_RPT_TIME_HOUR, new PoolEntry({0})); localDataPoolMap.emplace(supv::LATCHUP_RPT_TIME_DAY, new PoolEntry({0})); localDataPoolMap.emplace(supv::LATCHUP_RPT_TIME_MON, new PoolEntry({0})); localDataPoolMap.emplace(supv::LATCHUP_RPT_TIME_YEAR, new PoolEntry({0})); localDataPoolMap.emplace(supv::LATCHUP_RPT_IS_SET, new PoolEntry({0})); localDataPoolMap.emplace(supv::SIGNATURE, new PoolEntry()); localDataPoolMap.emplace(supv::LATCHUP_HAPPENED_CNTS, &latchupCounters); localDataPoolMap.emplace(supv::ADC_DEVIATION_TRIGGERS_CNT, new PoolEntry({0})); localDataPoolMap.emplace(supv::TC_RECEIVED_CNT, new PoolEntry({0})); localDataPoolMap.emplace(supv::TM_AVAILABLE_CNT, new PoolEntry({0})); localDataPoolMap.emplace(supv::SUPERVISOR_BOOTS, new PoolEntry({0})); localDataPoolMap.emplace(supv::MPSOC_BOOTS, new PoolEntry({0})); localDataPoolMap.emplace(supv::MPSOC_BOOT_FAILED_ATTEMPTS, new PoolEntry({0})); localDataPoolMap.emplace(supv::MPSOC_POWER_UP, new PoolEntry({0})); localDataPoolMap.emplace(supv::MPSOC_UPDATES, new PoolEntry({0})); localDataPoolMap.emplace(supv::MPSOC_HEARTBEAT_RESETS, new PoolEntry({0})); localDataPoolMap.emplace(supv::CPU_WDT_RESETS, new PoolEntry({0})); localDataPoolMap.emplace(supv::PS_HEARTBEATS_LOST, new PoolEntry({0})); localDataPoolMap.emplace(supv::PL_HEARTBEATS_LOST, new PoolEntry({0})); localDataPoolMap.emplace(supv::EB_TASK_LOST, new PoolEntry({0})); localDataPoolMap.emplace(supv::BM_TASK_LOST, new PoolEntry({0})); localDataPoolMap.emplace(supv::LM_TASK_LOST, new PoolEntry({0})); localDataPoolMap.emplace(supv::AM_TASK_LOST, new PoolEntry({0})); localDataPoolMap.emplace(supv::TCTMM_TASK_LOST, new PoolEntry({0})); localDataPoolMap.emplace(supv::MM_TASK_LOST, new PoolEntry({0})); localDataPoolMap.emplace(supv::HK_TASK_LOST, new PoolEntry({0})); localDataPoolMap.emplace(supv::DL_TASK_LOST, new PoolEntry({0})); localDataPoolMap.emplace(supv::RWS_TASKS_LOST, new PoolEntry(3)); localDataPoolMap.emplace(supv::ADC_RAW, &adcRawEntry); localDataPoolMap.emplace(supv::ADC_ENG, &adcEngEntry); poolManager.subscribeForRegularPeriodicPacket( subdp::RegularHkPeriodicParams(hkSet.getSid(), false, 10.0)); return returnvalue::OK; } ReturnValue_t FreshSupvHandler::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy, const uint8_t* data, size_t size) { // TODO: Handle all commands here. Need to add them to some command map. Send command immediately // then. using namespace supv; ReturnValue_t result; if (uartManager.longerRequestActive()) { return result::SUPV_HELPER_EXECUTING; } switch (actionId) { case PERFORM_UPDATE: { if (size > config::MAX_PATH_SIZE + config::MAX_FILENAME_SIZE) { return result::FILENAME_TOO_LONG; } UpdateParams params; result = extractUpdateCommand(data, size, params); if (result != returnvalue::OK) { return result; } result = uartManager.performUpdate(params); if (result != returnvalue::OK) { return result; } return EXECUTION_FINISHED; } case CONTINUE_UPDATE: { uartManager.initiateUpdateContinuation(); return EXECUTION_FINISHED; } case MEMORY_CHECK_WITH_FILE: { UpdateParams params; result = extractBaseParams(&data, size, params); if (result != returnvalue::OK) { return result; } if (not std::filesystem::exists(params.file)) { return HasFileSystemIF::FILE_DOES_NOT_EXIST; } uartManager.performMemCheck(params.file, params.memId, params.startAddr); return EXECUTION_FINISHED; } default: break; } if (isCommandAlreadyActive(actionId)) { return HasActionsIF::IS_BUSY; } spParams.buf = commandBuffer.data(); switch (actionId) { case GET_HK_REPORT: { sendEmptyCmd(Apid::HK, static_cast(tc::HkId::GET_REPORT)); result = returnvalue::OK; break; } case START_MPSOC: { sif::info << "PLOC SUPV: Starting MPSoC" << std::endl; sendEmptyCmd(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; sendEmptyCmd(Apid::BOOT_MAN, static_cast(tc::BootManId::SHUTDOWN_MPSOC)); result = returnvalue::OK; break; } case SEL_MPSOC_BOOT_IMAGE: { prepareSelBootImageCmd(data); result = returnvalue::OK; break; } case RESET_MPSOC: { sif::info << "PLOC SUPV: Resetting MPSoC" << std::endl; sendEmptyCmd(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(data, size); result = returnvalue::OK; break; } case SET_MAX_RESTART_TRIES: { prepareRestartTriesCmd(data, size); result = returnvalue::OK; break; } case DISABLE_PERIOIC_HK_TRANSMISSION: { prepareDisableHk(); result = returnvalue::OK; break; } case GET_BOOT_STATUS_REPORT: { sendEmptyCmd(Apid::BOOT_MAN, static_cast(tc::BootManId::GET_BOOT_STATUS_REPORT)); result = returnvalue::OK; break; } case ENABLE_LATCHUP_ALERT: { result = prepareLatchupConfigCmd(data, actionId, size); break; } case DISABLE_LATCHUP_ALERT: { result = prepareLatchupConfigCmd(data, actionId, size); break; } case SET_ALERT_LIMIT: { result = prepareSetAlertLimitCmd(data, size); break; } case GET_LATCHUP_STATUS_REPORT: { sendEmptyCmd(Apid::LATCHUP_MON, static_cast(tc::LatchupMonId::GET_STATUS_REPORT)); result = returnvalue::OK; break; } case SET_GPIO: { result = prepareSetGpioCmd(data, size); break; } case FACTORY_RESET: { result = prepareFactoryResetCmd(data, size); break; } case READ_GPIO: { result = prepareReadGpioCmd(data, size); break; } case SET_SHUTDOWN_TIMEOUT: { prepareSetShutdownTimeoutCmd(data, size); result = returnvalue::OK; break; } case FACTORY_FLASH: { sendEmptyCmd(Apid::BOOT_MAN, static_cast(tc::BootManId::FACTORY_FLASH)); result = returnvalue::OK; break; } case RESET_PL: { sendEmptyCmd(Apid::BOOT_MAN, static_cast(tc::BootManId::RESET_PL)); result = returnvalue::OK; break; } case SET_ADC_ENABLED_CHANNELS: { prepareSetAdcEnabledChannelsCmd(data); result = returnvalue::OK; break; } case SET_ADC_WINDOW_AND_STRIDE: { prepareSetAdcWindowAndStrideCmd(data); result = returnvalue::OK; break; } case SET_ADC_THRESHOLD: { prepareSetAdcThresholdCmd(data); result = returnvalue::OK; break; } case WIPE_MRAM: { result = prepareWipeMramCmd(data, size); break; } case REQUEST_ADC_REPORT: { sendEmptyCmd(Apid::ADC_MON, static_cast(tc::AdcMonId::REQUEST_ADC_SAMPLE)); result = returnvalue::OK; break; } case REQUEST_LOGGING_COUNTERS: { sendEmptyCmd(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; } return result; } ReturnValue_t FreshSupvHandler::prepareSetTimeRefCmd() { Clock::TimeOfDay_t time; ReturnValue_t result = Clock::getDateAndTime(&time); if (result != returnvalue::OK) { sif::warning << "PlocSupervisorHandler::prepareSetTimeRefCmd: Failed to get current time" << std::endl; return result::GET_TIME_FAILURE; } supv::SetTimeRef packet(spParams); result = packet.buildPacket(&time); if (result != returnvalue::OK) { return result; } sendCommand(packet); return returnvalue::OK; } ReturnValue_t FreshSupvHandler::checkModeCommand(Mode_t commandedMode, Submode_t commandedSubmode, uint32_t* msToReachTheMode) { if (commandedMode != MODE_OFF) { PoolReadGuard pg(&enablePl); if (pg.getReadResult() == returnvalue::OK) { if (enablePl.plUseAllowed.isValid() and not enablePl.plUseAllowed.value) { return NON_OP_STATE_OF_CHARGE; } } } if (commandedMode != HasModesIF::MODE_OFF and commandedMode != HasModesIF::MODE_ON and commandedMode != MODE_NORMAL) { return returnvalue::FAILED; } if (commandedMode != mode and msToReachTheMode != nullptr) { if (commandedMode == MODE_OFF) { *msToReachTheMode = supv::MAX_TRANSITION_TIME_TO_OFF_MS; } else { *msToReachTheMode = supv::MAX_TRANSITION_TIME_TO_ON_MS; } } return returnvalue::OK; } ReturnValue_t FreshSupvHandler::prepareSelBootImageCmd(const uint8_t* commandData) { supv::MPSoCBootSelect packet(spParams); ReturnValue_t result = packet.buildPacket(commandData[0], commandData[1], commandData[2], commandData[3]); if (result != returnvalue::OK) { return result; } sendCommand(packet); return returnvalue::OK; } void FreshSupvHandler::startTransition(Mode_t newMode, Submode_t newSubmode) { if (newMode == mode) { // Can finish immediately. setMode(newMode, newSubmode); return; } // Transition for both OFF to ON/NORMAL and ON/NORMAL to OFF require small state machine. transitionActive = true; targetMode = newMode; targetSubmode = newSubmode; if (targetMode == MODE_ON or targetMode == MODE_NORMAL) { startupState = StartupState::IDLE; } else if (targetMode == MODE_OFF) { shutdownState = ShutdownState::IDLE; } } void FreshSupvHandler::handleTransitionToOn() { if (startupState == StartupState::IDLE) { bootTimeout.resetTimer(); startupState = StartupState::POWER_SWITCHING; switchIF.sendSwitchCommand(switchId, PowerSwitchIF::SWITCH_ON); } else { if (modeHelper.isTimedOut()) { targetMode = MODE_OFF; shutdownState = ShutdownState::IDLE; handleTransitionToOff(); return; } } if (startupState == StartupState::POWER_SWITCHING) { if (switchIF.getSwitchState(switchId) == PowerSwitchIF::SWITCH_ON) { startupState = StartupState::BOOTING; } } if (startupState == StartupState::BOOTING) { if (bootTimeout.hasTimedOut()) { uartIsolatorSwitch.pullHigh(); uartManager.start(); if (SET_TIME_DURING_BOOT) { // TODO: Send command ,add command to command map. 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(targetMode); } } void FreshSupvHandler::handleTransitionToOff() { if (shutdownState == ShutdownState::IDLE) { hkSet.setReportingEnabled(false); hkSet.setValidity(false, true); uartManager.stop(); uartIsolatorSwitch.pullLow(); switchIF.sendSwitchCommand(switchId, PowerSwitchIF::SWITCH_OFF); shutdownState = ShutdownState::POWER_SWITCHING; } if (shutdownState == ShutdownState::POWER_SWITCHING) { if (switchIF.getSwitchState(switchId) == PowerSwitchIF::SWITCH_OFF or modeHelper.isTimedOut()) { supv::SUPV_ON = false; setMode(MODE_OFF); } } } ReturnValue_t FreshSupvHandler::sendCommand(TcBase& tc) { 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; } return uartManager.sendMessage(comCookie, tc.getFullPacket(), tc.getFullPacketLen()); } ReturnValue_t FreshSupvHandler::initialize() { uartManager.initializeInterface(comCookie); ReturnValue_t result = eventSubscription(); if (result != returnvalue::OK) { return result; } return FreshDeviceHandlerBase::initialize(); } ReturnValue_t FreshSupvHandler::sendEmptyCmd(uint16_t apid, uint8_t serviceId) { supv::NoPayloadPacket packet(spParams, apid, serviceId); ReturnValue_t result = packet.buildPacket(); if (result != returnvalue::OK) { return result; } sendCommand(packet); return returnvalue::OK; } ReturnValue_t FreshSupvHandler::prepareSetBootTimeoutCmd(const uint8_t* commandData, size_t cmdDataLen) { if (cmdDataLen < 4) { return HasActionsIF::INVALID_PARAMETERS; } supv::SetBootTimeout packet(spParams); uint32_t timeout = *(commandData) << 24 | *(commandData + 1) << 16 | *(commandData + 2) << 8 | *(commandData + 3); ReturnValue_t result = packet.buildPacket(timeout); if (result != returnvalue::OK) { return result; } sendCommand(packet); return returnvalue::OK; } ReturnValue_t FreshSupvHandler::prepareRestartTriesCmd(const uint8_t* commandData, size_t cmdDataLen) { if (cmdDataLen < 1) { return HasActionsIF::INVALID_PARAMETERS; } uint8_t restartTries = *(commandData); supv::SetRestartTries packet(spParams); ReturnValue_t result = packet.buildPacket(restartTries); if (result != returnvalue::OK) { return result; } sendCommand(packet); return returnvalue::OK; } ReturnValue_t FreshSupvHandler::prepareDisableHk() { supv::DisablePeriodicHkTransmission packet(spParams); ReturnValue_t result = packet.buildPacket(); if (result != returnvalue::OK) { return result; } sendCommand(packet); return returnvalue::OK; } ReturnValue_t FreshSupvHandler::prepareLatchupConfigCmd(const uint8_t* commandData, DeviceCommandId_t deviceCommand, size_t cmdDataLen) { ReturnValue_t result = returnvalue::OK; if (cmdDataLen < 1) { return HasActionsIF::INVALID_PARAMETERS; } uint8_t latchupId = *commandData; if (latchupId > 6) { return result::INVALID_LATCHUP_ID; } switch (deviceCommand) { case (supv::ENABLE_LATCHUP_ALERT): { supv::LatchupAlert packet(spParams); result = packet.buildPacket(true, latchupId); if (result != returnvalue::OK) { return result; } sendCommand(packet); break; } case (supv::DISABLE_LATCHUP_ALERT): { supv::LatchupAlert packet(spParams); result = packet.buildPacket(false, latchupId); if (result != returnvalue::OK) { return result; } sendCommand(packet); break; } default: { sif::debug << "PlocSupervisorHandler::prepareLatchupConfigCmd: Invalid command id" << std::endl; result = returnvalue::FAILED; break; } } return result; } ReturnValue_t FreshSupvHandler::prepareSetAlertLimitCmd(const uint8_t* commandData, size_t cmdDataLen) { if (cmdDataLen < 5) { return HasActionsIF::INVALID_PARAMETERS; } uint8_t offset = 0; uint8_t latchupId = *commandData; offset += 1; uint32_t dutycycle = *(commandData + offset) << 24 | *(commandData + offset + 1) << 16 | *(commandData + offset + 2) << 8 | *(commandData + offset + 3); if (latchupId > 6) { return result::INVALID_LATCHUP_ID; } supv::SetAlertlimit packet(spParams); ReturnValue_t result = packet.buildPacket(latchupId, dutycycle); if (result != returnvalue::OK) { return result; } sendCommand(packet); return returnvalue::OK; } ReturnValue_t FreshSupvHandler::prepareSetShutdownTimeoutCmd(const uint8_t* commandData, size_t cmdDataLen) { if (cmdDataLen < 4) { return HasActionsIF::INVALID_PARAMETERS; } uint32_t timeout = 0; ReturnValue_t result = returnvalue::OK; size_t size = sizeof(timeout); result = SerializeAdapter::deSerialize(&timeout, &commandData, &size, SerializeIF::Endianness::BIG); if (result != returnvalue::OK) { sif::warning << "PlocSupervisorHandler::prepareSetShutdownTimeoutCmd: Failed to deserialize timeout" << std::endl; return result; } supv::SetShutdownTimeout packet(spParams); result = packet.buildPacket(timeout); if (result != returnvalue::OK) { return result; } sendCommand(packet); return returnvalue::OK; } ReturnValue_t FreshSupvHandler::prepareSetGpioCmd(const uint8_t* commandData, size_t commandDataLen) { if (commandDataLen < 3) { return HasActionsIF::INVALID_PARAMETERS; } uint8_t port = *commandData; uint8_t pin = *(commandData + 1); uint8_t val = *(commandData + 2); supv::SetGpio packet(spParams); ReturnValue_t result = packet.buildPacket(port, pin, val); if (result != returnvalue::OK) { return result; } sendCommand(packet); return returnvalue::OK; } ReturnValue_t FreshSupvHandler::prepareReadGpioCmd(const uint8_t* commandData, size_t commandDataLen) { if (commandDataLen < 2) { return HasActionsIF::INVALID_PARAMETERS; } uint8_t port = *commandData; uint8_t pin = *(commandData + 1); supv::ReadGpio packet(spParams); ReturnValue_t result = packet.buildPacket(port, pin); if (result != returnvalue::OK) { return result; } sendCommand(packet); return returnvalue::OK; } ReturnValue_t FreshSupvHandler::prepareFactoryResetCmd(const uint8_t* commandData, size_t len) { FactoryReset resetCmd(spParams); if (len < 1) { return HasActionsIF::INVALID_PARAMETERS; } ReturnValue_t result = resetCmd.buildPacket(commandData[0]); if (result != returnvalue::OK) { return result; } sendCommand(resetCmd); return returnvalue::OK; } ReturnValue_t FreshSupvHandler::prepareSetAdcEnabledChannelsCmd(const uint8_t* commandData) { uint16_t ch = *(commandData) << 8 | *(commandData + 1); supv::SetAdcEnabledChannels packet(spParams); ReturnValue_t result = packet.buildPacket(ch); if (result != returnvalue::OK) { return result; } sendCommand(packet); return returnvalue::OK; } ReturnValue_t FreshSupvHandler::prepareSetAdcWindowAndStrideCmd(const uint8_t* commandData) { uint8_t offset = 0; uint16_t windowSize = *(commandData + offset) << 8 | *(commandData + offset + 1); offset += 2; uint16_t stridingStepSize = *(commandData + offset) << 8 | *(commandData + offset + 1); supv::SetAdcWindowAndStride packet(spParams); ReturnValue_t result = packet.buildPacket(windowSize, stridingStepSize); if (result != returnvalue::OK) { return result; } sendCommand(packet); return returnvalue::OK; } ReturnValue_t FreshSupvHandler::prepareSetAdcThresholdCmd(const uint8_t* commandData) { uint32_t threshold = *(commandData) << 24 | *(commandData + 1) << 16 | *(commandData + 2) << 8 | *(commandData + 3); supv::SetAdcThreshold packet(spParams); ReturnValue_t result = packet.buildPacket(threshold); if (result != returnvalue::OK) { return result; } sendCommand(packet); return returnvalue::OK; } ReturnValue_t FreshSupvHandler::prepareWipeMramCmd(const uint8_t* commandData, size_t cmdDataLen) { if (cmdDataLen < 8) { return HasActionsIF::INVALID_PARAMETERS; } uint32_t start = 0; uint32_t stop = 0; size_t size = sizeof(start) + sizeof(stop); SerializeAdapter::deSerialize(&start, &commandData, &size, SerializeIF::Endianness::BIG); SerializeAdapter::deSerialize(&stop, &commandData, &size, SerializeIF::Endianness::BIG); if ((stop - start) <= 0) { return result::INVALID_MRAM_ADDRESSES; } supv::MramCmd packet(spParams); ReturnValue_t result = packet.buildPacket(start, stop, supv::MramCmd::MramAction::WIPE); if (result != returnvalue::OK) { return result; } sendCommand(packet); return returnvalue::OK; } ReturnValue_t FreshSupvHandler::parseTmPackets() { uint8_t* receivedData = nullptr; size_t receivedSize = 0; ReturnValue_t result; while (true) { result = uartManager.readReceivedMessage(comCookie, &receivedData, &receivedSize); if (receivedSize == 0) { break; } // TODO: Implement TM packet parsing and call corresponding handler functions or verify // sent commands. } return returnvalue::OK; } bool FreshSupvHandler::isCommandAlreadyActive(ActionId_t actionId) const { auto iter = activeActionCmds.find(actionId); if (iter == activeActionCmds.end()) { return false; } if (iter->second.isPending) { return true; } return false; } ReturnValue_t FreshSupvHandler::extractUpdateCommand(const uint8_t* commandData, size_t size, supv::UpdateParams& params) { size_t remSize = size; if (size > (config::MAX_FILENAME_SIZE + config::MAX_PATH_SIZE + sizeof(params.memId)) + sizeof(params.startAddr) + sizeof(params.bytesWritten) + sizeof(params.seqCount) + sizeof(uint8_t)) { sif::warning << "PlocSupervisorHandler::extractUpdateCommand: Data size too big" << std::endl; return result::INVALID_LENGTH; } ReturnValue_t result = returnvalue::OK; result = extractBaseParams(&commandData, size, params); result = SerializeAdapter::deSerialize(¶ms.bytesWritten, &commandData, &remSize, SerializeIF::Endianness::BIG); if (result != returnvalue::OK) { sif::warning << "PlocSupervisorHandler::extractUpdateCommand: Failed to deserialize bytes " "already written" << std::endl; return result; } result = SerializeAdapter::deSerialize(¶ms.seqCount, &commandData, &remSize, SerializeIF::Endianness::BIG); if (result != returnvalue::OK) { sif::warning << "PlocSupervisorHandler::extractUpdateCommand: Failed to deserialize start sequence count" << std::endl; return result; } uint8_t delMemRaw = 0; result = SerializeAdapter::deSerialize(&delMemRaw, &commandData, &remSize, SerializeIF::Endianness::BIG); if (result != returnvalue::OK) { sif::warning << "PlocSupervisorHandler::extractUpdateCommand: Failed to deserialize whether to delete " "memory" << std::endl; return result; } params.deleteMemory = delMemRaw; return returnvalue::OK; } ReturnValue_t FreshSupvHandler::extractBaseParams(const uint8_t** commandData, size_t& remSize, supv::UpdateParams& params) { bool nullTermFound = false; for (size_t idx = 0; idx < remSize; idx++) { if ((*commandData)[idx] == '\0') { nullTermFound = true; break; } } if (not nullTermFound) { return returnvalue::FAILED; } params.file = std::string(reinterpret_cast(*commandData)); if (params.file.size() > (config::MAX_FILENAME_SIZE + config::MAX_PATH_SIZE)) { sif::warning << "PlocSupervisorHandler::extractUpdateCommand: Filename too long" << std::endl; return result::FILENAME_TOO_LONG; } *commandData += params.file.size() + SIZE_NULL_TERMINATOR; remSize -= (params.file.size() + SIZE_NULL_TERMINATOR); params.memId = **commandData; *commandData += 1; remSize -= 1; ReturnValue_t result = SerializeAdapter::deSerialize(¶ms.startAddr, commandData, &remSize, SerializeIF::Endianness::BIG); if (result != returnvalue::OK) { sif::warning << "PlocSupervisorHandler::extractBaseParams: Failed to deserialize start address" << std::endl; return result; } return result; } void FreshSupvHandler::handleEvent(EventMessage* eventMessage) { ReturnValue_t result = returnvalue::OK; object_id_t objectId = eventMessage->getReporter(); Event event = eventMessage->getEvent(); switch (objectId) { case objects::PLOC_SUPERVISOR_HELPER: { // After execution of update procedure, PLOC is in a state where it draws approx. 700 mA of // current. To leave this state the shutdown MPSoC command must be sent here. if (event == PlocSupvUartManager::SUPV_UPDATE_FAILED || event == PlocSupvUartManager::SUPV_UPDATE_SUCCESSFUL || event == PlocSupvUartManager::SUPV_CONTINUE_UPDATE_FAILED || event == PlocSupvUartManager::SUPV_CONTINUE_UPDATE_SUCCESSFUL || event == PlocSupvUartManager::SUPV_MEM_CHECK_FAIL || event == PlocSupvUartManager::SUPV_MEM_CHECK_OK) { // Wait for a short period for the uart state machine to adjust // TaskFactory::delayTask(5); if (not isCommandAlreadyActive(supv::SHUTDOWN_MPSOC)) { result = this->executeAction(supv::SHUTDOWN_MPSOC, MessageQueueIF::NO_QUEUE, nullptr, 0); if (result != returnvalue::OK) { triggerEvent(supv::SUPV_MPSOC_SHUTDOWN_BUILD_FAILED); sif::warning << "PlocSupervisorHandler::handleEvent: Failed to build MPSoC shutdown " "command" << std::endl; return; } } } break; } default: sif::debug << "PlocMPSoCHandler::handleEvent: Did not subscribe to this event" << std::endl; break; } } ReturnValue_t FreshSupvHandler::eventSubscription() { ReturnValue_t result = returnvalue::OK; EventManagerIF* manager = ObjectManager::instance()->get(objects::EVENT_MANAGER); if (manager == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PlocSupervisorHandler::eventSubscritpion: Invalid event manager" << std::endl; #endif return ObjectManagerIF::CHILD_INIT_FAILED; ; } result = manager->registerListener(eventQueue->getId()); if (result != returnvalue::OK) { return result; } result = manager->subscribeToEventRange( eventQueue->getId(), event::getEventId(PlocSupvUartManager::SUPV_UPDATE_FAILED), event::getEventId(PlocSupvUartManager::SUPV_MEM_CHECK_FAIL)); if (result != returnvalue::OK) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "PlocSupervisorHandler::eventSubscritpion: Failed to subscribe to events from " " ploc supervisor helper" << std::endl; #endif return ObjectManagerIF::CHILD_INIT_FAILED; } return result; }