include replacements
This commit is contained in:
@ -1,273 +1,273 @@
|
||||
#include <framework/devicehandlers/AssemblyBase.h>
|
||||
|
||||
AssemblyBase::AssemblyBase(object_id_t objectId, object_id_t parentId,
|
||||
uint16_t commandQueueDepth) :
|
||||
SubsystemBase(objectId, parentId, MODE_OFF, commandQueueDepth),
|
||||
internalState(STATE_NONE), recoveryState(RECOVERY_IDLE),
|
||||
recoveringDevice(childrenMap.end()), targetMode(MODE_OFF),
|
||||
targetSubmode(SUBMODE_NONE) {
|
||||
recoveryOffTimer.setTimeout(POWER_OFF_TIME_MS);
|
||||
}
|
||||
|
||||
AssemblyBase::~AssemblyBase() {
|
||||
}
|
||||
|
||||
ReturnValue_t AssemblyBase::handleCommandMessage(CommandMessage* message) {
|
||||
return handleHealthReply(message);
|
||||
}
|
||||
|
||||
void AssemblyBase::performChildOperation() {
|
||||
if (isInTransition()) {
|
||||
handleChildrenTransition();
|
||||
} else {
|
||||
handleChildrenChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBase::startTransition(Mode_t mode, Submode_t submode) {
|
||||
doStartTransition(mode, submode);
|
||||
if (modeHelper.isForced()) {
|
||||
triggerEvent(FORCING_MODE, mode, submode);
|
||||
} else {
|
||||
triggerEvent(CHANGING_MODE, mode, submode);
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBase::doStartTransition(Mode_t mode, Submode_t submode) {
|
||||
targetMode = mode;
|
||||
targetSubmode = submode;
|
||||
internalState = STATE_SINGLE_STEP;
|
||||
ReturnValue_t result = commandChildren(mode, submode);
|
||||
if (result == NEED_SECOND_STEP) {
|
||||
internalState = STATE_NEED_SECOND_STEP;
|
||||
}
|
||||
}
|
||||
|
||||
bool AssemblyBase::isInTransition() {
|
||||
return (internalState != STATE_NONE) || (recoveryState != RECOVERY_IDLE);
|
||||
}
|
||||
|
||||
bool AssemblyBase::handleChildrenChanged() {
|
||||
if (childrenChangedMode) {
|
||||
ReturnValue_t result = checkChildrenState();
|
||||
if (result != RETURN_OK) {
|
||||
handleChildrenLostMode(result);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return handleChildrenChangedHealth();
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBase::handleChildrenLostMode(ReturnValue_t result) {
|
||||
triggerEvent(CANT_KEEP_MODE, mode, submode);
|
||||
startTransition(MODE_OFF, SUBMODE_NONE);
|
||||
}
|
||||
|
||||
bool AssemblyBase::handleChildrenChangedHealth() {
|
||||
auto iter = childrenMap.begin();
|
||||
for (; iter != childrenMap.end(); iter++) {
|
||||
if (iter->second.healthChanged) {
|
||||
iter->second.healthChanged = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (iter == childrenMap.end()) {
|
||||
return false;
|
||||
}
|
||||
HealthState healthState = healthHelper.healthTable->getHealth(iter->first);
|
||||
if (healthState == HasHealthIF::NEEDS_RECOVERY) {
|
||||
triggerEvent(TRYING_RECOVERY);
|
||||
recoveryState = RECOVERY_STARTED;
|
||||
recoveringDevice = iter;
|
||||
doStartTransition(targetMode, targetSubmode);
|
||||
} else {
|
||||
triggerEvent(CHILD_CHANGED_HEALTH);
|
||||
doStartTransition(mode, submode);
|
||||
}
|
||||
if (modeHelper.isForced()) {
|
||||
triggerEvent(FORCING_MODE, targetMode, targetSubmode);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AssemblyBase::handleChildrenTransition() {
|
||||
if (commandsOutstanding <= 0) {
|
||||
switch (internalState) {
|
||||
case STATE_NEED_SECOND_STEP:
|
||||
internalState = STATE_SECOND_STEP;
|
||||
commandChildren(targetMode, targetSubmode);
|
||||
return;
|
||||
case STATE_OVERWRITE_HEALTH: {
|
||||
internalState = STATE_SINGLE_STEP;
|
||||
ReturnValue_t result = commandChildren(mode, submode);
|
||||
if (result == NEED_SECOND_STEP) {
|
||||
internalState = STATE_NEED_SECOND_STEP;
|
||||
}
|
||||
return;
|
||||
}
|
||||
case STATE_NONE:
|
||||
//Valid state, used in recovery.
|
||||
case STATE_SINGLE_STEP:
|
||||
case STATE_SECOND_STEP:
|
||||
if (checkAndHandleRecovery()) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ReturnValue_t result = checkChildrenState();
|
||||
if (result == RETURN_OK) {
|
||||
handleModeReached();
|
||||
} else {
|
||||
handleModeTransitionFailed(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBase::handleModeReached() {
|
||||
internalState = STATE_NONE;
|
||||
setMode(targetMode, targetSubmode);
|
||||
}
|
||||
|
||||
void AssemblyBase::handleModeTransitionFailed(ReturnValue_t result) {
|
||||
//always accept transition to OFF, there is nothing we can do except sending an info event
|
||||
//In theory this should never happen, but we would risk an infinite loop otherwise
|
||||
if (targetMode == MODE_OFF) {
|
||||
triggerEvent(CHILD_PROBLEMS, result);
|
||||
internalState = STATE_NONE;
|
||||
setMode(targetMode, targetSubmode);
|
||||
} else {
|
||||
if (handleChildrenChangedHealth()) {
|
||||
//If any health change is pending, handle that first.
|
||||
return;
|
||||
}
|
||||
triggerEvent(MODE_TRANSITION_FAILED, result);
|
||||
startTransition(MODE_OFF, SUBMODE_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBase::sendHealthCommand(MessageQueueId_t sendTo,
|
||||
HealthState health) {
|
||||
CommandMessage command;
|
||||
HealthMessage::setHealthMessage(&command, HealthMessage::HEALTH_SET,
|
||||
health);
|
||||
if (commandQueue->sendMessage(sendTo, &command) == RETURN_OK) {
|
||||
commandsOutstanding++;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t AssemblyBase::checkChildrenState() {
|
||||
if (targetMode == MODE_OFF) {
|
||||
return checkChildrenStateOff();
|
||||
} else {
|
||||
return checkChildrenStateOn(targetMode, targetSubmode);
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t AssemblyBase::checkChildrenStateOff() {
|
||||
for (const auto& childIter: childrenMap) {
|
||||
if (checkChildOff(childIter.first) != RETURN_OK) {
|
||||
return NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE;
|
||||
}
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t AssemblyBase::checkChildOff(uint32_t objectId) {
|
||||
ChildInfo childInfo = childrenMap.find(objectId)->second;
|
||||
if (healthHelper.healthTable->isCommandable(objectId)) {
|
||||
if (childInfo.submode != SUBMODE_NONE) {
|
||||
return RETURN_FAILED;
|
||||
} else {
|
||||
if ((childInfo.mode != MODE_OFF)
|
||||
&& (childInfo.mode != DeviceHandlerIF::MODE_ERROR_ON)) {
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t AssemblyBase::checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t* msToReachTheMode) {
|
||||
|
||||
//always accept transition to OFF
|
||||
if (mode == MODE_OFF) {
|
||||
if (submode != SUBMODE_NONE) {
|
||||
return INVALID_SUBMODE;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
if ((mode != MODE_ON) && (mode != DeviceHandlerIF::MODE_NORMAL)) {
|
||||
return INVALID_MODE;
|
||||
}
|
||||
|
||||
if (internalState != STATE_NONE) {
|
||||
return IN_TRANSITION;
|
||||
}
|
||||
|
||||
return isModeCombinationValid(mode, submode);
|
||||
}
|
||||
|
||||
ReturnValue_t AssemblyBase::handleHealthReply(CommandMessage* message) {
|
||||
if (message->getCommand() == HealthMessage::HEALTH_INFO) {
|
||||
HealthState health = HealthMessage::getHealth(message);
|
||||
if (health != EXTERNAL_CONTROL) {
|
||||
updateChildChangedHealth(message->getSender(), true);
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
if (message->getCommand() == HealthMessage::REPLY_HEALTH_SET
|
||||
|| (message->getCommand() == CommandMessage::REPLY_REJECTED
|
||||
&& message->getParameter2() == HealthMessage::HEALTH_SET)) {
|
||||
if (isInTransition()) {
|
||||
commandsOutstanding--;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
||||
bool AssemblyBase::checkAndHandleRecovery() {
|
||||
switch (recoveryState) {
|
||||
case RECOVERY_STARTED:
|
||||
recoveryState = RECOVERY_WAIT;
|
||||
recoveryOffTimer.resetTimer();
|
||||
return true;
|
||||
case RECOVERY_WAIT:
|
||||
if (recoveryOffTimer.isBusy()) {
|
||||
return true;
|
||||
}
|
||||
triggerEvent(RECOVERY_STEP, 0);
|
||||
sendHealthCommand(recoveringDevice->second.commandQueue, HEALTHY);
|
||||
internalState = STATE_NONE;
|
||||
recoveryState = RECOVERY_ONGOING;
|
||||
//Don't check state!
|
||||
return true;
|
||||
case RECOVERY_ONGOING:
|
||||
triggerEvent(RECOVERY_STEP, 1);
|
||||
recoveryState = RECOVERY_ONGOING_2;
|
||||
recoveringDevice->second.healthChanged = false;
|
||||
//Device should be healthy again, so restart a transition.
|
||||
//Might be including second step, but that's already handled.
|
||||
doStartTransition(targetMode, targetSubmode);
|
||||
return true;
|
||||
case RECOVERY_ONGOING_2:
|
||||
triggerEvent(RECOVERY_DONE);
|
||||
//Now we're through, but not sure if it was successful.
|
||||
recoveryState = RECOVERY_IDLE;
|
||||
return false;
|
||||
case RECOVERY_IDLE:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBase::overwriteDeviceHealth(object_id_t objectId,
|
||||
HasHealthIF::HealthState oldHealth) {
|
||||
triggerEvent(OVERWRITING_HEALTH, objectId, oldHealth);
|
||||
internalState = STATE_OVERWRITE_HEALTH;
|
||||
modeHelper.setForced(true);
|
||||
sendHealthCommand(childrenMap[objectId].commandQueue, EXTERNAL_CONTROL);
|
||||
}
|
||||
#include "../devicehandlers/AssemblyBase.h"
|
||||
|
||||
AssemblyBase::AssemblyBase(object_id_t objectId, object_id_t parentId,
|
||||
uint16_t commandQueueDepth) :
|
||||
SubsystemBase(objectId, parentId, MODE_OFF, commandQueueDepth),
|
||||
internalState(STATE_NONE), recoveryState(RECOVERY_IDLE),
|
||||
recoveringDevice(childrenMap.end()), targetMode(MODE_OFF),
|
||||
targetSubmode(SUBMODE_NONE) {
|
||||
recoveryOffTimer.setTimeout(POWER_OFF_TIME_MS);
|
||||
}
|
||||
|
||||
AssemblyBase::~AssemblyBase() {
|
||||
}
|
||||
|
||||
ReturnValue_t AssemblyBase::handleCommandMessage(CommandMessage* message) {
|
||||
return handleHealthReply(message);
|
||||
}
|
||||
|
||||
void AssemblyBase::performChildOperation() {
|
||||
if (isInTransition()) {
|
||||
handleChildrenTransition();
|
||||
} else {
|
||||
handleChildrenChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBase::startTransition(Mode_t mode, Submode_t submode) {
|
||||
doStartTransition(mode, submode);
|
||||
if (modeHelper.isForced()) {
|
||||
triggerEvent(FORCING_MODE, mode, submode);
|
||||
} else {
|
||||
triggerEvent(CHANGING_MODE, mode, submode);
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBase::doStartTransition(Mode_t mode, Submode_t submode) {
|
||||
targetMode = mode;
|
||||
targetSubmode = submode;
|
||||
internalState = STATE_SINGLE_STEP;
|
||||
ReturnValue_t result = commandChildren(mode, submode);
|
||||
if (result == NEED_SECOND_STEP) {
|
||||
internalState = STATE_NEED_SECOND_STEP;
|
||||
}
|
||||
}
|
||||
|
||||
bool AssemblyBase::isInTransition() {
|
||||
return (internalState != STATE_NONE) || (recoveryState != RECOVERY_IDLE);
|
||||
}
|
||||
|
||||
bool AssemblyBase::handleChildrenChanged() {
|
||||
if (childrenChangedMode) {
|
||||
ReturnValue_t result = checkChildrenState();
|
||||
if (result != RETURN_OK) {
|
||||
handleChildrenLostMode(result);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return handleChildrenChangedHealth();
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBase::handleChildrenLostMode(ReturnValue_t result) {
|
||||
triggerEvent(CANT_KEEP_MODE, mode, submode);
|
||||
startTransition(MODE_OFF, SUBMODE_NONE);
|
||||
}
|
||||
|
||||
bool AssemblyBase::handleChildrenChangedHealth() {
|
||||
auto iter = childrenMap.begin();
|
||||
for (; iter != childrenMap.end(); iter++) {
|
||||
if (iter->second.healthChanged) {
|
||||
iter->second.healthChanged = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (iter == childrenMap.end()) {
|
||||
return false;
|
||||
}
|
||||
HealthState healthState = healthHelper.healthTable->getHealth(iter->first);
|
||||
if (healthState == HasHealthIF::NEEDS_RECOVERY) {
|
||||
triggerEvent(TRYING_RECOVERY);
|
||||
recoveryState = RECOVERY_STARTED;
|
||||
recoveringDevice = iter;
|
||||
doStartTransition(targetMode, targetSubmode);
|
||||
} else {
|
||||
triggerEvent(CHILD_CHANGED_HEALTH);
|
||||
doStartTransition(mode, submode);
|
||||
}
|
||||
if (modeHelper.isForced()) {
|
||||
triggerEvent(FORCING_MODE, targetMode, targetSubmode);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AssemblyBase::handleChildrenTransition() {
|
||||
if (commandsOutstanding <= 0) {
|
||||
switch (internalState) {
|
||||
case STATE_NEED_SECOND_STEP:
|
||||
internalState = STATE_SECOND_STEP;
|
||||
commandChildren(targetMode, targetSubmode);
|
||||
return;
|
||||
case STATE_OVERWRITE_HEALTH: {
|
||||
internalState = STATE_SINGLE_STEP;
|
||||
ReturnValue_t result = commandChildren(mode, submode);
|
||||
if (result == NEED_SECOND_STEP) {
|
||||
internalState = STATE_NEED_SECOND_STEP;
|
||||
}
|
||||
return;
|
||||
}
|
||||
case STATE_NONE:
|
||||
//Valid state, used in recovery.
|
||||
case STATE_SINGLE_STEP:
|
||||
case STATE_SECOND_STEP:
|
||||
if (checkAndHandleRecovery()) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ReturnValue_t result = checkChildrenState();
|
||||
if (result == RETURN_OK) {
|
||||
handleModeReached();
|
||||
} else {
|
||||
handleModeTransitionFailed(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBase::handleModeReached() {
|
||||
internalState = STATE_NONE;
|
||||
setMode(targetMode, targetSubmode);
|
||||
}
|
||||
|
||||
void AssemblyBase::handleModeTransitionFailed(ReturnValue_t result) {
|
||||
//always accept transition to OFF, there is nothing we can do except sending an info event
|
||||
//In theory this should never happen, but we would risk an infinite loop otherwise
|
||||
if (targetMode == MODE_OFF) {
|
||||
triggerEvent(CHILD_PROBLEMS, result);
|
||||
internalState = STATE_NONE;
|
||||
setMode(targetMode, targetSubmode);
|
||||
} else {
|
||||
if (handleChildrenChangedHealth()) {
|
||||
//If any health change is pending, handle that first.
|
||||
return;
|
||||
}
|
||||
triggerEvent(MODE_TRANSITION_FAILED, result);
|
||||
startTransition(MODE_OFF, SUBMODE_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBase::sendHealthCommand(MessageQueueId_t sendTo,
|
||||
HealthState health) {
|
||||
CommandMessage command;
|
||||
HealthMessage::setHealthMessage(&command, HealthMessage::HEALTH_SET,
|
||||
health);
|
||||
if (commandQueue->sendMessage(sendTo, &command) == RETURN_OK) {
|
||||
commandsOutstanding++;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t AssemblyBase::checkChildrenState() {
|
||||
if (targetMode == MODE_OFF) {
|
||||
return checkChildrenStateOff();
|
||||
} else {
|
||||
return checkChildrenStateOn(targetMode, targetSubmode);
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t AssemblyBase::checkChildrenStateOff() {
|
||||
for (const auto& childIter: childrenMap) {
|
||||
if (checkChildOff(childIter.first) != RETURN_OK) {
|
||||
return NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE;
|
||||
}
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t AssemblyBase::checkChildOff(uint32_t objectId) {
|
||||
ChildInfo childInfo = childrenMap.find(objectId)->second;
|
||||
if (healthHelper.healthTable->isCommandable(objectId)) {
|
||||
if (childInfo.submode != SUBMODE_NONE) {
|
||||
return RETURN_FAILED;
|
||||
} else {
|
||||
if ((childInfo.mode != MODE_OFF)
|
||||
&& (childInfo.mode != DeviceHandlerIF::MODE_ERROR_ON)) {
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t AssemblyBase::checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t* msToReachTheMode) {
|
||||
|
||||
//always accept transition to OFF
|
||||
if (mode == MODE_OFF) {
|
||||
if (submode != SUBMODE_NONE) {
|
||||
return INVALID_SUBMODE;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
if ((mode != MODE_ON) && (mode != DeviceHandlerIF::MODE_NORMAL)) {
|
||||
return INVALID_MODE;
|
||||
}
|
||||
|
||||
if (internalState != STATE_NONE) {
|
||||
return IN_TRANSITION;
|
||||
}
|
||||
|
||||
return isModeCombinationValid(mode, submode);
|
||||
}
|
||||
|
||||
ReturnValue_t AssemblyBase::handleHealthReply(CommandMessage* message) {
|
||||
if (message->getCommand() == HealthMessage::HEALTH_INFO) {
|
||||
HealthState health = HealthMessage::getHealth(message);
|
||||
if (health != EXTERNAL_CONTROL) {
|
||||
updateChildChangedHealth(message->getSender(), true);
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
if (message->getCommand() == HealthMessage::REPLY_HEALTH_SET
|
||||
|| (message->getCommand() == CommandMessage::REPLY_REJECTED
|
||||
&& message->getParameter2() == HealthMessage::HEALTH_SET)) {
|
||||
if (isInTransition()) {
|
||||
commandsOutstanding--;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
||||
bool AssemblyBase::checkAndHandleRecovery() {
|
||||
switch (recoveryState) {
|
||||
case RECOVERY_STARTED:
|
||||
recoveryState = RECOVERY_WAIT;
|
||||
recoveryOffTimer.resetTimer();
|
||||
return true;
|
||||
case RECOVERY_WAIT:
|
||||
if (recoveryOffTimer.isBusy()) {
|
||||
return true;
|
||||
}
|
||||
triggerEvent(RECOVERY_STEP, 0);
|
||||
sendHealthCommand(recoveringDevice->second.commandQueue, HEALTHY);
|
||||
internalState = STATE_NONE;
|
||||
recoveryState = RECOVERY_ONGOING;
|
||||
//Don't check state!
|
||||
return true;
|
||||
case RECOVERY_ONGOING:
|
||||
triggerEvent(RECOVERY_STEP, 1);
|
||||
recoveryState = RECOVERY_ONGOING_2;
|
||||
recoveringDevice->second.healthChanged = false;
|
||||
//Device should be healthy again, so restart a transition.
|
||||
//Might be including second step, but that's already handled.
|
||||
doStartTransition(targetMode, targetSubmode);
|
||||
return true;
|
||||
case RECOVERY_ONGOING_2:
|
||||
triggerEvent(RECOVERY_DONE);
|
||||
//Now we're through, but not sure if it was successful.
|
||||
recoveryState = RECOVERY_IDLE;
|
||||
return false;
|
||||
case RECOVERY_IDLE:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBase::overwriteDeviceHealth(object_id_t objectId,
|
||||
HasHealthIF::HealthState oldHealth) {
|
||||
triggerEvent(OVERWRITING_HEALTH, objectId, oldHealth);
|
||||
internalState = STATE_OVERWRITE_HEALTH;
|
||||
modeHelper.setForced(true);
|
||||
sendHealthCommand(childrenMap[objectId].commandQueue, EXTERNAL_CONTROL);
|
||||
}
|
||||
|
Reference in New Issue
Block a user