Possible Bugfix for Duallane Swichting #545

Merged
muellerr merged 6 commits from possible_bugfix_duallane_power_switching into develop 2023-04-01 13:43:37 +02:00
8 changed files with 75 additions and 17 deletions

View File

@ -26,11 +26,13 @@ will consitute of a breaking change warranting a new major release:
- Added `PTME_LOCKED` boolean lock which is used to lock the PTME so it is not used by the VC tasks - Added `PTME_LOCKED` boolean lock which is used to lock the PTME so it is not used by the VC tasks
anymore. This lock will be controlled by the CCSDS IP core handler and is locked when the PTME anymore. This lock will be controlled by the CCSDS IP core handler and is locked when the PTME
needs to be reset. Examples for this are datarate changes. needs to be reset. Examples for this are datarate changes.
- Simulate real PCDU in PCDU dummy by remembering commandes switch change and triggering appropriate
events. Switch feedback is still immediate.
## Fixed ## Fixed
- Bugfix for side lane transitions of the dual lane assemblies, which only worked when the - Bugfix for side lane transitions of the dual lane assemblies, which only worked when the
assembly was directly commanded assembly was directly commanded.
- Syrlinks Handler: Bugfix so transition command is only sent once. - Syrlinks Handler: Bugfix so transition command is only sent once.
## Added ## Added

View File

@ -2,8 +2,12 @@
#include <mission/power/gsDefs.h> #include <mission/power/gsDefs.h>
#include "mission/power/defs.h"
PcduHandlerDummy::PcduHandlerDummy(object_id_t objectId, object_id_t comif, CookieIF *comCookie) PcduHandlerDummy::PcduHandlerDummy(object_id_t objectId, object_id_t comif, CookieIF *comCookie)
: DeviceHandlerBase(objectId, comif, comCookie), dummySwitcher(objectId, 18, 18, false) {} : DeviceHandlerBase(objectId, comif, comCookie), dummySwitcher(objectId, 18, 18, false) {
switcherLock = MutexFactory::instance()->createMutex();
}
PcduHandlerDummy::~PcduHandlerDummy() {} PcduHandlerDummy::~PcduHandlerDummy() {}
@ -44,6 +48,17 @@ ReturnValue_t PcduHandlerDummy::initializeLocalDataPool(localpool::DataPool &loc
} }
ReturnValue_t PcduHandlerDummy::sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) { ReturnValue_t PcduHandlerDummy::sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) {
if (onOff == SWITCH_ON) {
triggerEvent(power::SWITCH_CMD_SENT, true, switchNr);
} else {
triggerEvent(power::SWITCH_CMD_SENT, false, switchNr);
}
{
MutexGuard mg(switcherLock);
// To simulate a real PCDU, remember the switch change to trigger a SWITCH_HAS_CHANGED event
// at a later stage.
switchChangeArray[switchNr] = true;
}
return dummySwitcher.sendSwitchCommand(switchNr, onOff); return dummySwitcher.sendSwitchCommand(switchNr, onOff);
} }
@ -60,3 +75,22 @@ ReturnValue_t PcduHandlerDummy::getFuseState(uint8_t fuseNr) const {
} }
uint32_t PcduHandlerDummy::getSwitchDelayMs(void) const { return dummySwitcher.getSwitchDelayMs(); } uint32_t PcduHandlerDummy::getSwitchDelayMs(void) const { return dummySwitcher.getSwitchDelayMs(); }
void PcduHandlerDummy::performOperationHook() {
SwitcherBoolArray switcherChangeCopy{};
{
MutexGuard mg(switcherLock);
std::memcpy(switcherChangeCopy.data(), switchChangeArray.data(), switchChangeArray.size());
}
for (uint8_t idx = 0; idx < switcherChangeCopy.size(); idx++) {
if (switcherChangeCopy[idx]) {
if (dummySwitcher.getSwitchState(idx) == PowerSwitchIF::SWITCH_ON) {
triggerEvent(power::SWITCH_HAS_CHANGED, true, idx);
} else {
triggerEvent(power::SWITCH_HAS_CHANGED, false, idx);
}
MutexGuard mg(switcherLock);
switchChangeArray[idx] = false;
}
}
}

View File

@ -15,8 +15,12 @@ class PcduHandlerDummy : public DeviceHandlerBase, public PowerSwitchIF {
virtual ~PcduHandlerDummy(); virtual ~PcduHandlerDummy();
protected: protected:
MutexIF *switcherLock;
DummyPowerSwitcher dummySwitcher; DummyPowerSwitcher dummySwitcher;
using SwitcherBoolArray = std::array<bool, 18>;
SwitcherBoolArray switchChangeArray{};
void performOperationHook() override;
void doStartUp() override; void doStartUp() override;
void doShutDown() override; void doShutDown() override;
ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t *id) override; ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t *id) override;

View File

