diff --git a/CHANGELOG.md b/CHANGELOG.md index a5fbe994..247eddd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,11 +26,20 @@ will consitute of a breaking change warranting a new major release: - Detumbling is now exited when its exit value is undercut and not its entry value. - `EiveSystem`: Add a small delay between triggering an event for FDIR reboots and sending the command to the core controller. +- PL PDU: Fixed bounds checking logic. Bound checks will only be performed for modules which are + enabled. ## Changed - SCEX: Only perform filesystem checks when not in OFF mode. - The `EiveSystem` now only sends reboot commands targetting the same image. +- Added 200 ms delay between switching HPA/MPA/TX/X8 and DRO GPIO pin OFF. +- PL PCDU ADC set is now automatically enabled for `NORMAL` mode transitions. It is automatically + disabled for `OFF` mode transitions. + +## Added + +- PL PCDU for EM build. ## Added diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ffaf32f..17a6d5a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,7 +144,7 @@ set(OBSW_ADD_RAD_SENSORS ${INIT_VAL} CACHE STRING "Add Rad Sensor module") set(OBSW_ADD_PL_PCDU - ${INIT_VAL} + 1 CACHE STRING "Add Payload PCDU modukle") set(OBSW_ADD_SYRLINKS 1 diff --git a/bsp_q7s/em/emObjectFactory.cpp b/bsp_q7s/em/emObjectFactory.cpp index 14cafdb2..3c3ba290 100644 --- a/bsp_q7s/em/emObjectFactory.cpp +++ b/bsp_q7s/em/emObjectFactory.cpp @@ -94,6 +94,9 @@ void ObjectFactory::produce(void* args) { #if OBSW_ADD_ACS_BOARD == 1 dummyCfg.addAcsBoardDummies = false; #endif +#if OBSW_ADD_PL_PCDU == 0 + dummyCfg.addPlPcduDummy = true; +#endif PowerSwitchIF* pwrSwitcher = nullptr; #if OBSW_ADD_GOMSPACE_PCDU == 0 @@ -107,6 +110,8 @@ void ObjectFactory::produce(void* args) { new CoreController(objects::CORE_CONTROLLER, enableHkSets); + auto* stackHandler = new Stack5VHandler(*pwrSwitcher); + // Initialize chip select to avoid SPI bus issues. createRadSensorChipSelect(gpioComIF); @@ -146,6 +151,9 @@ void ObjectFactory::produce(void* args) { createStrComponents(pwrSwitcher); #endif /* OBSW_ADD_STAR_TRACKER == 1 */ +#if OBSW_ADD_PL_PCDU == 1 + createPlPcduComponents(gpioComIF, spiMainComIF, pwrSwitcher, *stackHandler); +#endif createPayloadComponents(gpioComIF, *pwrSwitcher); #if OBSW_ADD_CCSDS_IP_CORES == 1 diff --git a/bsp_q7s/fmObjectFactory.cpp b/bsp_q7s/fmObjectFactory.cpp index e43e3551..a3ab6bba 100644 --- a/bsp_q7s/fmObjectFactory.cpp +++ b/bsp_q7s/fmObjectFactory.cpp @@ -81,7 +81,9 @@ void ObjectFactory::produce(void* args) { createTmpComponents(tmpDevsToAdd); #endif createSolarArrayDeploymentComponents(*pwrSwitcher, *gpioComIF); +#if OBSW_ADD_PL_PCDU == 1 createPlPcduComponents(gpioComIF, spiMainComIF, pwrSwitcher, *stackHandler); +#endif #if OBSW_ADD_SYRLINKS == 1 createSyrlinksComponents(pwrSwitcher); #endif /* OBSW_ADD_SYRLINKS == 1 */ diff --git a/bsp_q7s/objectFactory.cpp b/bsp_q7s/objectFactory.cpp index 04da40a9..39271628 100644 --- a/bsp_q7s/objectFactory.cpp +++ b/bsp_q7s/objectFactory.cpp @@ -902,8 +902,6 @@ void ObjectFactory::createPlPcduComponents(LinuxLibgpioIF* gpioComIF, SpiComIF* new PayloadPcduHandler(objects::PLPCDU_HANDLER, objects::SPI_MAIN_COM_IF, spiCookie, gpioComIF, SdCardManager::instance(), stackHandler, false); spiCookie->setCallbackMode(PayloadPcduHandler::extConvAsTwoCallback, plPcduHandler); -// plPcduHandler->enablePeriodicPrintout(true, 5); -// static_cast(plPcduHandler); #if OBSW_TEST_PL_PCDU == 1 plPcduHandler->setStartUpImmediately(); #endif diff --git a/dummies/helperFactory.cpp b/dummies/helperFactory.cpp index 8f58cbaf..b23720b4 100644 --- a/dummies/helperFactory.cpp +++ b/dummies/helperFactory.cpp @@ -248,9 +248,11 @@ void dummy::createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitcher, GpioIF* gpio auto* scexDummy = new ScexDummy(objects::SCEX, objects::DUMMY_COM_IF, comCookieDummy); scexDummy->connectModeTreeParent(satsystem::payload::SUBSYSTEM); } - auto* plPcduDummy = - new PlPcduDummy(objects::PLPCDU_HANDLER, objects::DUMMY_COM_IF, comCookieDummy); - plPcduDummy->connectModeTreeParent(satsystem::payload::SUBSYSTEM); + if (cfg.addPlPcduDummy) { + auto* plPcduDummy = + new PlPcduDummy(objects::PLPCDU_HANDLER, objects::DUMMY_COM_IF, comCookieDummy); + plPcduDummy->connectModeTreeParent(satsystem::payload::SUBSYSTEM); + } if (cfg.addPlocDummies) { auto* plocMpsocDummy = new PlocMpsocDummy(objects::PLOC_MPSOC_HANDLER, objects::DUMMY_COM_IF, comCookieDummy); diff --git a/dummies/helperFactory.h b/dummies/helperFactory.h index 32da11cd..34d167f0 100644 --- a/dummies/helperFactory.h +++ b/dummies/helperFactory.h @@ -30,6 +30,7 @@ struct DummyCfg { bool addStrDummy = true; bool addTmpDummies = true; bool addRadSensorDummy = true; + bool addPlPcduDummy = false; Tmp1075Cfg tmp1075Cfg; bool addCamSwitcherDummy = false; bool addScexDummy = false; diff --git a/mission/payload/PayloadPcduHandler.cpp b/mission/payload/PayloadPcduHandler.cpp index 9223f454..0f2ef2d6 100644 --- a/mission/payload/PayloadPcduHandler.cpp +++ b/mission/payload/PayloadPcduHandler.cpp @@ -1,4 +1,6 @@ -#include +#include +#include "fsfw/thermal/tcsDefinitions.h" +#include #include #include "OBSWConfig.h" @@ -64,6 +66,16 @@ void PayloadPcduHandler::doShutDown() { return; } state = States::PL_PCDU_OFF; + quickTransitionAlreadyCalled = false; + { + PoolReadGuard pg(&adcSet); + adcSet.setReportingEnabled(false); + adcSet.tempC = thermal::INVALID_TEMPERATURE; + + std::memset(adcSet.channels.value, 0, sizeof(adcSet.channels.value)); + std::memset(adcSet.processed.value, 0, sizeof(adcSet.processed.value)); + adcSet.setValidity(false, true); + } // No need to set mode _MODE_POWER_DOWN, power switching was already handled setMode(MODE_OFF); } @@ -73,14 +85,7 @@ void PayloadPcduHandler::doTransition(Mode_t modeFrom, Submode_t subModeFrom) { stateMachineToNormal(modeFrom, subModeFrom); return; } else if (getMode() == _MODE_TO_ON and modeFrom == MODE_NORMAL) { - gpioIF->pullLow(gpioIds::PLPCDU_ENB_HPA); - gpioIF->pullLow(gpioIds::PLPCDU_ENB_MPA); - gpioIF->pullLow(gpioIds::PLPCDU_ENB_TX); - gpioIF->pullLow(gpioIds::PLPCDU_ENB_X8); - gpioIF->pullLow(gpioIds::PLPCDU_ENB_DRO); - gpioIF->pullLow(gpioIds::PLPCDU_ENB_TX); - gpioIF->pullLow(gpioIds::PLPCDU_ENB_VBAT0); - gpioIF->pullLow(gpioIds::PLPCDU_ENB_VBAT1); + pullAllGpiosLow(200); state = States::STACK_5V_CORRECT; } DeviceHandlerBase::doTransition(modeFrom, subModeFrom); @@ -89,6 +94,11 @@ void PayloadPcduHandler::doTransition(Mode_t modeFrom, Submode_t subModeFrom) { ReturnValue_t PayloadPcduHandler::stateMachineToNormal(Mode_t modeFrom, Submode_t subModeFrom) { using namespace plpcdu; bool doFinish = true; + if (toNormalOneShot) { + PoolReadGuard pg(&adcSet); + adcSet.setReportingEnabled(true); + toNormalOneShot = false; + } if (((getSubmode() >> SOLID_STATE_RELAYS_ADC_ON) & 0b1) == 1) { if (state == States::PL_PCDU_OFF) { sif::error << "PayloadPcduHandler::stateMachineToNormal: Unexpected state PL_PCDU_OFF" @@ -114,23 +124,23 @@ ReturnValue_t PayloadPcduHandler::stateMachineToNormal(Mode_t modeFrom, Submode_ state = States::ON_TRANS_ADC_CLOSE_ZERO; adcCountdown.setTimeout(50); adcCountdown.resetTimer(); - adcState = AdcStates::BOOT_DELAY; + adcState = AdcState::BOOT_DELAY; doFinish = false; // If the values are not close to zero, we should not allow transition monMode = MonitoringMode::CLOSE_TO_ZERO; } } if (state == States::ON_TRANS_ADC_CLOSE_ZERO) { - if (adcState == AdcStates::BOOT_DELAY) { + if (adcState == AdcState::BOOT_DELAY) { doFinish = false; if (adcCountdown.hasTimedOut()) { - adcState = AdcStates::SEND_SETUP; + adcState = AdcState::SEND_SETUP; adcCmdExecuted = false; } } - if (adcState == AdcStates::SEND_SETUP) { + if (adcState == AdcState::SEND_SETUP) { if (adcCmdExecuted) { - adcState = AdcStates::NORMAL; + adcState = AdcState::NORMAL; doFinish = true; adcCountdown.setTimeout(100); adcCountdown.resetTimer(); @@ -167,6 +177,7 @@ ReturnValue_t PayloadPcduHandler::stateMachineToNormal(Mode_t modeFrom, Submode_ switchHandler(MPA_ON, gpioIds::PLPCDU_ENB_MPA, "MPA"); switchHandler(HPA_ON, gpioIds::PLPCDU_ENB_HPA, "HPA"); if (doFinish) { + toNormalOneShot = true; setMode(MODE_NORMAL); } return returnvalue::OK; @@ -174,11 +185,11 @@ ReturnValue_t PayloadPcduHandler::stateMachineToNormal(Mode_t modeFrom, Submode_ ReturnValue_t PayloadPcduHandler::buildNormalDeviceCommand(DeviceCommandId_t* id) { switch (adcState) { - case (AdcStates::SEND_SETUP): { + case (AdcState::SEND_SETUP): { *id = plpcdu::SETUP_CMD; return buildCommandFromCommand(*id, nullptr, 0); } - case (AdcStates::NORMAL): { + case (AdcState::NORMAL): { *id = plpcdu::READ_WITH_TEMP_EXT; return buildCommandFromCommand(*id, nullptr, 0); } @@ -190,7 +201,7 @@ ReturnValue_t PayloadPcduHandler::buildNormalDeviceCommand(DeviceCommandId_t* id } ReturnValue_t PayloadPcduHandler::buildTransitionDeviceCommand(DeviceCommandId_t* id) { - if (adcState == AdcStates::SEND_SETUP) { + if (adcState == AdcState::SEND_SETUP) { *id = plpcdu::SETUP_CMD; return buildCommandFromCommand(*id, nullptr, 0); } @@ -211,9 +222,9 @@ void PayloadPcduHandler::updateSwitchGpio(gpioId_t id, gpio::Levels level) { } void PayloadPcduHandler::fillCommandAndReplyMap() { - insertInCommandAndReplyMap(plpcdu::READ_CMD, 2, &adcSet); - insertInCommandAndReplyMap(plpcdu::READ_TEMP_EXT, 1, &adcSet); - insertInCommandAndReplyMap(plpcdu::READ_WITH_TEMP_EXT, 1, &adcSet); + insertInCommandAndReplyMap(plpcdu::READ_CMD, 2); + insertInCommandAndReplyMap(plpcdu::READ_TEMP_EXT, 1); + insertInCommandAndReplyMap(plpcdu::READ_WITH_TEMP_EXT, 1); insertInCommandAndReplyMap(plpcdu::SETUP_CMD, 1); } @@ -277,27 +288,31 @@ ReturnValue_t PayloadPcduHandler::interpretDeviceReply(DeviceCommandId_t id, break; } case (READ_CMD): { - PoolReadGuard pg(&adcSet); - if (pg.getReadResult() != returnvalue::OK) { - return pg.getReadResult(); + { + PoolReadGuard pg(&adcSet); + if (pg.getReadResult() != returnvalue::OK) { + return pg.getReadResult(); + } + handleExtConvRead(packet); + checkAdcValues(); + adcSet.setValidity(true, true); } - handleExtConvRead(packet); - checkAdcValues(); - adcSet.setValidity(true, true); handlePrintout(); break; } case (READ_WITH_TEMP_EXT): { - PoolReadGuard pg(&adcSet); - if (pg.getReadResult() != returnvalue::OK) { - return pg.getReadResult(); + { + PoolReadGuard pg(&adcSet); + if (pg.getReadResult() != returnvalue::OK) { + return pg.getReadResult(); + } + handleExtConvRead(packet); + uint8_t tempStartIdx = ADC_REPLY_SIZE + TEMP_REPLY_SIZE - 2; + adcSet.tempC.value = + max1227::getTemperature(packet[tempStartIdx] << 8 | packet[tempStartIdx + 1]); + checkAdcValues(); + adcSet.setValidity(true, true); } - handleExtConvRead(packet); - uint8_t tempStartIdx = ADC_REPLY_SIZE + TEMP_REPLY_SIZE - 2; - adcSet.tempC.value = - max1227::getTemperature(packet[tempStartIdx] << 8 | packet[tempStartIdx + 1]); - checkAdcValues(); - adcSet.setValidity(true, true); handlePrintout(); break; } @@ -367,16 +382,9 @@ void PayloadPcduHandler::enablePeriodicPrintout(bool enable, uint8_t divider) { void PayloadPcduHandler::quickTransitionBackToOff(bool startTransitionToOff, bool notifyFdir) { States currentState = state; - gpioIF->pullLow(gpioIds::PLPCDU_ENB_HPA); - gpioIF->pullLow(gpioIds::PLPCDU_ENB_MPA); - gpioIF->pullLow(gpioIds::PLPCDU_ENB_TX); - gpioIF->pullLow(gpioIds::PLPCDU_ENB_X8); - gpioIF->pullLow(gpioIds::PLPCDU_ENB_DRO); - gpioIF->pullLow(gpioIds::PLPCDU_ENB_TX); - gpioIF->pullLow(gpioIds::PLPCDU_ENB_VBAT0); - gpioIF->pullLow(gpioIds::PLPCDU_ENB_VBAT1); + pullAllGpiosLow(200); state = States::STACK_5V_SWITCHING; - adcState = AdcStates::OFF; + adcState = AdcState::OFF; if (startTransitionToOff) { startTransition(MODE_OFF, 0); } @@ -405,10 +413,13 @@ void PayloadPcduHandler::checkAdcValues() { adcSet.processed[U_DRO_DIV_6] = static_cast(adcSet.channels[11]) * SCALE_VOLTAGE; float lowerBound = 0.0; float upperBound = 0.0; - bool adcTransition = false; - adcTransition = state == States::ON_TRANS_DRO and adcCountdown.isBusy(); - // Now check against voltage and current limits, depending on state - if (state >= States::ON_TRANS_DRO and not adcTransition) { + bool adcTransition = adcState == AdcState::NORMAL and adcCountdown.isBusy(); + if (NO_ADC_CHECKS or adcTransition) { + return; + } + // Now check against voltage and current limits. + uint8_t submode = getSubmode(); + if (((submode >> NormalSubmodeBits::DRO_ON) & 0b1) == 0b1) { if (ssrToDroInjectionRequested) { handleFailureInjection("SSR to DRO", NEG_V_OUT_OF_BOUNDS); ssrToDroInjectionRequested = false; @@ -435,8 +446,7 @@ void PayloadPcduHandler::checkAdcValues() { return; } } - adcTransition = state == States::ON_TRANS_X8 and adcCountdown.isBusy(); - if (state >= States::ON_TRANS_X8 and not adcTransition) { + if (((submode >> NormalSubmodeBits::X8_ON) & 0b1) == 0b1) { if (droToX8InjectionRequested) { handleFailureInjection("X8 to TX", U_X8_OUT_OF_BOUNDS); droToX8InjectionRequested = false; @@ -453,8 +463,7 @@ void PayloadPcduHandler::checkAdcValues() { return; } } - adcTransition = state == States::ON_TRANS_TX and adcCountdown.isBusy(); - if (state >= States::ON_TRANS_TX and not adcTransition) { + if (((submode >> NormalSubmodeBits::TX_ON) & 0b1) == 0b1) { if (txToMpaInjectionRequested) { handleFailureInjection("TX to MPA", U_TX_OUT_OF_BOUNDS); txToMpaInjectionRequested = false; @@ -471,8 +480,7 @@ void PayloadPcduHandler::checkAdcValues() { return; } } - adcTransition = state == States::ON_TRANS_MPA and adcCountdown.isBusy(); - if (state >= States::ON_TRANS_MPA and not adcTransition) { + if (((submode >> NormalSubmodeBits::MPA_ON) & 0b1) == 0b1) { if (mpaToHpaInjectionRequested) { handleFailureInjection("MPA to HPA", U_HPA_OUT_OF_BOUNDS); mpaToHpaInjectionRequested = false; @@ -489,8 +497,7 @@ void PayloadPcduHandler::checkAdcValues() { return; } } - adcTransition = state == States::ON_TRANS_HPA and adcCountdown.isBusy(); - if (state >= States::ON_TRANS_HPA and not adcTransition) { + if (((submode >> NormalSubmodeBits::HPA_ON) & 0b1) == 0b1) { if (allOnInjectRequested) { handleFailureInjection("All On", U_HPA_OUT_OF_BOUNDS); allOnInjectRequested = false; @@ -677,6 +684,18 @@ void PayloadPcduHandler::handleFailureInjection(std::string output, Event event) droToX8InjectionRequested = false; } +void PayloadPcduHandler::pullAllGpiosLow(uint32_t delayBeforeSwitchingOffDro) { + sif::info << "Pulling all PL PCDU GPIOs to low" << std::endl; + gpioIF->pullLow(gpioIds::PLPCDU_ENB_HPA); + gpioIF->pullLow(gpioIds::PLPCDU_ENB_MPA); + gpioIF->pullLow(gpioIds::PLPCDU_ENB_TX); + gpioIF->pullLow(gpioIds::PLPCDU_ENB_X8); + TaskFactory::delayTask(delayBeforeSwitchingOffDro); + gpioIF->pullLow(gpioIds::PLPCDU_ENB_DRO); + gpioIF->pullLow(gpioIds::PLPCDU_ENB_VBAT0); + gpioIF->pullLow(gpioIds::PLPCDU_ENB_VBAT1); +} + ReturnValue_t PayloadPcduHandler::handleDoubleParamUpdate(std::string key, ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues) { @@ -692,6 +711,8 @@ ReturnValue_t PayloadPcduHandler::handleDoubleParamUpdate(std::string key, return params.writeJsonFile(); } +LocalPoolDataSetBase* PayloadPcduHandler::getDataSetHandle(sid_t sid) { return &adcSet; } + #ifdef XIPHOS_Q7S ReturnValue_t PayloadPcduHandler::extConvAsTwoCallback(SpiComIF* comIf, SpiCookie* cookie, const uint8_t* sendData, size_t sendLen, diff --git a/mission/payload/PayloadPcduHandler.h b/mission/payload/PayloadPcduHandler.h index b73de353..d9370dcf 100644 --- a/mission/payload/PayloadPcduHandler.h +++ b/mission/payload/PayloadPcduHandler.h @@ -76,6 +76,8 @@ class PayloadPcduHandler : public DeviceHandlerBase { #endif private: + static constexpr bool NO_ADC_CHECKS = false; + enum class States : uint8_t { PL_PCDU_OFF, STACK_5V_SWITCHING, @@ -84,20 +86,7 @@ class PayloadPcduHandler : public DeviceHandlerBase { // Solid State Relay, enable battery voltages VBAT0 and VBAT1. This will also switch on // the ADC ON_TRANS_SSR, - ON_TRANS_ADC_CLOSE_ZERO, - // Enable Dielectric Resonant Oscillator and start monitoring voltages as - // soon as DRO voltage reaches 6V - ON_TRANS_DRO, - // Switch on X8 compoennt and monitor voltages for 5 seconds - ON_TRANS_X8, - // Switch on TX component and monitor voltages for 5 seconds - ON_TRANS_TX, - // Switch on MPA component and monitor voltages for 5 seconds - ON_TRANS_MPA, - // Switch on HPA component and monitor voltages for 5 seconds - ON_TRANS_HPA, - // All components of the experiment are on - PL_PCDU_ON, + ON_TRANS_ADC_CLOSE_ZERO } state = States::PL_PCDU_OFF; duallane::Submodes pwrSubmode = duallane::Submodes::A_SIDE; @@ -106,7 +95,7 @@ class PayloadPcduHandler : public DeviceHandlerBase { enum class MonitoringMode { NONE, CLOSE_TO_ZERO, NEGATIVE } monMode = MonitoringMode::NONE; - enum class AdcStates { OFF, BOOT_DELAY, SEND_SETUP, NORMAL } adcState = AdcStates::OFF; + enum class AdcState { OFF, BOOT_DELAY, SEND_SETUP, NORMAL } adcState = AdcState::OFF; bool goToNormalMode = false; plpcdu::PlPcduAdcSet adcSet; @@ -128,6 +117,7 @@ class PayloadPcduHandler : public DeviceHandlerBase { bool mpaToHpaInjectionRequested = false; bool allOnInjectRequested = false; bool clearSetOnOffFlag = true; + bool toNormalOneShot = true; PeriodicOperationDivider opDivider = PeriodicOperationDivider(5); uint8_t tempReadDivisor = 1; @@ -168,6 +158,7 @@ class PayloadPcduHandler : public DeviceHandlerBase { void handleExtConvRead(const uint8_t* bufStart); void handlePrintout(); + void pullAllGpiosLow(uint32_t delayBeforeSwitchingOffDro); void checkAdcValues(); void handleOutOfBoundsPrintout(); void checkJsonFileInit(); @@ -178,6 +169,7 @@ class PayloadPcduHandler : public DeviceHandlerBase { ReturnValue_t serializeFloat(uint32_t& param, float val); ReturnValue_t handleDoubleParamUpdate(std::string key, ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues); + LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; }; #endif /* LINUX_DEVICES_PLPCDUHANDLER_H_ */