Merge pull request 'PL PCDU tweaks' (#766) from pl-pcdu-tweaks into main
All checks were successful
EIVE/eive-obsw/pipeline/head This commit looks good

Reviewed-on: #766
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
This commit is contained in:
Robin Müller 2023-08-03 13:07:10 +02:00
commit 1267097368
9 changed files with 110 additions and 77 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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<void>(plPcduHandler);
#if OBSW_TEST_PL_PCDU == 1
plPcduHandler->setStartUpImmediately();
#endif

View File

@ -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);

View File

@ -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;

View File

@ -1,4 +1,6 @@
#include <fsfw/src/fsfw/datapool/PoolReadGuard.h>
#include <fsfw/datapool/PoolReadGuard.h>
#include "fsfw/thermal/tcsDefinitions.h"
#include <fsfw/tasks/TaskFactory.h>
#include <mission/payload/PayloadPcduHandler.h>
#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<float>(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,

View File

@ -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_ */