@ -112,19 +112,7 @@ ReturnValue_t AcsBoardAssembly::handleNormalOrOnModeCmd(Mode_t mode, Submode_t s
using namespace duallane; using namespace duallane;
ReturnValue_t result = returnvalue::OK; ReturnValue_t result = returnvalue::OK;
bool needsSecondStep = false; bool needsSecondStep = false;
if (sideSwitchState == SideSwitchState::REQUESTED) { handleSideSwitchStates(submode, needsSecondStep);
sideSwitchState = SideSwitchState::TO_DUAL;
}
// Switch to dual side first, and later switch back to the otherside
if (sideSwitchState == SideSwitchState::TO_DUAL) {
targetSubmodeForSideSwitch = static_cast<duallane::Submodes>(submode);
submode = Submodes::DUAL_MODE;
sideSwitchState = SideSwitchState::DISABLE_OTHER_SIDE;
// TODO: Ugly hack. The base class should support arbitrary number of steps..
needsSecondStep = true;
} else if (sideSwitchState == SideSwitchState::DISABLE_OTHER_SIDE) {
submode = targetSubmodeForSideSwitch;
}
auto cmdSeq = [&](object_id_t objectId, Mode_t devMode, ModeTableIdx tableIdx) { auto cmdSeq = [&](object_id_t objectId, Mode_t devMode, ModeTableIdx tableIdx) {
if (mode == devMode) { if (mode == devMode) {
modeTable[tableIdx].setMode(mode); modeTable[tableIdx].setMode(mode);

View File

@ -130,7 +130,11 @@ void DualLaneAssemblyBase::handleModeReached() {
// For dual to single side transition, devices should be logically off, but the switch // For dual to single side transition, devices should be logically off, but the switch
// handling still needs to be done. // handling still needs to be done.
if (dualToSingleSideTransition) { if (dualToSingleSideTransition) {
pwrStateMachine.start(targetMode, targetSubmode); if (sideSwitchState == SideSwitchState::DISABLE_OTHER_SIDE) {
pwrStateMachine.start(targetMode, targetSubmodeForSideSwitch);
} else {
pwrStateMachine.start(targetMode, targetSubmode);
}
pwrStateMachineWrapper(); pwrStateMachineWrapper();
return; return;
} }
@ -238,6 +242,24 @@ bool DualLaneAssemblyBase::sideSwitchTransition(Mode_t mode, Submode_t submode)
return false; return false;
} }
void DualLaneAssemblyBase::handleSideSwitchStates(uint8_t& submode, bool& needsSecondStep) {
if (sideSwitchState == SideSwitchState::REQUESTED) {
sideSwitchState = SideSwitchState::TO_DUAL;
}
// Switch to dual side first, and later switch back to the otherside
if (sideSwitchState == SideSwitchState::TO_DUAL) {
targetSubmodeForSideSwitch = static_cast<duallane::Submodes>(submode);
submode = duallane::Submodes::DUAL_MODE;
sideSwitchState = SideSwitchState::DISABLE_OTHER_SIDE;
// TODO: Ugly hack. The base class should support arbitrary number of steps..
needsSecondStep = true;
} else if (sideSwitchState == SideSwitchState::DISABLE_OTHER_SIDE) {
// Set this flag because the power needs to be switched off.
dualToSingleSideTransition = true;
submode = targetSubmodeForSideSwitch;
}
}
void DualLaneAssemblyBase::finishModeOp() { void DualLaneAssemblyBase::finishModeOp() {
using namespace duallane; using namespace duallane;
AssemblyBase::handleModeReached(); AssemblyBase::handleModeReached();

View File

@ -48,6 +48,13 @@ class DualLaneAssemblyBase : public AssemblyBase, public ConfirmsFailuresIF {
MessageQueueIF* eventQueue = nullptr; MessageQueueIF* eventQueue = nullptr;
/**
* To be called in mode command packer function of the child class.
* @param submode
* @param needsSecondStep
*/
void handleSideSwitchStates(uint8_t& submode, bool& needsSecondStep);
/** /**
* Check whether it makes sense to send mode commands to the device. * Check whether it makes sense to send mode commands to the device.
* @param object * @param object

View File

@ -45,6 +45,7 @@ ReturnValue_t SusAssembly::handleNormalOrOnModeCmd(Mode_t mode, Submode_t submod
using namespace duallane; using namespace duallane;
ReturnValue_t result = returnvalue::OK; ReturnValue_t result = returnvalue::OK;
bool needsSecondStep = false; bool needsSecondStep = false;
handleSideSwitchStates(submode, needsSecondStep);
auto cmdSeq = [&](object_id_t objectId, Mode_t devMode, uint8_t tableIdx) { auto cmdSeq = [&](object_id_t objectId, Mode_t devMode, uint8_t tableIdx) {
if (mode == devMode) { if (mode == devMode) {
modeTable[tableIdx].setMode(mode); modeTable[tableIdx].setMode(mode);

2
tmtc

@ -1 +1 @@
Subproject commit aab50dce5ace6878432377fff5e6b2cd1c485213 Subproject commit bc85ccd8eff0eaf2a168eee907d3436433e9b219