Possible Bugfix for Duallane Swichting #545
@ -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
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
|
@ -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
|
||||||
|
@ -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
2
tmtc
@ -1 +1 @@
|
|||||||
Subproject commit aab50dce5ace6878432377fff5e6b2cd1c485213
|
Subproject commit bc85ccd8eff0eaf2a168eee907d3436433e9b219
|
Loading…
Reference in New Issue
Block a user