From a404bc881ef08d4f7c6b741b6bbe4ac7025379ec Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 3 Feb 2021 13:28:31 +0100 Subject: [PATCH] removed hk switcher for now --- devicehandlers/DeviceHandlerBase.cpp | 2264 +++++++++++++------------- devicehandlers/DeviceHandlerBase.h | 2113 ++++++++++++------------ 2 files changed, 2188 insertions(+), 2189 deletions(-) diff --git a/devicehandlers/DeviceHandlerBase.cpp b/devicehandlers/DeviceHandlerBase.cpp index 897d0595..8650ec30 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/devicehandlers/DeviceHandlerBase.cpp @@ -17,460 +17,458 @@ object_id_t DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT; object_id_t DeviceHandlerBase::rawDataReceiverId = objects::NO_OBJECT; object_id_t DeviceHandlerBase::defaultFdirParentId = objects::NO_OBJECT; -DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, - object_id_t deviceCommunication, CookieIF * comCookie, - FailureIsolationBase* fdirInstance, size_t cmdQueueSize) : - SystemObject(setObjectId), mode(MODE_OFF), submode(SUBMODE_NONE), - wiretappingMode(OFF), storedRawData(StorageManagerIF::INVALID_ADDRESS), - deviceCommunicationId(deviceCommunication), comCookie(comCookie), - healthHelper(this,setObjectId), modeHelper(this), parameterHelper(this), - actionHelper(this, nullptr), poolManager(this, nullptr), - childTransitionFailure(RETURN_OK), fdirInstance(fdirInstance), - hkSwitcher(this), defaultFDIRUsed(fdirInstance == nullptr), - switchOffWasReported(false), childTransitionDelay(5000), - transitionSourceMode(_MODE_POWER_DOWN), - transitionSourceSubMode(SUBMODE_NONE) { - commandQueue = QueueFactory::instance()->createMessageQueue(cmdQueueSize, - MessageQueueMessage::MAX_MESSAGE_SIZE); - insertInCommandMap(RAW_COMMAND_ID); - cookieInfo.state = COOKIE_UNUSED; - cookieInfo.pendingCommand = deviceCommandMap.end(); - if (comCookie == nullptr) { - printWarningOrError(sif::OutputTypes::OUT_ERROR, "DeviceHandlerBase", - HasReturnvaluesIF::RETURN_FAILED, "Invalid cookie"); - } - if (this->fdirInstance == nullptr) { - this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, - defaultFdirParentId); - } +DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, + CookieIF * comCookie, FailureIsolationBase* fdirInstance, size_t cmdQueueSize): + SystemObject(setObjectId), mode(MODE_OFF), submode(SUBMODE_NONE), + wiretappingMode(OFF), storedRawData(StorageManagerIF::INVALID_ADDRESS), + deviceCommunicationId(deviceCommunication), comCookie(comCookie), + healthHelper(this,setObjectId), modeHelper(this), parameterHelper(this), + actionHelper(this, nullptr), poolManager(this, nullptr), + childTransitionFailure(RETURN_OK), fdirInstance(fdirInstance), + defaultFDIRUsed(fdirInstance == nullptr), + switchOffWasReported(false), childTransitionDelay(5000), + transitionSourceMode(_MODE_POWER_DOWN), + transitionSourceSubMode(SUBMODE_NONE) { + commandQueue = QueueFactory::instance()->createMessageQueue(cmdQueueSize, + MessageQueueMessage::MAX_MESSAGE_SIZE); + insertInCommandMap(RAW_COMMAND_ID); + cookieInfo.state = COOKIE_UNUSED; + cookieInfo.pendingCommand = deviceCommandMap.end(); + if (comCookie == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_ERROR, "DeviceHandlerBase", + HasReturnvaluesIF::RETURN_FAILED, "Invalid cookie"); + } + if (this->fdirInstance == nullptr) { + this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, + defaultFdirParentId); + } } void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) { - this->hkDestination = hkDestination; + this->hkDestination = hkDestination; } void DeviceHandlerBase::setThermalStateRequestPoolIds( - lp_id_t thermalStatePoolId, lp_id_t heaterRequestPoolId, - uint32_t thermalSetId) { - thermalSet = new DeviceHandlerThermalSet(this, thermalSetId, - thermalStatePoolId, heaterRequestPoolId); + lp_id_t thermalStatePoolId, lp_id_t heaterRequestPoolId, + uint32_t thermalSetId) { + thermalSet = new DeviceHandlerThermalSet(this, thermalSetId, + thermalStatePoolId, heaterRequestPoolId); } DeviceHandlerBase::~DeviceHandlerBase() { - delete comCookie; - if (defaultFDIRUsed) { - delete fdirInstance; - } - QueueFactory::instance()->deleteMessageQueue(commandQueue); + delete comCookie; + if (defaultFDIRUsed) { + delete fdirInstance; + } + QueueFactory::instance()->deleteMessageQueue(commandQueue); } ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) { - this->pstStep = counter; - this->lastStep = this->pstStep; + this->pstStep = counter; + this->lastStep = this->pstStep; - if (getComAction() == CommunicationAction::NOTHING) { - return HasReturnvaluesIF::RETURN_OK; - } + if (getComAction() == CommunicationAction::NOTHING) { + return HasReturnvaluesIF::RETURN_OK; + } - if (getComAction() == CommunicationAction::PERFORM_OPERATION) { - cookieInfo.state = COOKIE_UNUSED; - readCommandQueue(); - doStateMachine(); - checkSwitchState(); - decrementDeviceReplyMap(); - fdirInstance->checkForFailures(); - hkSwitcher.performOperation(); - performOperationHook(); - return RETURN_OK; - } + if (getComAction() == CommunicationAction::PERFORM_OPERATION) { + cookieInfo.state = COOKIE_UNUSED; + readCommandQueue(); + doStateMachine(); + checkSwitchState(); + decrementDeviceReplyMap(); + fdirInstance->checkForFailures(); + performOperationHook(); + return RETURN_OK; + } - if (mode == MODE_OFF) { - return RETURN_OK; - } + if (mode == MODE_OFF) { + return RETURN_OK; + } - switch (getComAction()) { - case CommunicationAction::SEND_WRITE: - if (cookieInfo.state == COOKIE_UNUSED) { - // if no external command was specified, build internal command. - buildInternalCommand(); - } - doSendWrite(); - break; - case CommunicationAction::GET_WRITE: - doGetWrite(); - break; - case CommunicationAction::SEND_READ: - doSendRead(); - break; - case CommunicationAction::GET_READ: - doGetRead(); - // This will be performed after datasets have been updated by the - // custom device implementation. - poolManager.performHkOperation(); - break; - default: - break; - } - return RETURN_OK; + switch (getComAction()) { + case CommunicationAction::SEND_WRITE: + if (cookieInfo.state == COOKIE_UNUSED) { + // if no external command was specified, build internal command. + buildInternalCommand(); + } + doSendWrite(); + break; + case CommunicationAction::GET_WRITE: + doGetWrite(); + break; + case CommunicationAction::SEND_READ: + doSendRead(); + break; + case CommunicationAction::GET_READ: + doGetRead(); + // This will be performed after datasets have been updated by the + // custom device implementation. + poolManager.performHkOperation(); + break; + default: + break; + } + return RETURN_OK; } ReturnValue_t DeviceHandlerBase::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != RETURN_OK) { - return result; - } + ReturnValue_t result = SystemObject::initialize(); + if (result != RETURN_OK) { + return result; + } - communicationInterface = objectManager->get( - deviceCommunicationId); - if (communicationInterface == nullptr) { - printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize", - ObjectManagerIF::CHILD_INIT_FAILED, - "Passed communication IF invalid"); - return ObjectManagerIF::CHILD_INIT_FAILED; - } + communicationInterface = objectManager->get( + deviceCommunicationId); + if (communicationInterface == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize", + ObjectManagerIF::CHILD_INIT_FAILED, + "Passed communication IF invalid"); + return ObjectManagerIF::CHILD_INIT_FAILED; + } - result = communicationInterface->initializeInterface(comCookie); - if (result != RETURN_OK) { - printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize", - ObjectManagerIF::CHILD_INIT_FAILED, - "ComIF initialization failed"); - return result; - } + result = communicationInterface->initializeInterface(comCookie); + if (result != RETURN_OK) { + printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize", + ObjectManagerIF::CHILD_INIT_FAILED, + "ComIF initialization failed"); + return result; + } - IPCStore = objectManager->get(objects::IPC_STORE); - if (IPCStore == nullptr) { - printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize", - ObjectManagerIF::CHILD_INIT_FAILED, "IPC Store not set up"); - return ObjectManagerIF::CHILD_INIT_FAILED; - } + IPCStore = objectManager->get(objects::IPC_STORE); + if (IPCStore == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize", + ObjectManagerIF::CHILD_INIT_FAILED, "IPC Store not set up"); + return ObjectManagerIF::CHILD_INIT_FAILED; + } - if(rawDataReceiverId != objects::NO_OBJECT) { - AcceptsDeviceResponsesIF *rawReceiver = objectManager->get< - AcceptsDeviceResponsesIF>(rawDataReceiverId); + if(rawDataReceiverId != objects::NO_OBJECT) { + AcceptsDeviceResponsesIF *rawReceiver = objectManager->get< + AcceptsDeviceResponsesIF>(rawDataReceiverId); - if (rawReceiver == nullptr) { - printWarningOrError(sif::OutputTypes::OUT_ERROR, - "initialize", ObjectManagerIF::CHILD_INIT_FAILED, - "Raw receiver object ID set but no valid object found."); + if (rawReceiver == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "initialize", ObjectManagerIF::CHILD_INIT_FAILED, + "Raw receiver object ID set but no valid object found."); #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Make sure the raw receiver object is set up properly" - " and implements AcceptsDeviceResponsesIF" << std::endl; + sif::error << "Make sure the raw receiver object is set up properly" + " and implements AcceptsDeviceResponsesIF" << std::endl; #else - sif::printError("Make sure the raw receiver object is set up " - "properly and implements AcceptsDeviceResponsesIF\n"); + sif::printError("Make sure the raw receiver object is set up " + "properly and implements AcceptsDeviceResponsesIF\n"); #endif - return ObjectManagerIF::CHILD_INIT_FAILED; - } - defaultRawReceiver = rawReceiver->getDeviceQueue(); - } + return ObjectManagerIF::CHILD_INIT_FAILED; + } + defaultRawReceiver = rawReceiver->getDeviceQueue(); + } - if(powerSwitcherId != objects::NO_OBJECT) { - powerSwitcher = objectManager->get(powerSwitcherId); - if (powerSwitcher == nullptr) { - printWarningOrError(sif::OutputTypes::OUT_ERROR, - "initialize", ObjectManagerIF::CHILD_INIT_FAILED, - "Power switcher set but no valid object found."); + if(powerSwitcherId != objects::NO_OBJECT) { + powerSwitcher = objectManager->get(powerSwitcherId); + if (powerSwitcher == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "initialize", ObjectManagerIF::CHILD_INIT_FAILED, + "Power switcher set but no valid object found."); #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Make sure the power switcher object is set up " - << "properly and implements PowerSwitchIF" << std::endl; + sif::error << "Make sure the power switcher object is set up " + << "properly and implements PowerSwitchIF" << std::endl; #else - sif::printError("Make sure the power switcher object is set up " - "properly and implements PowerSwitchIF\n"); + sif::printError("Make sure the power switcher object is set up " + "properly and implements PowerSwitchIF\n"); #endif - return ObjectManagerIF::CHILD_INIT_FAILED; - } - } + return ObjectManagerIF::CHILD_INIT_FAILED; + } + } - result = healthHelper.initialize(); - if (result != RETURN_OK) { - return result; - } + result = healthHelper.initialize(); + if (result != RETURN_OK) { + return result; + } - result = modeHelper.initialize(); - if (result != RETURN_OK) { - return result; - } - result = actionHelper.initialize(commandQueue); - if (result != RETURN_OK) { - return result; - } - result = fdirInstance->initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + result = modeHelper.initialize(); + if (result != RETURN_OK) { + return result; + } + result = actionHelper.initialize(commandQueue); + if (result != RETURN_OK) { + return result; + } + result = fdirInstance->initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } - result = parameterHelper.initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + result = parameterHelper.initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } - result = hkSwitcher.initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + result = hkSwitcher.initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } - result = poolManager.initialize(commandQueue); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + result = poolManager.initialize(commandQueue); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } - fillCommandAndReplyMap(); + fillCommandAndReplyMap(); - if(thermalSet != nullptr) { - //Set temperature target state to NON_OP. - result = thermalSet->read(); - if(result == HasReturnvaluesIF::RETURN_OK) { - thermalSet->heaterRequest.value = - ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; - thermalSet->heaterRequest.setValid(true); - thermalSet->commit(); - } + if(thermalSet != nullptr) { + //Set temperature target state to NON_OP. + result = thermalSet->read(); + if(result == HasReturnvaluesIF::RETURN_OK) { + thermalSet->heaterRequest.value = + ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; + thermalSet->heaterRequest.setValid(true); + thermalSet->commit(); + } - } + } - return RETURN_OK; + return RETURN_OK; } void DeviceHandlerBase::decrementDeviceReplyMap() { - for (std::map::iterator iter = - deviceReplyMap.begin(); iter != deviceReplyMap.end(); iter++) { - if (iter->second.delayCycles != 0) { - iter->second.delayCycles--; - if (iter->second.delayCycles == 0) { - if (iter->second.periodic) { - iter->second.delayCycles = iter->second.maxDelayCycles; - } - replyToReply(iter, TIMEOUT); - missedReply(iter->first); - } - } - } + for (std::map::iterator iter = + deviceReplyMap.begin(); iter != deviceReplyMap.end(); iter++) { + if (iter->second.delayCycles != 0) { + iter->second.delayCycles--; + if (iter->second.delayCycles == 0) { + if (iter->second.periodic) { + iter->second.delayCycles = iter->second.maxDelayCycles; + } + replyToReply(iter, TIMEOUT); + missedReply(iter->first); + } + } + } } void DeviceHandlerBase::readCommandQueue() { - if (dontCheckQueue()) { - return; - } + if (dontCheckQueue()) { + return; + } - CommandMessage command; - ReturnValue_t result = commandQueue->receiveMessage(&command); - if (result != RETURN_OK) { - return; - } + CommandMessage command; + ReturnValue_t result = commandQueue->receiveMessage(&command); + if (result != RETURN_OK) { + return; + } - result = healthHelper.handleHealthCommand(&command); - if (result == RETURN_OK) { - return; - } + result = healthHelper.handleHealthCommand(&command); + if (result == RETURN_OK) { + return; + } - result = modeHelper.handleModeCommand(&command); - if (result == RETURN_OK) { - return; - } + result = modeHelper.handleModeCommand(&command); + if (result == RETURN_OK) { + return; + } - result = actionHelper.handleActionMessage(&command); - if (result == RETURN_OK) { - return; - } + result = actionHelper.handleActionMessage(&command); + if (result == RETURN_OK) { + return; + } - result = parameterHelper.handleParameterMessage(&command); - if (result == RETURN_OK) { - return; - } + result = parameterHelper.handleParameterMessage(&command); + if (result == RETURN_OK) { + return; + } - result = poolManager.handleHousekeepingMessage(&command); - if (result == RETURN_OK) { - return; - } + result = poolManager.handleHousekeepingMessage(&command); + if (result == RETURN_OK) { + return; + } - result = handleDeviceHandlerMessage(&command); - if (result == RETURN_OK) { - return; - } + result = handleDeviceHandlerMessage(&command); + if (result == RETURN_OK) { + return; + } - result = letChildHandleMessage(&command); - if (result == RETURN_OK) { - return; - } + result = letChildHandleMessage(&command); + if (result == RETURN_OK) { + return; + } - replyReturnvalueToCommand(CommandMessage::UNKNOWN_COMMAND); + replyReturnvalueToCommand(CommandMessage::UNKNOWN_COMMAND); } void DeviceHandlerBase::doStateMachine() { - switch (mode) { - case _MODE_START_UP: - case _MODE_SHUT_DOWN: - case _MODE_TO_NORMAL: - case _MODE_TO_ON: - case _MODE_TO_RAW: { - Mode_t currentMode = mode; - callChildStatemachine(); - //Only do timeout if child did not change anything - if (mode != currentMode) { - break; - } - uint32_t currentUptime; - Clock::getUptime(¤tUptime); - if (currentUptime - timeoutStart >= childTransitionDelay) { - triggerEvent(MODE_TRANSITION_FAILED, childTransitionFailure, 0); - setMode(transitionSourceMode, transitionSourceSubMode); - break; - } - } - break; - case _MODE_POWER_DOWN: - commandSwitch(PowerSwitchIF::SWITCH_OFF); - setMode(_MODE_WAIT_OFF); - break; - case _MODE_POWER_ON: - commandSwitch(PowerSwitchIF::SWITCH_ON); - setMode(_MODE_WAIT_ON); - break; - case _MODE_WAIT_ON: { - uint32_t currentUptime; - Clock::getUptime(¤tUptime); - if (powerSwitcher != nullptr and currentUptime - timeoutStart >= - powerSwitcher->getSwitchDelayMs()) { - triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, - 0); - setMode(_MODE_POWER_DOWN); - callChildStatemachine(); - break; - } - ReturnValue_t switchState = getStateOfSwitches(); - if ((switchState == PowerSwitchIF::SWITCH_ON) - || (switchState == NO_SWITCH)) { - //NOTE: TransitionSourceMode and -SubMode are set by handleCommandedModeTransition - childTransitionFailure = CHILD_TIMEOUT; - setMode(_MODE_START_UP); - callChildStatemachine(); - } - } - break; - case _MODE_WAIT_OFF: { - uint32_t currentUptime; - Clock::getUptime(¤tUptime); + switch (mode) { + case _MODE_START_UP: + case _MODE_SHUT_DOWN: + case _MODE_TO_NORMAL: + case _MODE_TO_ON: + case _MODE_TO_RAW: { + Mode_t currentMode = mode; + callChildStatemachine(); + //Only do timeout if child did not change anything + if (mode != currentMode) { + break; + } + uint32_t currentUptime; + Clock::getUptime(¤tUptime); + if (currentUptime - timeoutStart >= childTransitionDelay) { + triggerEvent(MODE_TRANSITION_FAILED, childTransitionFailure, 0); + setMode(transitionSourceMode, transitionSourceSubMode); + break; + } + } + break; + case _MODE_POWER_DOWN: + commandSwitch(PowerSwitchIF::SWITCH_OFF); + setMode(_MODE_WAIT_OFF); + break; + case _MODE_POWER_ON: + commandSwitch(PowerSwitchIF::SWITCH_ON); + setMode(_MODE_WAIT_ON); + break; + case _MODE_WAIT_ON: { + uint32_t currentUptime; + Clock::getUptime(¤tUptime); + if (powerSwitcher != nullptr and currentUptime - timeoutStart >= + powerSwitcher->getSwitchDelayMs()) { + triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, + 0); + setMode(_MODE_POWER_DOWN); + callChildStatemachine(); + break; + } + ReturnValue_t switchState = getStateOfSwitches(); + if ((switchState == PowerSwitchIF::SWITCH_ON) + || (switchState == NO_SWITCH)) { + //NOTE: TransitionSourceMode and -SubMode are set by handleCommandedModeTransition + childTransitionFailure = CHILD_TIMEOUT; + setMode(_MODE_START_UP); + callChildStatemachine(); + } + } + break; + case _MODE_WAIT_OFF: { + uint32_t currentUptime; + Clock::getUptime(¤tUptime); - if(powerSwitcher == nullptr) { - setMode(MODE_OFF); - break; - } + if(powerSwitcher == nullptr) { + setMode(MODE_OFF); + break; + } - if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) { - triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, - 0); - setMode(MODE_ERROR_ON); - break; - } - ReturnValue_t switchState = getStateOfSwitches(); - if ((switchState == PowerSwitchIF::SWITCH_OFF) - || (switchState == NO_SWITCH)) { - setMode(_MODE_SWITCH_IS_OFF); - } - } - break; - case MODE_OFF: - doOffActivity(); - break; - case MODE_ON: - doOnActivity(); - break; - case MODE_RAW: - case MODE_NORMAL: - case MODE_ERROR_ON: - break; - case _MODE_SWITCH_IS_OFF: - setMode(MODE_OFF, SUBMODE_NONE); - break; - default: - triggerEvent(OBJECT_IN_INVALID_MODE, mode, submode); - setMode(_MODE_POWER_DOWN, 0); - break; - } + if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) { + triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, + 0); + setMode(MODE_ERROR_ON); + break; + } + ReturnValue_t switchState = getStateOfSwitches(); + if ((switchState == PowerSwitchIF::SWITCH_OFF) + || (switchState == NO_SWITCH)) { + setMode(_MODE_SWITCH_IS_OFF); + } + } + break; + case MODE_OFF: + doOffActivity(); + break; + case MODE_ON: + doOnActivity(); + break; + case MODE_RAW: + case MODE_NORMAL: + case MODE_ERROR_ON: + break; + case _MODE_SWITCH_IS_OFF: + setMode(MODE_OFF, SUBMODE_NONE); + break; + default: + triggerEvent(OBJECT_IN_INVALID_MODE, mode, submode); + setMode(_MODE_POWER_DOWN, 0); + break; + } } ReturnValue_t DeviceHandlerBase::isModeCombinationValid(Mode_t mode, - Submode_t submode) { - switch (mode) { - case MODE_OFF: - case MODE_ON: - case MODE_NORMAL: - case MODE_RAW: - if (submode == SUBMODE_NONE) { - return RETURN_OK; - } else { - return INVALID_SUBMODE; - } - default: - return HasModesIF::INVALID_MODE; - } + Submode_t submode) { + switch (mode) { + case MODE_OFF: + case MODE_ON: + case MODE_NORMAL: + case MODE_RAW: + if (submode == SUBMODE_NONE) { + return RETURN_OK; + } else { + return INVALID_SUBMODE; + } + default: + return HasModesIF::INVALID_MODE; + } } ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap( - DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, - LocalPoolDataSetBase* replyDataSet, size_t replyLen, bool periodic, - bool hasDifferentReplyId, DeviceCommandId_t replyId) { - //No need to check, as we may try to insert multiple times. - insertInCommandMap(deviceCommand); - if (hasDifferentReplyId) { - return insertInReplyMap(replyId, maxDelayCycles, - replyDataSet, replyLen, periodic); - } else { - return insertInReplyMap(deviceCommand, maxDelayCycles, - replyDataSet, replyLen, periodic); - } + DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, + LocalPoolDataSetBase* replyDataSet, size_t replyLen, bool periodic, + bool hasDifferentReplyId, DeviceCommandId_t replyId) { + //No need to check, as we may try to insert multiple times. + insertInCommandMap(deviceCommand); + if (hasDifferentReplyId) { + return insertInReplyMap(replyId, maxDelayCycles, + replyDataSet, replyLen, periodic); + } else { + return insertInReplyMap(deviceCommand, maxDelayCycles, + replyDataSet, replyLen, periodic); + } } ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId, - uint16_t maxDelayCycles, LocalPoolDataSetBase* dataSet, - size_t replyLen, bool periodic) { - DeviceReplyInfo info; - info.maxDelayCycles = maxDelayCycles; - info.periodic = periodic; - info.delayCycles = 0; - info.replyLen = replyLen; - info.dataSet = dataSet; - info.command = deviceCommandMap.end(); - auto resultPair = deviceReplyMap.emplace(replyId, info); - if (resultPair.second) { - return RETURN_OK; - } else { - return RETURN_FAILED; - } + uint16_t maxDelayCycles, LocalPoolDataSetBase* dataSet, + size_t replyLen, bool periodic) { + DeviceReplyInfo info; + info.maxDelayCycles = maxDelayCycles; + info.periodic = periodic; + info.delayCycles = 0; + info.replyLen = replyLen; + info.dataSet = dataSet; + info.command = deviceCommandMap.end(); + auto resultPair = deviceReplyMap.emplace(replyId, info); + if (resultPair.second) { + return RETURN_OK; + } else { + return RETURN_FAILED; + } } ReturnValue_t DeviceHandlerBase::insertInCommandMap( - DeviceCommandId_t deviceCommand) { - DeviceCommandInfo info; - info.expectedReplies = 0; - info.isExecuting = false; - info.sendReplyTo = NO_COMMANDER; - auto resultPair = deviceCommandMap.emplace(deviceCommand, info); - if (resultPair.second) { - return RETURN_OK; - } else { - return RETURN_FAILED; - } + DeviceCommandId_t deviceCommand) { + DeviceCommandInfo info; + info.expectedReplies = 0; + info.isExecuting = false; + info.sendReplyTo = NO_COMMANDER; + auto resultPair = deviceCommandMap.emplace(deviceCommand, info); + if (resultPair.second) { + return RETURN_OK; + } else { + return RETURN_FAILED; + } } ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceReply, - uint16_t delayCycles, uint16_t maxDelayCycles, bool periodic) { - auto replyIter = deviceReplyMap.find(deviceReply); - if (replyIter == deviceReplyMap.end()) { - triggerEvent(INVALID_DEVICE_COMMAND, deviceReply); - return RETURN_FAILED; - } else { - DeviceReplyInfo *info = &(replyIter->second); - if (maxDelayCycles != 0) { - info->maxDelayCycles = maxDelayCycles; - } - info->delayCycles = delayCycles; - info->periodic = periodic; - return RETURN_OK; - } + uint16_t delayCycles, uint16_t maxDelayCycles, bool periodic) { + auto replyIter = deviceReplyMap.find(deviceReply); + if (replyIter == deviceReplyMap.end()) { + triggerEvent(INVALID_DEVICE_COMMAND, deviceReply); + return RETURN_FAILED; + } else { + DeviceReplyInfo *info = &(replyIter->second); + if (maxDelayCycles != 0) { + info->maxDelayCycles = maxDelayCycles; + } + info->delayCycles = delayCycles; + info->periodic = periodic; + return RETURN_OK; + } } @@ -485,499 +483,501 @@ ReturnValue_t DeviceHandlerBase::setReplyDataset(DeviceCommandId_t replyId, } void DeviceHandlerBase::callChildStatemachine() { - if (mode == _MODE_START_UP) { - doStartUp(); - } else if (mode == _MODE_SHUT_DOWN) { - doShutDown(); - } else if (mode & TRANSITION_MODE_CHILD_ACTION_MASK) { - doTransition(transitionSourceMode, transitionSourceSubMode); - } + if (mode == _MODE_START_UP) { + doStartUp(); + } else if (mode == _MODE_SHUT_DOWN) { + doShutDown(); + } else if (mode & TRANSITION_MODE_CHILD_ACTION_MASK) { + doTransition(transitionSourceMode, transitionSourceSubMode); + } } void DeviceHandlerBase::setTransition(Mode_t modeTo, Submode_t submodeTo) { - triggerEvent(CHANGING_MODE, modeTo, submodeTo); - childTransitionDelay = getTransitionDelayMs(mode, modeTo); - transitionSourceMode = mode; - transitionSourceSubMode = submode; - childTransitionFailure = CHILD_TIMEOUT; + triggerEvent(CHANGING_MODE, modeTo, submodeTo); + childTransitionDelay = getTransitionDelayMs(mode, modeTo); + transitionSourceMode = mode; + transitionSourceSubMode = submode; + childTransitionFailure = CHILD_TIMEOUT; - // transitionTargetMode is set by setMode - setMode((modeTo | TRANSITION_MODE_CHILD_ACTION_MASK), submodeTo); + // transitionTargetMode is set by setMode + setMode((modeTo | TRANSITION_MODE_CHILD_ACTION_MASK), submodeTo); } void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) { - changeHK(mode, submode, false); - submode = newSubmode; - mode = newMode; - modeChanged(); - setNormalDatapoolEntriesInvalid(); - if (!isTransitionalMode()) { - modeHelper.modeChanged(newMode, newSubmode); - announceMode(false); - } - Clock::getUptime(&timeoutStart); + /* TODO: This will probably be done by the LocalDataPoolManager now */ + //changeHK(mode, submode, false); + submode = newSubmode; + mode = newMode; + modeChanged(); + setNormalDatapoolEntriesInvalid(); + if (!isTransitionalMode()) { + modeHelper.modeChanged(newMode, newSubmode); + announceMode(false); + } + Clock::getUptime(&timeoutStart); - if (mode == MODE_OFF and thermalSet != nullptr) { - ReturnValue_t result = thermalSet->read(); - if(result == HasReturnvaluesIF::RETURN_OK) { - if (thermalSet->heaterRequest.value != - ThermalComponentIF::STATE_REQUEST_IGNORE) { - thermalSet->heaterRequest.value = ThermalComponentIF:: - STATE_REQUEST_NON_OPERATIONAL; - } - thermalSet->heaterRequest.commit(PoolVariableIF::VALID); - } + if (mode == MODE_OFF and thermalSet != nullptr) { + ReturnValue_t result = thermalSet->read(); + if(result == HasReturnvaluesIF::RETURN_OK) { + if (thermalSet->heaterRequest.value != + ThermalComponentIF::STATE_REQUEST_IGNORE) { + thermalSet->heaterRequest.value = ThermalComponentIF:: + STATE_REQUEST_NON_OPERATIONAL; + } + thermalSet->heaterRequest.commit(PoolVariableIF::VALID); + } - } - changeHK(mode, submode, true); + } + /* TODO: This will probably be done by the LocalDataPoolManager now */ + //changeHK(mode, submode, true); } void DeviceHandlerBase::setMode(Mode_t newMode) { - setMode(newMode, submode); + setMode(newMode, submode); } void DeviceHandlerBase::replyReturnvalueToCommand(ReturnValue_t status, - uint32_t parameter) { - //This is actually the reply protocol for raw and misc DH commands. - if (status == RETURN_OK) { - CommandMessage reply(CommandMessage::REPLY_COMMAND_OK, 0, parameter); - commandQueue->reply(&reply); - } else { - CommandMessage reply(CommandMessage::REPLY_REJECTED, status, parameter); - commandQueue->reply(&reply); - } + uint32_t parameter) { + //This is actually the reply protocol for raw and misc DH commands. + if (status == RETURN_OK) { + CommandMessage reply(CommandMessage::REPLY_COMMAND_OK, 0, parameter); + commandQueue->reply(&reply); + } else { + CommandMessage reply(CommandMessage::REPLY_REJECTED, status, parameter); + commandQueue->reply(&reply); + } } void DeviceHandlerBase::replyToCommand(ReturnValue_t status, - uint32_t parameter) { - // Check if we reply to a raw command. - if (cookieInfo.pendingCommand->first == RAW_COMMAND_ID) { - if (status == NO_REPLY_EXPECTED) { - status = RETURN_OK; - } - replyReturnvalueToCommand(status, parameter); - // Always delete data from a raw command. - IPCStore->deleteData(storedRawData); - return; - } - // Check if we were externally commanded. - if (cookieInfo.pendingCommand->second.sendReplyTo != NO_COMMANDER) { - MessageQueueId_t queueId = cookieInfo.pendingCommand->second.sendReplyTo; - if (status == NO_REPLY_EXPECTED) { - actionHelper.finish(queueId, cookieInfo.pendingCommand->first, - RETURN_OK); - } else { - actionHelper.step(1, queueId, cookieInfo.pendingCommand->first, - status); - } - } + uint32_t parameter) { + // Check if we reply to a raw command. + if (cookieInfo.pendingCommand->first == RAW_COMMAND_ID) { + if (status == NO_REPLY_EXPECTED) { + status = RETURN_OK; + } + replyReturnvalueToCommand(status, parameter); + // Always delete data from a raw command. + IPCStore->deleteData(storedRawData); + return; + } + // Check if we were externally commanded. + if (cookieInfo.pendingCommand->second.sendReplyTo != NO_COMMANDER) { + MessageQueueId_t queueId = cookieInfo.pendingCommand->second.sendReplyTo; + if (status == NO_REPLY_EXPECTED) { + actionHelper.finish(queueId, cookieInfo.pendingCommand->first, + RETURN_OK); + } else { + actionHelper.step(1, queueId, cookieInfo.pendingCommand->first, + status); + } + } } void DeviceHandlerBase::replyToReply(DeviceReplyMap::iterator iter, - ReturnValue_t status) { - // No need to check if iter exists, as this is checked by callers. - // If someone else uses the method, add check. - if (iter->second.command == deviceCommandMap.end()) { - //Is most likely periodic reply. Silent return. - return; - } - // Check if more replies are expected. If so, do nothing. - DeviceCommandInfo* info = &(iter->second.command->second); - if (--info->expectedReplies == 0) { - // Check if it was transition or internal command. - // Don't send any replies in that case. - if (info->sendReplyTo != NO_COMMANDER) { - actionHelper.finish(info->sendReplyTo, iter->first, status); - } - info->isExecuting = false; - } + ReturnValue_t status) { + // No need to check if iter exists, as this is checked by callers. + // If someone else uses the method, add check. + if (iter->second.command == deviceCommandMap.end()) { + //Is most likely periodic reply. Silent return. + return; + } + // Check if more replies are expected. If so, do nothing. + DeviceCommandInfo* info = &(iter->second.command->second); + if (--info->expectedReplies == 0) { + // Check if it was transition or internal command. + // Don't send any replies in that case. + if (info->sendReplyTo != NO_COMMANDER) { + actionHelper.finish(info->sendReplyTo, iter->first, status); + } + info->isExecuting = false; + } } void DeviceHandlerBase::doSendWrite() { - if (cookieInfo.state == COOKIE_WRITE_READY) { + if (cookieInfo.state == COOKIE_WRITE_READY) { - ReturnValue_t result = communicationInterface->sendMessage(comCookie, - rawPacket, rawPacketLen); + ReturnValue_t result = communicationInterface->sendMessage(comCookie, + rawPacket, rawPacketLen); - if (result == RETURN_OK) { - cookieInfo.state = COOKIE_WRITE_SENT; - } else { - // always generate a failure event, so that FDIR knows what's up - triggerEvent(DEVICE_SENDING_COMMAND_FAILED, result, - cookieInfo.pendingCommand->first); - replyToCommand(result); - cookieInfo.state = COOKIE_UNUSED; - cookieInfo.pendingCommand->second.isExecuting = false; - } - } + if (result == RETURN_OK) { + cookieInfo.state = COOKIE_WRITE_SENT; + } else { + // always generate a failure event, so that FDIR knows what's up + triggerEvent(DEVICE_SENDING_COMMAND_FAILED, result, + cookieInfo.pendingCommand->first); + replyToCommand(result); + cookieInfo.state = COOKIE_UNUSED; + cookieInfo.pendingCommand->second.isExecuting = false; + } + } } void DeviceHandlerBase::doGetWrite() { - if (cookieInfo.state != COOKIE_WRITE_SENT) { - return; - } - cookieInfo.state = COOKIE_UNUSED; - ReturnValue_t result = communicationInterface->getSendSuccess(comCookie); - if (result == RETURN_OK) { - if (wiretappingMode == RAW) { - replyRawData(rawPacket, rawPacketLen, requestedRawTraffic, true); - } + if (cookieInfo.state != COOKIE_WRITE_SENT) { + return; + } + cookieInfo.state = COOKIE_UNUSED; + ReturnValue_t result = communicationInterface->getSendSuccess(comCookie); + if (result == RETURN_OK) { + if (wiretappingMode == RAW) { + replyRawData(rawPacket, rawPacketLen, requestedRawTraffic, true); + } - //We need to distinguish here, because a raw command never expects a reply. - //(Could be done in eRIRM, but then child implementations need to be careful. - result = enableReplyInReplyMap(cookieInfo.pendingCommand); - } else { - //always generate a failure event, so that FDIR knows what's up - triggerEvent(DEVICE_SENDING_COMMAND_FAILED, result, - cookieInfo.pendingCommand->first); - } - if (result != RETURN_OK) { - cookieInfo.pendingCommand->second.isExecuting = false; - } - replyToCommand(result); + //We need to distinguish here, because a raw command never expects a reply. + //(Could be done in eRIRM, but then child implementations need to be careful. + result = enableReplyInReplyMap(cookieInfo.pendingCommand); + } else { + //always generate a failure event, so that FDIR knows what's up + triggerEvent(DEVICE_SENDING_COMMAND_FAILED, result, + cookieInfo.pendingCommand->first); + } + if (result != RETURN_OK) { + cookieInfo.pendingCommand->second.isExecuting = false; + } + replyToCommand(result); } void DeviceHandlerBase::doSendRead() { - ReturnValue_t result; + ReturnValue_t result; - size_t requestLen = 0; - if(cookieInfo.pendingCommand != deviceCommandMap.end()) { - DeviceReplyIter iter = deviceReplyMap.find( - cookieInfo.pendingCommand->first); - if(iter != deviceReplyMap.end()) { - requestLen = iter->second.replyLen; - } - } + size_t requestLen = 0; + if(cookieInfo.pendingCommand != deviceCommandMap.end()) { + DeviceReplyIter iter = deviceReplyMap.find( + cookieInfo.pendingCommand->first); + if(iter != deviceReplyMap.end()) { + requestLen = iter->second.replyLen; + } + } - result = communicationInterface->requestReceiveMessage(comCookie, requestLen); + result = communicationInterface->requestReceiveMessage(comCookie, requestLen); - if (result == RETURN_OK) { - cookieInfo.state = COOKIE_READ_SENT; - } else { - triggerEvent(DEVICE_REQUESTING_REPLY_FAILED, result); - //We can't inform anyone, because we don't know which command was sent last. - //So, we need to wait for a timeout. - //but I think we can allow to ignore one missedReply. - ignoreMissedRepliesCount++; - cookieInfo.state = COOKIE_UNUSED; - } + if (result == RETURN_OK) { + cookieInfo.state = COOKIE_READ_SENT; + } else { + triggerEvent(DEVICE_REQUESTING_REPLY_FAILED, result); + //We can't inform anyone, because we don't know which command was sent last. + //So, we need to wait for a timeout. + //but I think we can allow to ignore one missedReply. + ignoreMissedRepliesCount++; + cookieInfo.state = COOKIE_UNUSED; + } } void DeviceHandlerBase::doGetRead() { - size_t receivedDataLen = 0; - uint8_t *receivedData = nullptr; + size_t receivedDataLen = 0; + uint8_t *receivedData = nullptr; - if (cookieInfo.state != COOKIE_READ_SENT) { - cookieInfo.state = COOKIE_UNUSED; - return; - } + if (cookieInfo.state != COOKIE_READ_SENT) { + cookieInfo.state = COOKIE_UNUSED; + return; + } - cookieInfo.state = COOKIE_UNUSED; + cookieInfo.state = COOKIE_UNUSED; - ReturnValue_t result = communicationInterface->readReceivedMessage( - comCookie, &receivedData, &receivedDataLen); + ReturnValue_t result = communicationInterface->readReceivedMessage( + comCookie, &receivedData, &receivedDataLen); - if (result != RETURN_OK) { - triggerEvent(DEVICE_REQUESTING_REPLY_FAILED, result); - //I think we can allow to ignore one missedReply. - ignoreMissedRepliesCount++; - return; - } + if (result != RETURN_OK) { + triggerEvent(DEVICE_REQUESTING_REPLY_FAILED, result); + //I think we can allow to ignore one missedReply. + ignoreMissedRepliesCount++; + return; + } - if (receivedDataLen == 0 or result == DeviceCommunicationIF::NO_REPLY_RECEIVED) - return; + if (receivedDataLen == 0 or result == DeviceCommunicationIF::NO_REPLY_RECEIVED) + return; - if (wiretappingMode == RAW) { - replyRawData(receivedData, receivedDataLen, requestedRawTraffic); - } + if (wiretappingMode == RAW) { + replyRawData(receivedData, receivedDataLen, requestedRawTraffic); + } - if (mode == MODE_RAW) { - if (defaultRawReceiver != MessageQueueIF::NO_QUEUE) { - replyRawReplyIfnotWiretapped(receivedData, receivedDataLen); - } - } - else { - parseReply(receivedData, receivedDataLen); - } + if (mode == MODE_RAW) { + if (defaultRawReceiver != MessageQueueIF::NO_QUEUE) { + replyRawReplyIfnotWiretapped(receivedData, receivedDataLen); + } + } + else { + parseReply(receivedData, receivedDataLen); + } } void DeviceHandlerBase::parseReply(const uint8_t* receivedData, - size_t receivedDataLen) { - ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; - DeviceCommandId_t foundId = DeviceHandlerIF::NO_COMMAND_ID; - size_t foundLen = 0; - // The loop may not execute more often than the number of received bytes - // (worst case). This approach avoids infinite loops due to buggy - // scanForReply routines. - uint32_t remainingLength = receivedDataLen; - for (uint32_t count = 0; count < receivedDataLen; count++) { - result = scanForReply(receivedData, remainingLength, &foundId, - &foundLen); - switch (result) { - case RETURN_OK: - handleReply(receivedData, foundId, foundLen); - if(foundLen == 0) { - printWarningOrError(sif::OutputTypes::OUT_WARNING, - "parseReply", ObjectManagerIF::CHILD_INIT_FAILED, - "Found length is one, parsing might be stuck"); - } - break; - case APERIODIC_REPLY: { - result = interpretDeviceReply(foundId, receivedData); - if (result != RETURN_OK) { - replyRawReplyIfnotWiretapped(receivedData, foundLen); - triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result, - foundId); - } - if(foundLen == 0) { - printWarningOrError(sif::OutputTypes::OUT_ERROR, - "parseReply", ObjectManagerIF::CHILD_INIT_FAILED, - "Power switcher set but no valid object found."); + size_t receivedDataLen) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + DeviceCommandId_t foundId = DeviceHandlerIF::NO_COMMAND_ID; + size_t foundLen = 0; + // The loop may not execute more often than the number of received bytes + // (worst case). This approach avoids infinite loops due to buggy + // scanForReply routines. + uint32_t remainingLength = receivedDataLen; + for (uint32_t count = 0; count < receivedDataLen; count++) { + result = scanForReply(receivedData, remainingLength, &foundId, + &foundLen); + switch (result) { + case RETURN_OK: + handleReply(receivedData, foundId, foundLen); + if(foundLen == 0) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "parseReply", ObjectManagerIF::CHILD_INIT_FAILED, + "Found length is one, parsing might be stuck"); + } + break; + case APERIODIC_REPLY: { + result = interpretDeviceReply(foundId, receivedData); + if (result != RETURN_OK) { + replyRawReplyIfnotWiretapped(receivedData, foundLen); + triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result, + foundId); + } + if(foundLen == 0) { + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "parseReply", ObjectManagerIF::CHILD_INIT_FAILED, + "Power switcher set but no valid object found."); #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "DeviceHandlerBase::parseReply: foundLen is 0!" - " Packet parsing will be stuck." << std::endl; + sif::warning << "DeviceHandlerBase::parseReply: foundLen is 0!" + " Packet parsing will be stuck." << std::endl; #endif - } - break; - } - case IGNORE_REPLY_DATA: - continue; - case IGNORE_FULL_PACKET: - return; - default: - // We need to wait for timeout.. don't know what command failed - // and who sent it. - replyRawReplyIfnotWiretapped(receivedData, foundLen); - triggerEvent(DEVICE_READING_REPLY_FAILED, result, foundLen); - break; - } - receivedData += foundLen; - if (remainingLength > foundLen) { - remainingLength -= foundLen; - } else { - return; - } - } + } + break; + } + case IGNORE_REPLY_DATA: + continue; + case IGNORE_FULL_PACKET: + return; + default: + // We need to wait for timeout.. don't know what command failed + // and who sent it. + replyRawReplyIfnotWiretapped(receivedData, foundLen); + triggerEvent(DEVICE_READING_REPLY_FAILED, result, foundLen); + break; + } + receivedData += foundLen; + if (remainingLength > foundLen) { + remainingLength -= foundLen; + } else { + return; + } + } } void DeviceHandlerBase::handleReply(const uint8_t* receivedData, - DeviceCommandId_t foundId, uint32_t foundLen) { - ReturnValue_t result; - DeviceReplyMap::iterator iter = deviceReplyMap.find(foundId); + DeviceCommandId_t foundId, uint32_t foundLen) { + ReturnValue_t result; + DeviceReplyMap::iterator iter = deviceReplyMap.find(foundId); - if (iter == deviceReplyMap.end()) { - replyRawReplyIfnotWiretapped(receivedData, foundLen); - triggerEvent(DEVICE_UNKNOWN_REPLY, foundId); - return; - } + if (iter == deviceReplyMap.end()) { + replyRawReplyIfnotWiretapped(receivedData, foundLen); + triggerEvent(DEVICE_UNKNOWN_REPLY, foundId); + return; + } - DeviceReplyInfo *info = &(iter->second); + DeviceReplyInfo *info = &(iter->second); - if (info->delayCycles != 0) { - result = interpretDeviceReply(foundId, receivedData); + if (info->delayCycles != 0) { + result = interpretDeviceReply(foundId, receivedData); - if(result == IGNORE_REPLY_DATA) { - return; - } + if(result == IGNORE_REPLY_DATA) { + return; + } - if (info->periodic) { - info->delayCycles = info->maxDelayCycles; - } - else { - info->delayCycles = 0; - } + if (info->periodic) { + info->delayCycles = info->maxDelayCycles; + } + else { + info->delayCycles = 0; + } - if (result != RETURN_OK) { - // Report failed interpretation to FDIR. - replyRawReplyIfnotWiretapped(receivedData, foundLen); - triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result, foundId); - } - replyToReply(iter, result); - } - else { - // Other completion failure messages are created by timeout. - // Powering down the device might take some time during which periodic - // replies may still come in. - if (mode != _MODE_WAIT_OFF) { - triggerEvent(DEVICE_UNREQUESTED_REPLY, foundId); - } - } + if (result != RETURN_OK) { + // Report failed interpretation to FDIR. + replyRawReplyIfnotWiretapped(receivedData, foundLen); + triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result, foundId); + } + replyToReply(iter, result); + } + else { + // Other completion failure messages are created by timeout. + // Powering down the device might take some time during which periodic + // replies may still come in. + if (mode != _MODE_WAIT_OFF) { + triggerEvent(DEVICE_UNREQUESTED_REPLY, foundId); + } + } } ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress, - uint8_t** data, uint32_t * len) { - size_t lenTmp; + uint8_t** data, uint32_t * len) { + size_t lenTmp; - if (IPCStore == nullptr) { - *data = nullptr; - *len = 0; - return RETURN_FAILED; - } - ReturnValue_t result = IPCStore->modifyData(storageAddress, data, &lenTmp); - if (result == RETURN_OK) { - *len = lenTmp; - return RETURN_OK; - } else { - triggerEvent(StorageManagerIF::GET_DATA_FAILED, result, - storageAddress.raw); - *data = nullptr; - *len = 0; - return result; - } + if (IPCStore == nullptr) { + *data = nullptr; + *len = 0; + return RETURN_FAILED; + } + ReturnValue_t result = IPCStore->modifyData(storageAddress, data, &lenTmp); + if (result == RETURN_OK) { + *len = lenTmp; + return RETURN_OK; + } else { + triggerEvent(StorageManagerIF::GET_DATA_FAILED, result, + storageAddress.raw); + *data = nullptr; + *len = 0; + return result; + } } void DeviceHandlerBase::replyRawData(const uint8_t *data, size_t len, - MessageQueueId_t sendTo, bool isCommand) { - if (IPCStore == nullptr or len == 0 or sendTo == MessageQueueIF::NO_QUEUE) { - return; - } - store_address_t address; - ReturnValue_t result = IPCStore->addData(&address, data, len); + MessageQueueId_t sendTo, bool isCommand) { + if (IPCStore == nullptr or len == 0 or sendTo == MessageQueueIF::NO_QUEUE) { + return; + } + store_address_t address; + ReturnValue_t result = IPCStore->addData(&address, data, len); - if (result != RETURN_OK) { - triggerEvent(StorageManagerIF::STORE_DATA_FAILED, result); - return; - } + if (result != RETURN_OK) { + triggerEvent(StorageManagerIF::STORE_DATA_FAILED, result); + return; + } - CommandMessage command; + CommandMessage command; - DeviceHandlerMessage::setDeviceHandlerRawReplyMessage(&command, - getObjectId(), address, isCommand); + DeviceHandlerMessage::setDeviceHandlerRawReplyMessage(&command, + getObjectId(), address, isCommand); - result = commandQueue->sendMessage(sendTo, &command); + result = commandQueue->sendMessage(sendTo, &command); - if (result != RETURN_OK) { - IPCStore->deleteData(address); - // Silently discard data, this indicates heavy TM traffic which - // should not be increased by additional events. - } + if (result != RETURN_OK) { + IPCStore->deleteData(address); + // Silently discard data, this indicates heavy TM traffic which + // should not be increased by additional events. + } } //Default child implementations DeviceHandlerIF::CommunicationAction DeviceHandlerBase::getComAction() { - switch (pstStep) { - case 0: - return CommunicationAction::PERFORM_OPERATION; - break; - case 1: - return CommunicationAction::SEND_WRITE; - break; - case 2: - return CommunicationAction::GET_WRITE; - break; - case 3: - return CommunicationAction::SEND_READ; - break; - case 4: - return CommunicationAction::GET_READ; - break; - default: - break; - } - return CommunicationAction::NOTHING; + switch (pstStep) { + case 0: + return CommunicationAction::PERFORM_OPERATION; + break; + case 1: + return CommunicationAction::SEND_WRITE; + break; + case 2: + return CommunicationAction::GET_WRITE; + break; + case 3: + return CommunicationAction::SEND_READ; + break; + case 4: + return CommunicationAction::GET_READ; + break; + default: + break; + } + return CommunicationAction::NOTHING; } MessageQueueId_t DeviceHandlerBase::getCommandQueue() const { - return commandQueue->getId(); + return commandQueue->getId(); } void DeviceHandlerBase::buildRawDeviceCommand(CommandMessage* commandMessage) { - storedRawData = DeviceHandlerMessage::getStoreAddress(commandMessage); - ReturnValue_t result = getStorageData(storedRawData, &rawPacket, - &rawPacketLen); - if (result != RETURN_OK) { - replyReturnvalueToCommand(result, RAW_COMMAND_ID); - storedRawData.raw = StorageManagerIF::INVALID_ADDRESS; - } else { - cookieInfo.pendingCommand = deviceCommandMap.find( - (DeviceCommandId_t) RAW_COMMAND_ID); - cookieInfo.pendingCommand->second.isExecuting = true; - cookieInfo.state = COOKIE_WRITE_READY; - } + storedRawData = DeviceHandlerMessage::getStoreAddress(commandMessage); + ReturnValue_t result = getStorageData(storedRawData, &rawPacket, + &rawPacketLen); + if (result != RETURN_OK) { + replyReturnvalueToCommand(result, RAW_COMMAND_ID); + storedRawData.raw = StorageManagerIF::INVALID_ADDRESS; + } else { + cookieInfo.pendingCommand = deviceCommandMap.find( + (DeviceCommandId_t) RAW_COMMAND_ID); + cookieInfo.pendingCommand->second.isExecuting = true; + cookieInfo.state = COOKIE_WRITE_READY; + } } void DeviceHandlerBase::commandSwitch(ReturnValue_t onOff) { - if(powerSwitcher == nullptr) { - return; - } - const uint8_t *switches; - uint8_t numberOfSwitches = 0; - ReturnValue_t result = getSwitches(&switches, &numberOfSwitches); - if (result == RETURN_OK) { - while (numberOfSwitches > 0) { - powerSwitcher->sendSwitchCommand(switches[numberOfSwitches - 1], - onOff); - numberOfSwitches--; - } - } + if(powerSwitcher == nullptr) { + return; + } + const uint8_t *switches; + uint8_t numberOfSwitches = 0; + ReturnValue_t result = getSwitches(&switches, &numberOfSwitches); + if (result == RETURN_OK) { + while (numberOfSwitches > 0) { + powerSwitcher->sendSwitchCommand(switches[numberOfSwitches - 1], + onOff); + numberOfSwitches--; + } + } } ReturnValue_t DeviceHandlerBase::getSwitches(const uint8_t **switches, - uint8_t *numberOfSwitches) { - return DeviceHandlerBase::NO_SWITCH; + uint8_t *numberOfSwitches) { + return DeviceHandlerBase::NO_SWITCH; } void DeviceHandlerBase::modeChanged(void) { } ReturnValue_t DeviceHandlerBase::enableReplyInReplyMap( - DeviceCommandMap::iterator command, uint8_t expectedReplies, - bool useAlternativeId, DeviceCommandId_t alternativeReply) { - DeviceReplyMap::iterator iter; - if (useAlternativeId) { - iter = deviceReplyMap.find(alternativeReply); - } else { - iter = deviceReplyMap.find(command->first); - } - if (iter != deviceReplyMap.end()) { - DeviceReplyInfo *info = &(iter->second); - info->delayCycles = info->maxDelayCycles; - info->command = command; - command->second.expectedReplies = expectedReplies; - return RETURN_OK; - } else { - return NO_REPLY_EXPECTED; - } + DeviceCommandMap::iterator command, uint8_t expectedReplies, + bool useAlternativeId, DeviceCommandId_t alternativeReply) { + DeviceReplyMap::iterator iter; + if (useAlternativeId) { + iter = deviceReplyMap.find(alternativeReply); + } else { + iter = deviceReplyMap.find(command->first); + } + if (iter != deviceReplyMap.end()) { + DeviceReplyInfo *info = &(iter->second); + info->delayCycles = info->maxDelayCycles; + info->command = command; + command->second.expectedReplies = expectedReplies; + return RETURN_OK; + } else { + return NO_REPLY_EXPECTED; + } } void DeviceHandlerBase::doTransition(Mode_t modeFrom, Submode_t subModeFrom) { - setMode(getBaseMode(mode)); + setMode(getBaseMode(mode)); } ReturnValue_t DeviceHandlerBase::getStateOfSwitches(void) { - if(powerSwitcher == nullptr) { - return NO_SWITCH; - } - uint8_t numberOfSwitches = 0; - const uint8_t *switches; + if(powerSwitcher == nullptr) { + return NO_SWITCH; + } + uint8_t numberOfSwitches = 0; + const uint8_t *switches; - ReturnValue_t result = getSwitches(&switches, &numberOfSwitches); - if ((result == RETURN_OK) && (numberOfSwitches != 0)) { - while (numberOfSwitches > 0) { - if (powerSwitcher->getSwitchState(switches[numberOfSwitches - 1]) - == PowerSwitchIF::SWITCH_OFF) { - return PowerSwitchIF::SWITCH_OFF; - } - numberOfSwitches--; - } - return PowerSwitchIF::SWITCH_ON; - } + ReturnValue_t result = getSwitches(&switches, &numberOfSwitches); + if ((result == RETURN_OK) && (numberOfSwitches != 0)) { + while (numberOfSwitches > 0) { + if (powerSwitcher->getSwitchState(switches[numberOfSwitches - 1]) + == PowerSwitchIF::SWITCH_OFF) { + return PowerSwitchIF::SWITCH_OFF; + } + numberOfSwitches--; + } + return PowerSwitchIF::SWITCH_ON; + } - return NO_SWITCH; + return NO_SWITCH; } Mode_t DeviceHandlerBase::getBaseMode(Mode_t transitionMode) { - // only child action special modes are handled, as a child should - // never see any base action modes - if (transitionMode == _MODE_START_UP) { - return _MODE_TO_ON; - } - if (transitionMode == _MODE_SHUT_DOWN) { - return _MODE_POWER_DOWN; - } - return transitionMode - & ~(TRANSITION_MODE_BASE_ACTION_MASK - | TRANSITION_MODE_CHILD_ACTION_MASK); + // only child action special modes are handled, as a child should + // never see any base action modes + if (transitionMode == _MODE_START_UP) { + return _MODE_TO_ON; + } + if (transitionMode == _MODE_SHUT_DOWN) { + return _MODE_POWER_DOWN; + } + return transitionMode + & ~(TRANSITION_MODE_BASE_ACTION_MASK + | TRANSITION_MODE_CHILD_ACTION_MASK); } //SHOULDDO: Allow transition from OFF to NORMAL to reduce complexity in assemblies. And, by the way, throw away DHB and write a new one: @@ -985,127 +985,127 @@ Mode_t DeviceHandlerBase::getBaseMode(Mode_t transitionMode) { // - Don't use modes for state transitions, reduce FSM (Finte State Machine) complexity. // - Modularization? ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode, - Submode_t commandedSubmode, uint32_t* msToReachTheMode) { - if (isTransitionalMode()) { - return IN_TRANSITION; - } - if ((mode == MODE_ERROR_ON) && (commandedMode != MODE_OFF)) { - return TRANS_NOT_ALLOWED; - } - if ((commandedMode == MODE_NORMAL) && (mode == MODE_OFF)) { - return TRANS_NOT_ALLOWED; - } + Submode_t commandedSubmode, uint32_t* msToReachTheMode) { + if (isTransitionalMode()) { + return IN_TRANSITION; + } + if ((mode == MODE_ERROR_ON) && (commandedMode != MODE_OFF)) { + return TRANS_NOT_ALLOWED; + } + if ((commandedMode == MODE_NORMAL) && (mode == MODE_OFF)) { + return TRANS_NOT_ALLOWED; + } - if ((commandedMode == MODE_ON) && (mode == MODE_OFF) - and (thermalSet != nullptr)) { - ReturnValue_t result = thermalSet->read(); - if(result == HasReturnvaluesIF::RETURN_OK) { - if((thermalSet->heaterRequest.value != - ThermalComponentIF::STATE_REQUEST_IGNORE) and (not - ThermalComponentIF::isOperational( - thermalSet->thermalState.value))) { - triggerEvent(ThermalComponentIF::TEMP_NOT_IN_OP_RANGE, - thermalSet->thermalState.value); - return NON_OP_TEMPERATURE; - } - } - } + if ((commandedMode == MODE_ON) && (mode == MODE_OFF) + and (thermalSet != nullptr)) { + ReturnValue_t result = thermalSet->read(); + if(result == HasReturnvaluesIF::RETURN_OK) { + if((thermalSet->heaterRequest.value != + ThermalComponentIF::STATE_REQUEST_IGNORE) and (not + ThermalComponentIF::isOperational( + thermalSet->thermalState.value))) { + triggerEvent(ThermalComponentIF::TEMP_NOT_IN_OP_RANGE, + thermalSet->thermalState.value); + return NON_OP_TEMPERATURE; + } + } + } - return isModeCombinationValid(commandedMode, commandedSubmode); + return isModeCombinationValid(commandedMode, commandedSubmode); } void DeviceHandlerBase::startTransition(Mode_t commandedMode, - Submode_t commandedSubmode) { - switch (commandedMode) { - case MODE_ON: - handleTransitionToOnMode(commandedMode, commandedSubmode); - break; - case MODE_OFF: - if (mode == MODE_OFF) { - triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); - setMode(_MODE_POWER_DOWN, commandedSubmode); - } else { - // already set the delay for the child transition - // so we don't need to call it twice - childTransitionDelay = getTransitionDelayMs(mode, _MODE_POWER_DOWN); - transitionSourceMode = _MODE_POWER_DOWN; - transitionSourceSubMode = commandedSubmode; - childTransitionFailure = CHILD_TIMEOUT; - setMode(_MODE_SHUT_DOWN, commandedSubmode); - triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); - } - break; - case MODE_RAW: - if (mode != MODE_OFF) { - setTransition(MODE_RAW, commandedSubmode); - } else { - setMode(MODE_RAW, commandedSubmode); - } - break; - case MODE_NORMAL: - if (mode != MODE_OFF) { - setTransition(MODE_NORMAL, commandedSubmode); - } else { - replyReturnvalueToCommand(HasModesIF::TRANS_NOT_ALLOWED); - } - break; - } + Submode_t commandedSubmode) { + switch (commandedMode) { + case MODE_ON: + handleTransitionToOnMode(commandedMode, commandedSubmode); + break; + case MODE_OFF: + if (mode == MODE_OFF) { + triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); + setMode(_MODE_POWER_DOWN, commandedSubmode); + } else { + // already set the delay for the child transition + // so we don't need to call it twice + childTransitionDelay = getTransitionDelayMs(mode, _MODE_POWER_DOWN); + transitionSourceMode = _MODE_POWER_DOWN; + transitionSourceSubMode = commandedSubmode; + childTransitionFailure = CHILD_TIMEOUT; + setMode(_MODE_SHUT_DOWN, commandedSubmode); + triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); + } + break; + case MODE_RAW: + if (mode != MODE_OFF) { + setTransition(MODE_RAW, commandedSubmode); + } else { + setMode(MODE_RAW, commandedSubmode); + } + break; + case MODE_NORMAL: + if (mode != MODE_OFF) { + setTransition(MODE_NORMAL, commandedSubmode); + } else { + replyReturnvalueToCommand(HasModesIF::TRANS_NOT_ALLOWED); + } + break; + } } void DeviceHandlerBase::handleTransitionToOnMode(Mode_t commandedMode, - Submode_t commandedSubmode) { - if (mode == MODE_OFF) { - transitionSourceMode = _MODE_POWER_DOWN; - transitionSourceSubMode = SUBMODE_NONE; - setMode(_MODE_POWER_ON, commandedSubmode); - // already set the delay for the child transition so we don't - // need to call it twice - childTransitionDelay = getTransitionDelayMs(_MODE_START_UP, - MODE_ON); - triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); - if(thermalSet != nullptr) { - ReturnValue_t result = thermalSet->read(); - if(result == HasReturnvaluesIF::RETURN_OK) { - if(thermalSet->heaterRequest != - ThermalComponentIF::STATE_REQUEST_IGNORE) { - thermalSet->heaterRequest = - ThermalComponentIF::STATE_REQUEST_OPERATIONAL; - thermalSet->commit(); - } - } - } - } else { - setTransition(MODE_ON, commandedSubmode); - } + Submode_t commandedSubmode) { + if (mode == MODE_OFF) { + transitionSourceMode = _MODE_POWER_DOWN; + transitionSourceSubMode = SUBMODE_NONE; + setMode(_MODE_POWER_ON, commandedSubmode); + // already set the delay for the child transition so we don't + // need to call it twice + childTransitionDelay = getTransitionDelayMs(_MODE_START_UP, + MODE_ON); + triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); + if(thermalSet != nullptr) { + ReturnValue_t result = thermalSet->read(); + if(result == HasReturnvaluesIF::RETURN_OK) { + if(thermalSet->heaterRequest != + ThermalComponentIF::STATE_REQUEST_IGNORE) { + thermalSet->heaterRequest = + ThermalComponentIF::STATE_REQUEST_OPERATIONAL; + thermalSet->commit(); + } + } + } + } else { + setTransition(MODE_ON, commandedSubmode); + } } void DeviceHandlerBase::getMode(Mode_t* mode, Submode_t* submode) { - *mode = this->mode; - *submode = this->submode; + *mode = this->mode; + *submode = this->submode; } void DeviceHandlerBase::setToExternalControl() { - healthHelper.setHealth(EXTERNAL_CONTROL); + healthHelper.setHealth(EXTERNAL_CONTROL); } void DeviceHandlerBase::announceMode(bool recursive) { - triggerEvent(MODE_INFO, mode, submode); + triggerEvent(MODE_INFO, mode, submode); } bool DeviceHandlerBase::dontCheckQueue() { - return false; + return false; } void DeviceHandlerBase::missedReply(DeviceCommandId_t id) { - if (ignoreMissedRepliesCount > 0) { - ignoreMissedRepliesCount--; - } else { - triggerEvent(DEVICE_MISSED_REPLY, id); - } + if (ignoreMissedRepliesCount > 0) { + ignoreMissedRepliesCount--; + } else { + triggerEvent(DEVICE_MISSED_REPLY, id); + } } HasHealthIF::HealthState DeviceHandlerBase::getHealth() { - return healthHelper.getHealth(); + return healthHelper.getHealth(); } ReturnValue_t DeviceHandlerBase::setHealth(HealthState health) { @@ -1114,92 +1114,92 @@ ReturnValue_t DeviceHandlerBase::setHealth(HealthState health) { } void DeviceHandlerBase::checkSwitchState() { - if ((mode == MODE_ON || mode == MODE_NORMAL)) { - //We only check in ON and NORMAL, ignore RAW and ERROR_ON. - ReturnValue_t result = getStateOfSwitches(); - if (result == PowerSwitchIF::SWITCH_OFF && !switchOffWasReported) { - triggerEvent(PowerSwitchIF::SWITCH_WENT_OFF); - switchOffWasReported = true; - } - } else { - switchOffWasReported = false; - } + if ((mode == MODE_ON || mode == MODE_NORMAL)) { + //We only check in ON and NORMAL, ignore RAW and ERROR_ON. + ReturnValue_t result = getStateOfSwitches(); + if (result == PowerSwitchIF::SWITCH_OFF && !switchOffWasReported) { + triggerEvent(PowerSwitchIF::SWITCH_WENT_OFF); + switchOffWasReported = true; + } + } else { + switchOffWasReported = false; + } } void DeviceHandlerBase::doOnActivity() { } ReturnValue_t DeviceHandlerBase::acceptExternalDeviceCommands() { - if ((mode != MODE_ON) && (mode != MODE_NORMAL)) { - return WRONG_MODE_FOR_COMMAND; - } - return RETURN_OK; + if ((mode != MODE_ON) && (mode != MODE_NORMAL)) { + return WRONG_MODE_FOR_COMMAND; + } + return RETURN_OK; } void DeviceHandlerBase::replyRawReplyIfnotWiretapped(const uint8_t* data, - size_t len) { - if ((wiretappingMode == RAW) - && (defaultRawReceiver == requestedRawTraffic)) { - //The raw packet was already sent by the wiretapping service - } else { - replyRawData(data, len, defaultRawReceiver); - } + size_t len) { + if ((wiretappingMode == RAW) + && (defaultRawReceiver == requestedRawTraffic)) { + //The raw packet was already sent by the wiretapping service + } else { + replyRawData(data, len, defaultRawReceiver); + } } ReturnValue_t DeviceHandlerBase::handleDeviceHandlerMessage( - CommandMessage * message) { - switch (message->getCommand()) { - case DeviceHandlerMessage::CMD_WIRETAPPING: - switch (DeviceHandlerMessage::getWiretappingMode(message)) { - case RAW: - wiretappingMode = RAW; - requestedRawTraffic = commandQueue->getLastPartner(); - break; - case TM: - wiretappingMode = TM; - requestedRawTraffic = commandQueue->getLastPartner(); - break; - case OFF: - wiretappingMode = OFF; - break; - default: - replyReturnvalueToCommand(INVALID_COMMAND_PARAMETER); - wiretappingMode = OFF; - return RETURN_OK; - } - replyReturnvalueToCommand(RETURN_OK); - return RETURN_OK; - case DeviceHandlerMessage::CMD_RAW: - if ((mode != MODE_RAW)) { - DeviceHandlerMessage::clear(message); - replyReturnvalueToCommand(WRONG_MODE_FOR_COMMAND); - } else { - buildRawDeviceCommand(message); - } - return RETURN_OK; - default: - return RETURN_FAILED; - } + CommandMessage * message) { + switch (message->getCommand()) { + case DeviceHandlerMessage::CMD_WIRETAPPING: + switch (DeviceHandlerMessage::getWiretappingMode(message)) { + case RAW: + wiretappingMode = RAW; + requestedRawTraffic = commandQueue->getLastPartner(); + break; + case TM: + wiretappingMode = TM; + requestedRawTraffic = commandQueue->getLastPartner(); + break; + case OFF: + wiretappingMode = OFF; + break; + default: + replyReturnvalueToCommand(INVALID_COMMAND_PARAMETER); + wiretappingMode = OFF; + return RETURN_OK; + } + replyReturnvalueToCommand(RETURN_OK); + return RETURN_OK; + case DeviceHandlerMessage::CMD_RAW: + if ((mode != MODE_RAW)) { + DeviceHandlerMessage::clear(message); + replyReturnvalueToCommand(WRONG_MODE_FOR_COMMAND); + } else { + buildRawDeviceCommand(message); + } + return RETURN_OK; + default: + return RETURN_FAILED; + } } void DeviceHandlerBase::setParentQueue(MessageQueueId_t parentQueueId) { - modeHelper.setParentQueue(parentQueueId); - healthHelper.setParentQueue(parentQueueId); + modeHelper.setParentQueue(parentQueueId); + healthHelper.setParentQueue(parentQueueId); } bool DeviceHandlerBase::isAwaitingReply() { - std::map::iterator iter; - for (iter = deviceReplyMap.begin(); iter != deviceReplyMap.end(); ++iter) { - if (iter->second.delayCycles != 0) { - return true; - } - } - return false; + std::map::iterator iter; + for (iter = deviceReplyMap.begin(); iter != deviceReplyMap.end(); ++iter) { + if (iter->second.delayCycles != 0) { + return true; + } + } + return false; } ReturnValue_t DeviceHandlerBase::letChildHandleMessage( - CommandMessage * message) { - return RETURN_FAILED; + CommandMessage * message) { + return RETURN_FAILED; } void DeviceHandlerBase::handleDeviceTM(SerializeIF *dataSet, DeviceCommandId_t replyId, @@ -1208,229 +1208,225 @@ void DeviceHandlerBase::handleDeviceTM(SerializeIF *dataSet, DeviceCommandId_t r return; } - DeviceReplyMap::iterator iter = deviceReplyMap.find(replyId); - if (iter == deviceReplyMap.end()) { - triggerEvent(DEVICE_UNKNOWN_REPLY, replyId); - return; - } + DeviceReplyMap::iterator iter = deviceReplyMap.find(replyId); + if (iter == deviceReplyMap.end()) { + triggerEvent(DEVICE_UNKNOWN_REPLY, replyId); + return; + } - /* Regular replies to a command */ - if (iter->second.command != deviceCommandMap.end()) - { - MessageQueueId_t queueId = iter->second.command->second.sendReplyTo; + /* Regular replies to a command */ + if (iter->second.command != deviceCommandMap.end()) + { + MessageQueueId_t queueId = iter->second.command->second.sendReplyTo; - if (queueId != NO_COMMANDER) { - /* This may fail, but we'll ignore the fault. */ - actionHelper.reportData(queueId, replyId, dataSet); - } + if (queueId != NO_COMMANDER) { + /* This may fail, but we'll ignore the fault. */ + actionHelper.reportData(queueId, replyId, dataSet); + } - /* This check should make sure we get any TM but don't get anything doubled. */ - if (wiretappingMode == TM && (requestedRawTraffic != queueId)) { + /* This check should make sure we get any TM but don't get anything doubled. */ + if (wiretappingMode == TM && (requestedRawTraffic != queueId)) { DeviceTmReportingWrapper wrapper(getObjectId(), replyId, dataSet); - actionHelper.reportData(requestedRawTraffic, replyId, &wrapper); - } + actionHelper.reportData(requestedRawTraffic, replyId, &wrapper); + } - else if (forceDirectTm and (defaultRawReceiver != queueId) and - (defaultRawReceiver != MessageQueueIF::NO_QUEUE)) - { - // hiding of sender needed so the service will handle it as - // unexpected Data, no matter what state (progress or completed) - // it is in - actionHelper.reportData(defaultRawReceiver, replyId, dataSet, true); - } - } - /* Unrequested or aperiodic replies */ - else - { - DeviceTmReportingWrapper wrapper(getObjectId(), replyId, dataSet); - if (wiretappingMode == TM) { - actionHelper.reportData(requestedRawTraffic, replyId, &wrapper); - } - if (forceDirectTm and defaultRawReceiver != MessageQueueIF::NO_QUEUE) - { -// sid_t setSid = sid_t(this->getObjectId(), replyId); -// LocalPoolDataSetBase* dataset = getDataSetHandle(setSid); -// if(dataset != nullptr) { -// poolManager.generateHousekeepingPacket(setSid, dataset, true); -// } + else if (forceDirectTm and (defaultRawReceiver != queueId) and + (defaultRawReceiver != MessageQueueIF::NO_QUEUE)) + { + // hiding of sender needed so the service will handle it as + // unexpected Data, no matter what state (progress or completed) + // it is in + actionHelper.reportData(defaultRawReceiver, replyId, dataSet, true); + } + } + /* Unrequested or aperiodic replies */ + else + { + DeviceTmReportingWrapper wrapper(getObjectId(), replyId, dataSet); + if (wiretappingMode == TM) { + actionHelper.reportData(requestedRawTraffic, replyId, &wrapper); + } + if (forceDirectTm and defaultRawReceiver != MessageQueueIF::NO_QUEUE) + { + // sid_t setSid = sid_t(this->getObjectId(), replyId); + // LocalPoolDataSetBase* dataset = getDataSetHandle(setSid); + // if(dataset != nullptr) { + // poolManager.generateHousekeepingPacket(setSid, dataset, true); + // } - // hiding of sender needed so the service will handle it as - // unexpected Data, no matter what state (progress or completed) - // it is in - actionHelper.reportData(defaultRawReceiver, replyId, &wrapper, true); - } - } + // hiding of sender needed so the service will handle it as + // unexpected Data, no matter what state (progress or completed) + // it is in + actionHelper.reportData(defaultRawReceiver, replyId, &wrapper, true); + } + } } ReturnValue_t DeviceHandlerBase::executeAction(ActionId_t actionId, - MessageQueueId_t commandedBy, const uint8_t* data, size_t size) { - ReturnValue_t result = acceptExternalDeviceCommands(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - DeviceCommandMap::iterator iter = deviceCommandMap.find(actionId); - if (iter == deviceCommandMap.end()) { - result = COMMAND_NOT_SUPPORTED; - } else if (iter->second.isExecuting) { - result = COMMAND_ALREADY_SENT; - } else { - result = buildCommandFromCommand(actionId, data, size); - } - if (result == RETURN_OK) { - iter->second.sendReplyTo = commandedBy; - iter->second.isExecuting = true; - cookieInfo.pendingCommand = iter; - cookieInfo.state = COOKIE_WRITE_READY; - } - return result; + MessageQueueId_t commandedBy, const uint8_t* data, size_t size) { + ReturnValue_t result = acceptExternalDeviceCommands(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + DeviceCommandMap::iterator iter = deviceCommandMap.find(actionId); + if (iter == deviceCommandMap.end()) { + result = COMMAND_NOT_SUPPORTED; + } else if (iter->second.isExecuting) { + result = COMMAND_ALREADY_SENT; + } else { + result = buildCommandFromCommand(actionId, data, size); + } + if (result == RETURN_OK) { + iter->second.sendReplyTo = commandedBy; + iter->second.isExecuting = true; + cookieInfo.pendingCommand = iter; + cookieInfo.state = COOKIE_WRITE_READY; + } + return result; } void DeviceHandlerBase::buildInternalCommand(void) { /* Neither raw nor direct could build a command */ - ReturnValue_t result = NOTHING_TO_SEND; - DeviceCommandId_t deviceCommandId = NO_COMMAND_ID; - if (mode == MODE_NORMAL) { - result = buildNormalDeviceCommand(&deviceCommandId); - if (result == BUSY) { - /* So we can track misconfigurations */ - printWarningOrError(sif::OutputTypes::OUT_WARNING, "buildInternalCommand", - HasReturnvaluesIF::RETURN_FAILED, "Busy."); - /* No need to report this */ - result = NOTHING_TO_SEND; - } - } - else if (mode == MODE_RAW) { - result = buildChildRawCommand(); - deviceCommandId = RAW_COMMAND_ID; - } - else if (mode & TRANSITION_MODE_CHILD_ACTION_MASK) { - result = buildTransitionDeviceCommand(&deviceCommandId); - } - else { - return; - } + ReturnValue_t result = NOTHING_TO_SEND; + DeviceCommandId_t deviceCommandId = NO_COMMAND_ID; + if (mode == MODE_NORMAL) { + result = buildNormalDeviceCommand(&deviceCommandId); + if (result == BUSY) { + /* So we can track misconfigurations */ + printWarningOrError(sif::OutputTypes::OUT_WARNING, "buildInternalCommand", + HasReturnvaluesIF::RETURN_FAILED, "Busy."); + /* No need to report this */ + result = NOTHING_TO_SEND; + } + } + else if (mode == MODE_RAW) { + result = buildChildRawCommand(); + deviceCommandId = RAW_COMMAND_ID; + } + else if (mode & TRANSITION_MODE_CHILD_ACTION_MASK) { + result = buildTransitionDeviceCommand(&deviceCommandId); + } + else { + return; + } - if (result == NOTHING_TO_SEND) { - return; - } - if (result == RETURN_OK) { - DeviceCommandMap::iterator iter = deviceCommandMap.find( - deviceCommandId); - if (iter == deviceCommandMap.end()) { - result = COMMAND_NOT_SUPPORTED; - } - else if (iter->second.isExecuting) { + if (result == NOTHING_TO_SEND) { + return; + } + if (result == RETURN_OK) { + DeviceCommandMap::iterator iter = deviceCommandMap.find( + deviceCommandId); + if (iter == deviceCommandMap.end()) { + result = COMMAND_NOT_SUPPORTED; + } + else if (iter->second.isExecuting) { #if FSFW_DISABLE_PRINTOUT == 0 - char output[36]; - sprintf(output, "Command 0x%08x is executing", - static_cast(deviceCommandId)); - // so we can track misconfigurations - printWarningOrError(sif::OutputTypes::OUT_WARNING, - "buildInternalCommand", - HasReturnvaluesIF::RETURN_FAILED, - output); + char output[36]; + sprintf(output, "Command 0x%08x is executing", + static_cast(deviceCommandId)); + // so we can track misconfigurations + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "buildInternalCommand", + HasReturnvaluesIF::RETURN_FAILED, + output); #endif - // this is an internal command, no need to report a failure here, - // missed reply will track if a reply is too late, otherwise, it's ok - return; - } else { - iter->second.sendReplyTo = NO_COMMANDER; - iter->second.isExecuting = true; - cookieInfo.pendingCommand = iter; - cookieInfo.state = COOKIE_WRITE_READY; - } - } - if (result != RETURN_OK) { - triggerEvent(DEVICE_BUILDING_COMMAND_FAILED, result, deviceCommandId); - } + // this is an internal command, no need to report a failure here, + // missed reply will track if a reply is too late, otherwise, it's ok + return; + } else { + iter->second.sendReplyTo = NO_COMMANDER; + iter->second.isExecuting = true; + cookieInfo.pendingCommand = iter; + cookieInfo.state = COOKIE_WRITE_READY; + } + } + if (result != RETURN_OK) { + triggerEvent(DEVICE_BUILDING_COMMAND_FAILED, result, deviceCommandId); + } } ReturnValue_t DeviceHandlerBase::buildChildRawCommand() { - return NOTHING_TO_SEND; + return NOTHING_TO_SEND; } uint8_t DeviceHandlerBase::getReplyDelayCycles( - DeviceCommandId_t deviceCommand) { - DeviceReplyMap::iterator iter = deviceReplyMap.find(deviceCommand); - if (iter == deviceReplyMap.end()) { - return 0; - } - return iter->second.delayCycles; + DeviceCommandId_t deviceCommand) { + DeviceReplyMap::iterator iter = deviceReplyMap.find(deviceCommand); + if (iter == deviceReplyMap.end()) { + return 0; + } + return iter->second.delayCycles; } Mode_t DeviceHandlerBase::getTransitionSourceMode() const { - return transitionSourceMode; + return transitionSourceMode; } Submode_t DeviceHandlerBase::getTransitionSourceSubMode() const { - return transitionSourceSubMode; + return transitionSourceSubMode; } void DeviceHandlerBase::triggerEvent(Event event, uint32_t parameter1, - uint32_t parameter2) { - fdirInstance->triggerEvent(event, parameter1, parameter2); + uint32_t parameter2) { + fdirInstance->triggerEvent(event, parameter1, parameter2); } void DeviceHandlerBase::forwardEvent(Event event, uint32_t parameter1, - uint32_t parameter2) const { - fdirInstance->triggerEvent(event, parameter1, parameter2); + uint32_t parameter2) const { + fdirInstance->triggerEvent(event, parameter1, parameter2); } void DeviceHandlerBase::doOffActivity() { } -ReturnValue_t DeviceHandlerBase::getParameter(uint8_t domainId, - uint8_t uniqueId, ParameterWrapper* parameterWrapper, - const ParameterWrapper* newValues, uint16_t startAtIndex) { - ReturnValue_t result = fdirInstance->getParameter(domainId, uniqueId, parameterWrapper, - newValues, startAtIndex); - if (result != INVALID_DOMAIN_ID) { - return result; - } - return INVALID_DOMAIN_ID; +ReturnValue_t DeviceHandlerBase::getParameter(uint8_t domainId, uint8_t uniqueId, + ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, + uint16_t startAtIndex) { + ReturnValue_t result = fdirInstance->getParameter(domainId, uniqueId, parameterWrapper, + newValues, startAtIndex); + if (result != INVALID_DOMAIN_ID) { + return result; + } + return INVALID_DOMAIN_ID; } bool DeviceHandlerBase::isTransitionalMode() { - return ((mode - & (TRANSITION_MODE_BASE_ACTION_MASK - | TRANSITION_MODE_CHILD_ACTION_MASK)) != 0); + return ((mode + & (TRANSITION_MODE_BASE_ACTION_MASK + | TRANSITION_MODE_CHILD_ACTION_MASK)) != 0); } bool DeviceHandlerBase::commandIsExecuting(DeviceCommandId_t commandId) { - auto iter = deviceCommandMap.find(commandId); - if (iter != deviceCommandMap.end()) { - return iter->second.isExecuting; - } else { - return false; - } + auto iter = deviceCommandMap.find(commandId); + if (iter != deviceCommandMap.end()) { + return iter->second.isExecuting; + } else { + return false; + } } -void DeviceHandlerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) { -} - void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task){ - executingTask = task; + executingTask = task; } -// Default implementations empty. void DeviceHandlerBase::debugInterface(uint8_t positionTracker, - object_id_t objectId, uint32_t parameter) {} + object_id_t objectId, uint32_t parameter) {} void DeviceHandlerBase::performOperationHook() { } ReturnValue_t DeviceHandlerBase::initializeLocalDataPool( - localpool::DataPool &localDataPoolMap, + localpool::DataPool &localDataPoolMap, LocalDataPoolManager& poolManager) { - if(thermalSet != nullptr) { - localDataPoolMap.emplace(thermalSet->thermalStatePoolId, - new PoolEntry); - localDataPoolMap.emplace(thermalSet->heaterRequestPoolId, - new PoolEntry); - } - return RETURN_OK; + if(thermalSet != nullptr) { + localDataPoolMap.emplace(thermalSet->thermalStatePoolId, + new PoolEntry); + localDataPoolMap.emplace(thermalSet->heaterRequestPoolId, + new PoolEntry); + } + return RETURN_OK; } ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() { @@ -1448,13 +1444,13 @@ ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() { } LocalPoolDataSetBase* DeviceHandlerBase::getDataSetHandle(sid_t sid) { - auto iter = deviceReplyMap.find(sid.ownerSetId); - if(iter != deviceReplyMap.end()) { - return iter->second.dataSet; - } - else { - return nullptr; - } + auto iter = deviceReplyMap.find(sid.ownerSetId); + if(iter != deviceReplyMap.end()) { + return iter->second.dataSet; + } + else { + return nullptr; + } } object_id_t DeviceHandlerBase::getObjectId() const { @@ -1477,55 +1473,55 @@ DeviceCommandId_t DeviceHandlerBase::getPendingCommand() const { } void DeviceHandlerBase::setNormalDatapoolEntriesInvalid() { - for(const auto& reply: deviceReplyMap) { - if(reply.second.dataSet != nullptr) { - reply.second.dataSet->setValidity(false, true); - } - } + for(const auto& reply: deviceReplyMap) { + if(reply.second.dataSet != nullptr) { + reply.second.dataSet->setValidity(false, true); + } + } } void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType, - const char *functionName, ReturnValue_t errorCode, - const char *errorPrint) { - if(errorPrint == nullptr) { - if(errorCode == ObjectManagerIF::CHILD_INIT_FAILED) { - errorPrint = "Initialization error"; - } - if(errorCode == HasReturnvaluesIF::RETURN_FAILED) { - if(errorType == sif::OutputTypes::OUT_WARNING) { - errorPrint = "Generic Warning"; - } - else { - errorPrint = "Generic Error"; - } - } - else { - errorPrint = "Unknown error"; - } - } + const char *functionName, ReturnValue_t errorCode, + const char *errorPrint) { + if(errorPrint == nullptr) { + if(errorCode == ObjectManagerIF::CHILD_INIT_FAILED) { + errorPrint = "Initialization error"; + } + if(errorCode == HasReturnvaluesIF::RETURN_FAILED) { + if(errorType == sif::OutputTypes::OUT_WARNING) { + errorPrint = "Generic Warning"; + } + else { + errorPrint = "Generic Error"; + } + } + else { + errorPrint = "Unknown error"; + } + } - if(errorType == sif::OutputTypes::OUT_WARNING) { + if(errorType == sif::OutputTypes::OUT_WARNING) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "DeviceHandlerBase::" << functionName << ": Object ID " - << std::hex << std::setw(8) << std::setfill('0') - << this->getObjectId() << " | " << errorPrint << std::dec - << std::setfill(' ') << std::endl; + sif::warning << "DeviceHandlerBase::" << functionName << ": Object ID " + << std::hex << std::setw(8) << std::setfill('0') + << this->getObjectId() << " | " << errorPrint << std::dec + << std::setfill(' ') << std::endl; #else - sif::printWarning("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n", - this->getObjectId(), errorPrint); + sif::printWarning("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n", + this->getObjectId(), errorPrint); #endif - } - else if(errorType == sif::OutputTypes::OUT_ERROR) { + } + else if(errorType == sif::OutputTypes::OUT_ERROR) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "DeviceHandlerBase::" << functionName << ": Object ID " - << std::hex << std::setw(8) << std::setfill('0') - << this->getObjectId() << " | " << errorPrint << std::dec - << std::setfill(' ') << std::endl; + sif::error << "DeviceHandlerBase::" << functionName << ": Object ID " + << std::hex << std::setw(8) << std::setfill('0') + << this->getObjectId() << " | " << errorPrint << std::dec + << std::setfill(' ') << std::endl; #else - sif::printError("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n", - this->getObjectId(), errorPrint); + sif::printError("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n", + this->getObjectId(), errorPrint); #endif - } + } } diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index e75d2729..1d4a4424 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -20,7 +20,6 @@ #include "../action/ActionHelper.h" #include "../health/HealthHelper.h" #include "../parameters/ParameterHelper.h" -#include "../datapool/HkSwitchHelper.h" #include "../datapoollocal/HasLocalDataPoolIF.h" #include "../datapoollocal/LocalDataPoolManager.h" @@ -80,114 +79,113 @@ class StorageManagerIF; * @ingroup devices */ class DeviceHandlerBase: public DeviceHandlerIF, - public HasReturnvaluesIF, - public ExecutableObjectIF, - public SystemObject, - public HasModesIF, - public HasHealthIF, - public HasActionsIF, - public ReceivesParameterMessagesIF, - public HasLocalDataPoolIF { - friend void (Factory::setStaticFrameworkObjectIds)(); +public HasReturnvaluesIF, +public ExecutableObjectIF, +public SystemObject, +public HasModesIF, +public HasHealthIF, +public HasActionsIF, +public ReceivesParameterMessagesIF, +public HasLocalDataPoolIF { + friend void (Factory::setStaticFrameworkObjectIds)(); public: - /** - * The constructor passes the objectId to the SystemObject(). - * - * @param setObjectId the ObjectId to pass to the SystemObject() Constructor - * @param deviceCommuncation Communcation Interface object which is used - * to implement communication functions - * @param comCookie This object will be passed to the communication inter- - * face and can contain user-defined information about the communication. - * @param fdirInstance - * @param cmdQueueSize - */ - DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, - CookieIF * comCookie, FailureIsolationBase* fdirInstance = nullptr, - size_t cmdQueueSize = 20); + /** + * The constructor passes the objectId to the SystemObject(). + * + * @param setObjectId the ObjectId to pass to the SystemObject() Constructor + * @param deviceCommuncation Communcation Interface object which is used + * to implement communication functions + * @param comCookie This object will be passed to the communication inter- + * face and can contain user-defined information about the communication. + * @param fdirInstance + * @param cmdQueueSize + */ + DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, + CookieIF * comCookie, FailureIsolationBase* fdirInstance = nullptr, + size_t cmdQueueSize = 20); - void setHkDestination(object_id_t hkDestination); + void setHkDestination(object_id_t hkDestination); - /** - * If the device handler is controlled by the FSFW thermal building blocks, - * this function should be called to initialize all required components. - * The device handler will then take care of creating local pool entries - * for the device thermal state and device heating request. - * Custom local pool IDs can be assigned as well. - * @param thermalStatePoolId - * @param thermalRequestPoolId - */ - void setThermalStateRequestPoolIds(lp_id_t thermalStatePoolId = - DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID, - lp_id_t thermalRequestPoolId = - DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID, - uint32_t thermalSetId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID); - /** - * @brief Helper function to ease device handler development. - * This will instruct the transition to MODE_ON immediately - * (leading to doStartUp() being called for the transition to the ON mode), - * so external mode commanding is not necessary anymore. - * - * This has to be called before the task is started! - * (e.g. in the task factory). This is only a helper function for - * development. Regular mode commanding should be performed by commanding - * the AssemblyBase or Subsystem objects resposible for the device handler. - */ - void setStartUpImmediately(); + /** + * If the device handler is controlled by the FSFW thermal building blocks, + * this function should be called to initialize all required components. + * The device handler will then take care of creating local pool entries + * for the device thermal state and device heating request. + * Custom local pool IDs can be assigned as well. + * @param thermalStatePoolId + * @param thermalRequestPoolId + */ + void setThermalStateRequestPoolIds(lp_id_t thermalStatePoolId = + DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID, + lp_id_t thermalRequestPoolId = + DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID, + uint32_t thermalSetId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID); + /** + * @brief Helper function to ease device handler development. + * This will instruct the transition to MODE_ON immediately + * (leading to doStartUp() being called for the transition to the ON mode), + * so external mode commanding is not necessary anymore. + * + * This has to be called before the task is started! + * (e.g. in the task factory). This is only a helper function for + * development. Regular mode commanding should be performed by commanding + * the AssemblyBase or Subsystem objects resposible for the device handler. + */ + void setStartUpImmediately(); - /** - * @brief This function is the device handler base core component and is - * called periodically. - * @details - * General sequence, showing where abstract virtual functions are called: - * If the State is SEND_WRITE: - * 1. Set the cookie state to COOKIE_UNUSED and read the command queue - * 2. Handles Device State Modes by calling doStateMachine(). - * This function calls callChildStatemachine() which calls the - * abstract functions doStartUp() and doShutDown() - * 3. Check switch states by calling checkSwitchStates() - * 4. Decrements counter for timeout of replies by calling - * decrementDeviceReplyMap() - * 5. Performs FDIR check for failures - * 6. Calls hkSwitcher.performOperation() - * 7. If the device mode is MODE_OFF, return RETURN_OK. + /** + * @brief This function is the device handler base core component and is + * called periodically. + * @details + * General sequence, showing where abstract virtual functions are called: + * If the State is SEND_WRITE: + * 1. Set the cookie state to COOKIE_UNUSED and read the command queue + * 2. Handles Device State Modes by calling doStateMachine(). + * This function calls callChildStatemachine() which calls the + * abstract functions doStartUp() and doShutDown() + * 3. Check switch states by calling checkSwitchStates() + * 4. Decrements counter for timeout of replies by calling + * decrementDeviceReplyMap() + * 5. Performs FDIR check for failures + * 6. If the device mode is MODE_OFF, return RETURN_OK. * Otherwise, perform the Action property and performs depending * on value specified by input value counter (incremented in PST). * The child class tells base class what to do by setting this value. - * - SEND_WRITE: Send data or commands to device by calling - * doSendWrite() which calls sendMessage function - * of #communicationInterface - * and calls buildInternalCommand if the cookie state is COOKIE_UNUSED - * - GET_WRITE: Get ackknowledgement for sending by calling doGetWrite() - * which calls getSendSuccess of #communicationInterface. - * Calls abstract functions scanForReply() and interpretDeviceReply(). - * - SEND_READ: Request reading data from device by calling doSendRead() - * which calls requestReceiveMessage of #communcationInterface - * - GET_READ: Access requested reading data by calling doGetRead() - * which calls readReceivedMessage of #communicationInterface - * @param counter Specifies which Action to perform - * @return RETURN_OK for successful execution - */ - virtual ReturnValue_t performOperation(uint8_t counter); + * - SEND_WRITE: Send data or commands to device by calling + * doSendWrite() which calls sendMessage function + * of #communicationInterface + * and calls buildInternalCommand if the cookie state is COOKIE_UNUSED + * - GET_WRITE: Get ackknowledgement for sending by calling doGetWrite() + * which calls getSendSuccess of #communicationInterface. + * Calls abstract functions scanForReply() and interpretDeviceReply(). + * - SEND_READ: Request reading data from device by calling doSendRead() + * which calls requestReceiveMessage of #communcationInterface + * - GET_READ: Access requested reading data by calling doGetRead() + * which calls readReceivedMessage of #communicationInterface + * @param counter Specifies which Action to perform + * @return RETURN_OK for successful execution + */ + virtual ReturnValue_t performOperation(uint8_t counter); - /** - * @brief Initializes the device handler - * @details - * Initialize Device Handler as system object and - * initializes all important helper classes. - * Calls fillCommandAndReplyMap(). - * @return - */ - virtual ReturnValue_t initialize(); + /** + * @brief Initializes the device handler + * @details + * Initialize Device Handler as system object and + * initializes all important helper classes. + * Calls fillCommandAndReplyMap(). + * @return + */ + virtual ReturnValue_t initialize(); - /** - * @brief Intialization steps performed after all tasks have been created. - * This function will be called by the executing task. - * @return - */ + /** + * @brief Intialization steps performed after all tasks have been created. + * This function will be called by the executing task. + * @return + */ virtual ReturnValue_t initializeAfterTaskCreation() override; - /** Destructor. */ - virtual ~DeviceHandlerBase(); + /** Destructor. */ + virtual ~DeviceHandlerBase(); /** @@ -222,1054 +220,1059 @@ public: protected: - /** - * @brief This is used to let the child class handle the transition from - * mode @c _MODE_START_UP to @c MODE_ON - * @details - * It is only called when the device handler is in mode @c _MODE_START_UP. - * That means, the device switch(es) are already set to on. - * Device handler commands are read and can be handled by the child class. - * If the child class handles a command, it should also send - * an reply accordingly. - * If an Command is not handled (ie #DeviceHandlerCommand is not @c CMD_NONE, - * the base class handles rejecting the command and sends a reply. - * The replies for mode transitions are handled by the base class. - * - * - If the device is started and ready for operation, the mode should be - * set to MODE_ON. It is possible to set the mode to _MODE_TO_ON to - * use the to on transition if available. - * - If the power-up fails, the mode should be set to _MODE_POWER_DOWN - * which will lead to the device being powered off. - * - If the device does not change the mode, the mode will be changed - * to _MODE_POWER_DOWN, after the timeout (from getTransitionDelay()) - * has passed. - * - * #transitionFailure can be set to a failure code indicating the reason - * for a failed transition - */ - virtual void doStartUp() = 0; + /** + * @brief This is used to let the child class handle the transition from + * mode @c _MODE_START_UP to @c MODE_ON + * @details + * It is only called when the device handler is in mode @c _MODE_START_UP. + * That means, the device switch(es) are already set to on. + * Device handler commands are read and can be handled by the child class. + * If the child class handles a command, it should also send + * an reply accordingly. + * If an Command is not handled (ie #DeviceHandlerCommand is not @c CMD_NONE, + * the base class handles rejecting the command and sends a reply. + * The replies for mode transitions are handled by the base class. + * + * - If the device is started and ready for operation, the mode should be + * set to MODE_ON. It is possible to set the mode to _MODE_TO_ON to + * use the to on transition if available. + * - If the power-up fails, the mode should be set to _MODE_POWER_DOWN + * which will lead to the device being powered off. + * - If the device does not change the mode, the mode will be changed + * to _MODE_POWER_DOWN, after the timeout (from getTransitionDelay()) + * has passed. + * + * #transitionFailure can be set to a failure code indicating the reason + * for a failed transition + */ + virtual void doStartUp() = 0; + /** + * @brief This is used to let the child class handle the transition + * from mode @c _MODE_SHUT_DOWN to @c _MODE_POWER_DOWN + * @details + * It is only called when the device handler is in mode @c _MODE_SHUT_DOWN. + * Device handler commands are read and can be handled by the child class. + * If the child class handles a command, it should also send an reply + * accordingly. + * If an Command is not handled (ie #DeviceHandlerCommand is not + * @c CMD_NONE, the base class handles rejecting the command and sends a + * reply. The replies for mode transitions are handled by the base class. + * + * - If the device ready to be switched off, + * the mode should be set to _MODE_POWER_DOWN. + * - If the device should not be switched off, the mode can be changed to + * _MODE_TO_ON (or MODE_ON if no transition is needed). + * - If the device does not change the mode, the mode will be changed to + * _MODE_POWER_DOWN, when the timeout (from getTransitionDelay()) + * has passed. + * + * #transitionFailure can be set to a failure code indicating the reason + * for a failed transition + */ + virtual void doShutDown() = 0; - /** - * @brief This is used to let the child class handle the transition - * from mode @c _MODE_SHUT_DOWN to @c _MODE_POWER_DOWN - * @details - * It is only called when the device handler is in mode @c _MODE_SHUT_DOWN. - * Device handler commands are read and can be handled by the child class. - * If the child class handles a command, it should also send an reply - * accordingly. - * If an Command is not handled (ie #DeviceHandlerCommand is not - * @c CMD_NONE, the base class handles rejecting the command and sends a - * reply. The replies for mode transitions are handled by the base class. - * - * - If the device ready to be switched off, - * the mode should be set to _MODE_POWER_DOWN. - * - If the device should not be switched off, the mode can be changed to - * _MODE_TO_ON (or MODE_ON if no transition is needed). - * - If the device does not change the mode, the mode will be changed to - * _MODE_POWER_DOWN, when the timeout (from getTransitionDelay()) - * has passed. - * - * #transitionFailure can be set to a failure code indicating the reason - * for a failed transition - */ - virtual void doShutDown() = 0; + /* Command handling */ + /** + * Build the device command to send for normal mode. + * + * This is only called in @c MODE_NORMAL. If multiple submodes for + * @c MODE_NORMAL are supported, different commands can built, + * depending on the submode. + * + * #rawPacket and #rawPacketLen must be set by this method to the + * packet to be sent. If variable command frequence is required, a counter + * can be used and the frequency in the reply map has to be set manually + * by calling updateReplyMap(). + * + * @param[out] id the device command id that has been built + * @return + * - @c RETURN_OK to send command after setting #rawPacket and + * #rawPacketLen. + * - @c NOTHING_TO_SEND when no command is to be sent. + * - Anything else triggers an even with the returnvalue as a parameter. + */ + virtual ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t * id) = 0; + /** + * Build the device command to send for a transitional mode. + * + * This is only called in @c _MODE_TO_NORMAL, @c _MODE_TO_ON, @c _MODE_TO_RAW, + * @c _MODE_START_UP and @c _MODE_SHUT_DOWN. So it is used by doStartUp() + * and doShutDown() as well as doTransition(), by setting those + * modes in the respective functions. + * + * A good idea is to implement a flag indicating a command has to be built + * and a variable containing the command number to be built + * and filling them in doStartUp(), doShutDown() and doTransition() so no + * modes have to be checked here. + * + * #rawPacket and #rawPacketLen must be set by this method to the + * packet to be sent. + * + * @param[out] id the device command id built + * @return + * - @c RETURN_OK when a command is to be sent + * - @c NOTHING_TO_SEND when no command is to be sent + * - Anything else triggers an even with the returnvalue as a parameter + */ + virtual ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t * id) = 0; + /** + * @brief Build a device command packet from data supplied by a direct + * command (PUS Service 8) + * @details + * This will be called if an functional command via PUS Service 8 is received and is + * the primary interface for functional command instead of #executeAction for users. The + * supplied ActionId_t action ID will be converted to a DeviceCommandId_t command ID after + * an internal check whether the action ID is a key in the device command map. + * + * #rawPacket and #rawPacketLen should be set by this method to the packet to be sent. + * The existence of the command in the command map and the command size check against 0 are + * done by the base class. + * + * @param deviceCommand The command to build, already checked against deviceCommandMap + * @param commandData Pointer to the data from the direct command + * @param commandDataLen Length of commandData + * @return + * - @c RETURN_OK to send command after #rawPacket and #rawPacketLen + * have been set. + * - @c HasActionsIF::EXECUTION_COMPLETE to generate a finish reply immediately. This can + * be used if no reply is expected. Otherwise, the developer can call #actionHelper.finish + * to finish the command handling. + * - Anything else triggers an event with the return code as a parameter as well as a + * step reply failed with the return code + */ + virtual ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, + const uint8_t * commandData, size_t commandDataLen) = 0; - /** - * Build the device command to send for normal mode. - * - * This is only called in @c MODE_NORMAL. If multiple submodes for - * @c MODE_NORMAL are supported, different commands can built, - * depending on the submode. - * - * #rawPacket and #rawPacketLen must be set by this method to the - * packet to be sent. If variable command frequence is required, a counter - * can be used and the frequency in the reply map has to be set manually - * by calling updateReplyMap(). - * - * @param[out] id the device command id that has been built - * @return - * - @c RETURN_OK to send command after setting #rawPacket and - * #rawPacketLen. - * - @c NOTHING_TO_SEND when no command is to be sent. - * - Anything else triggers an even with the returnvalue as a parameter. - */ - virtual ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t * id) = 0; + /* Reply handling */ + /** + * @brief Scans a buffer for a valid reply. + * @details + * This is used by the base class to check the data received for valid packets. + * It only checks if a valid packet starts at @c start. + * It also only checks the structural validy of the packet, + * e.g. checksums lengths and protocol data. No information check is done, + * e.g. range checks etc. + * + * Errors should be reported directly, the base class does NOT report any + * errors based on the return value of this function. + * + * @param start start of remaining buffer to be scanned + * @param len length of remaining buffer to be scanned + * @param[out] foundId the id of the data found in the buffer. + * @param[out] foundLen length of the data found. Is to be set in function, + * buffer is scanned at previous position + foundLen. + * @return + * - @c RETURN_OK a valid packet was found at @c start, @c foundLen is valid + * - @c RETURN_FAILED no reply could be found starting at @c start, + * implies @c foundLen is not valid, base class will call scanForReply() + * again with ++start + * - @c DeviceHandlerIF::INVALID_DATA a packet was found but it is invalid, + * e.g. checksum error, implies @c foundLen is valid, can be used to + * skip some bytes + * - @c DeviceHandlerIF::LENGTH_MISSMATCH @c len is invalid + * - @c DeviceHandlerIF::IGNORE_REPLY_DATA Ignore this specific part of + * the packet + * - @c DeviceHandlerIF::IGNORE_FULL_PACKET Ignore the packet + * - @c APERIODIC_REPLY if a valid reply is received that has not been + * requested by a command, but should be handled anyway + * (@see also fillCommandAndCookieMap() ) + */ + virtual ReturnValue_t scanForReply(const uint8_t *start, size_t len, + DeviceCommandId_t *foundId, size_t *foundLen) = 0; + /** + * @brief Interpret a reply from the device. + * @details + * This is called after scanForReply() found a valid packet, it can be + * assumed that the length and structure is valid. + * This routine extracts the data from the packet into a DataSet and then + * calls handleDeviceTM(), which either sends a TM packet or stores the + * data in the DataPool depending on whether it was an external command. + * No packet length is given, as it should be defined implicitly by the id. + * + * @param id the id found by scanForReply() + * @param packet + * @return + * - @c RETURN_OK when the reply was interpreted. + * - @c IGNORE_REPLY_DATA Ignore the reply and don't reset reply cycle + * counter. + * - @c RETURN_FAILED when the reply could not be interpreted, + * e.g. logical errors or range violations occurred + */ + virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) = 0; + MessageQueueId_t getCommanderId(DeviceCommandId_t replyId) const; + /** + * Helper function to get pending command. This is useful for devices + * like SPI sensors to identify the last sent command. + * This only returns the command sent in the last SEND_WRITE cycle. + * @return + */ + DeviceCommandId_t getPendingCommand() const; - /** - * Build the device command to send for a transitional mode. - * - * This is only called in @c _MODE_TO_NORMAL, @c _MODE_TO_ON, @c _MODE_TO_RAW, - * @c _MODE_START_UP and @c _MODE_SHUT_DOWN. So it is used by doStartUp() - * and doShutDown() as well as doTransition(), by setting those - * modes in the respective functions. - * - * A good idea is to implement a flag indicating a command has to be built - * and a variable containing the command number to be built - * and filling them in doStartUp(), doShutDown() and doTransition() so no - * modes have to be checked here. - * - * #rawPacket and #rawPacketLen must be set by this method to the - * packet to be sent. - * - * @param[out] id the device command id built - * @return - * - @c RETURN_OK when a command is to be sent - * - @c NOTHING_TO_SEND when no command is to be sent - * - Anything else triggers an even with the returnvalue as a parameter - */ - virtual ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t * id) = 0; + /* Specifying commands and replies */ + /** + * @brief Fill the #DeviceCommandMap and #DeviceReplyMap called by the #initialize + * of the base class + * @details + * This is used to let the base class know which replies are expected. + * There are different scenarios regarding this: + * + * - "Normal" commands. These are commands, that trigger a direct reply + * from the device. In this case, the id of the command should be added + * to the command map with a commandData_t where maxDelayCycles is set + * to the maximum expected number of PST cycles the reply will take. + * Then, scanForReply returns the id of the command and the base class + * can handle time-out and missing replies. + * + * - Periodic, unrequested replies. These are replies that, once enabled, + * are sent by the device on its own in a defined interval. + * In this case, the id of the reply or a placeholder id should be added + * to the deviceCommandMap with a commandData_t where maxDelayCycles is + * set to the maximum expected number of PST cycles between two replies + * (also a tolerance should be added, as an FDIR message will be + * generated if it is missed). + * From then on, the base class handles the reception. + * Then, scanForReply returns the id of the reply or the placeholder id + * and the base class will take care of checking that all replies are + * received and the interval is correct. + * + * - Aperiodic, unrequested replies. These are replies that are sent + * by the device without any preceding command and not in a defined + * interval. These are not entered in the deviceCommandMap but + * handled by returning @c APERIODIC_REPLY in scanForReply(). + */ + virtual void fillCommandAndReplyMap() = 0; + /** + * This is a helper method to facilitate inserting entries in the command map. + * @param deviceCommand Identifier of the command to add. + * @param maxDelayCycles The maximum number of delay cycles the command + * waits until it times out. + * @param replyLen Will be supplied to the requestReceiveMessage call of + * the communication interface. + * @param periodic Indicates if the command is periodic (i.e. it is sent + * by the device repeatedly without request) or not. Default is aperiodic (0) + * @return - @c RETURN_OK when the command was successfully inserted, + * - @c RETURN_FAILED else. + */ + ReturnValue_t insertInCommandAndReplyMap(DeviceCommandId_t deviceCommand, + uint16_t maxDelayCycles, + LocalPoolDataSetBase* replyDataSet = nullptr, + size_t replyLen = 0, bool periodic = false, + bool hasDifferentReplyId = false, DeviceCommandId_t replyId = 0); + /** + * @brief This is a helper method to insert replies in the reply map. + * @param deviceCommand Identifier of the reply to add. + * @param maxDelayCycles The maximum number of delay cycles the reply waits + * until it times out. + * @param periodic Indicates if the command is periodic (i.e. it is sent + * by the device repeatedly without request) or not. Default is aperiodic (0) + * @return - @c RETURN_OK when the command was successfully inserted, + * - @c RETURN_FAILED else. + */ + ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand, + uint16_t maxDelayCycles, LocalPoolDataSetBase* dataSet = nullptr, + size_t replyLen = 0, bool periodic = false); + /** + * @brief A simple command to add a command to the commandList. + * @param deviceCommand The command to add + * @return - @c RETURN_OK when the command was successfully inserted, + * - @c RETURN_FAILED else. + */ + ReturnValue_t insertInCommandMap(DeviceCommandId_t deviceCommand); + /** + * @brief This is a helper method to facilitate updating entries + * in the reply map. + * @param deviceCommand Identifier of the reply to update. + * @param delayCycles The current number of delay cycles to wait. + * As stated in #fillCommandAndCookieMap, to disable periodic commands, + * this is set to zero. + * @param maxDelayCycles The maximum number of delay cycles the reply waits + * until it times out. By passing 0 the entry remains untouched. + * @param periodic Indicates if the command is periodic (i.e. it is sent + * by the device repeatedly without request) or not.Default is aperiodic (0). + * Warning: The setting always overrides the value that was entered in the map. + * @return - @c RETURN_OK when the command was successfully inserted, + * - @c RETURN_FAILED else. + */ + ReturnValue_t updateReplyMapEntry(DeviceCommandId_t deviceReply, + uint16_t delayCycles, uint16_t maxDelayCycles, + bool periodic = false); + /** + * @brief Can be used to set the dataset corresponding to a reply ID manually. + * @details + * Used by the local data pool manager. + */ + ReturnValue_t setReplyDataset(DeviceCommandId_t replyId, + LocalPoolDataSetBase* dataset); - /** - * @brief Build a device command packet from data supplied by a direct - * command (PUS Service 8) - * @details - * This will be called if an functional command via PUS Service 8 is received and is - * the primary interface for functional command instead of #executeAction for users. The - * supplied ActionId_t action ID will be converted to a DeviceCommandId_t command ID after - * an internal check whether the action ID is a key in the device command map. - * - * #rawPacket and #rawPacketLen should be set by this method to the packet to be sent. - * The existence of the command in the command map and the command size check against 0 are - * done by the base class. - * - * @param deviceCommand The command to build, already checked against deviceCommandMap - * @param commandData Pointer to the data from the direct command - * @param commandDataLen Length of commandData - * @return - * - @c RETURN_OK to send command after #rawPacket and #rawPacketLen - * have been set. - * - @c HasActionsIF::EXECUTION_COMPLETE to generate a finish reply immediately. This can - * be used if no reply is expected. Otherwise, the developer can call #actionHelper.finish - * to finish the command handling. - * - Anything else triggers an event with the return code as a parameter as well as a - * step reply failed with the return code - */ - virtual ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, - const uint8_t * commandData, size_t commandDataLen) = 0; + /** + * Get the time needed to transit from modeFrom to modeTo. + * + * Used for the following transitions: + * modeFrom -> modeTo: + * MODE_ON -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] + * MODE_NORMAL -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] + * MODE_RAW -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] + * _MODE_START_UP -> MODE_ON (do not include time to set the switches, + * the base class got you covered) + * + * The default implementation returns 0 ! + * @param modeFrom + * @param modeTo + * @return time in ms + */ + virtual uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) = 0; - /** - * @brief Scans a buffer for a valid reply. - * @details - * This is used by the base class to check the data received for valid packets. - * It only checks if a valid packet starts at @c start. - * It also only checks the structural validy of the packet, - * e.g. checksums lengths and protocol data. No information check is done, - * e.g. range checks etc. - * - * Errors should be reported directly, the base class does NOT report any - * errors based on the return value of this function. - * - * @param start start of remaining buffer to be scanned - * @param len length of remaining buffer to be scanned - * @param[out] foundId the id of the data found in the buffer. - * @param[out] foundLen length of the data found. Is to be set in function, - * buffer is scanned at previous position + foundLen. - * @return - * - @c RETURN_OK a valid packet was found at @c start, @c foundLen is valid - * - @c RETURN_FAILED no reply could be found starting at @c start, - * implies @c foundLen is not valid, base class will call scanForReply() - * again with ++start - * - @c DeviceHandlerIF::INVALID_DATA a packet was found but it is invalid, - * e.g. checksum error, implies @c foundLen is valid, can be used to - * skip some bytes - * - @c DeviceHandlerIF::LENGTH_MISSMATCH @c len is invalid - * - @c DeviceHandlerIF::IGNORE_REPLY_DATA Ignore this specific part of - * the packet - * - @c DeviceHandlerIF::IGNORE_FULL_PACKET Ignore the packet - * - @c APERIODIC_REPLY if a valid reply is received that has not been - * requested by a command, but should be handled anyway - * (@see also fillCommandAndCookieMap() ) - */ - virtual ReturnValue_t scanForReply(const uint8_t *start, size_t len, - DeviceCommandId_t *foundId, size_t *foundLen) = 0; + /* Functions used by the local data pool manager */ + /** + * This function is used to initialize the local housekeeping pool + * entries. The default implementation leaves the pool empty. + * @param localDataPoolMap + * @return + */ + virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) override; + /** + * @brief Set all datapool variables that are update periodically in + * normal mode invalid + * @details + * The default implementation will set all datasets which have been added + * in #fillCommandAndReplyMap to invalid. It will also set all pool + * variables inside the dataset to invalid. The user can override this + * method optionally. + */ + virtual void setNormalDatapoolEntriesInvalid(); + /** + * @brief Get the dataset handle for a given SID. + * @details + * The default implementation will use the deviceCommandMap to look for the corresponding + * dataset handle. The user can override this function if this is not desired. + * @param sid + * @return + */ + virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; - /** - * @brief Interpret a reply from the device. - * @details - * This is called after scanForReply() found a valid packet, it can be - * assumed that the length and structure is valid. - * This routine extracts the data from the packet into a DataSet and then - * calls handleDeviceTM(), which either sends a TM packet or stores the - * data in the DataPool depending on whether it was an external command. - * No packet length is given, as it should be defined implicitly by the id. - * - * @param id the id found by scanForReply() - * @param packet - * @return - * - @c RETURN_OK when the reply was interpreted. - * - @c IGNORE_REPLY_DATA Ignore the reply and don't reset reply cycle - * counter. - * - @c RETURN_FAILED when the reply could not be interpreted, - * e.g. logical errors or range violations occurred - */ - virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, - const uint8_t *packet) = 0; + /* HasModesIF overrides */ + virtual void startTransition(Mode_t mode, Submode_t submode) override; + virtual void setToExternalControl() override; + virtual void announceMode(bool recursive) override; + /** + * @brief Set the device handler mode + * @details + * Sets #timeoutStart with every call Also sets #transitionTargetMode if necessary so + * transitional states can be entered from everywhere without breaking the state machine + * (which relies on a correct #transitionTargetMode). + * The submode is left unchanged. + * + * @param newMode + */ + void setMode(Mode_t newMode); + /** + * @overload + * @param submode + */ + void setMode(Mode_t newMode, Submode_t submode); + /** + * @brief Should be implemented properly by child class. + * @param mode + * @param submode + * @return + * - @c RETURN_OK if valid + * - @c RETURN_FAILED if invalid + */ + virtual ReturnValue_t isModeCombinationValid(Mode_t mode, + Submode_t submode); + /** + * @brief Notify child about mode change. + * @details + * Can be overriden to be used like a callback. + */ + virtual void modeChanged(); - /** - * @brief fill the #DeviceCommandMap and #DeviceReplyMap - * called by the initialize() of the base class - * @details - * This is used to let the base class know which replies are expected. - * There are different scenarios regarding this: - * - * - "Normal" commands. These are commands, that trigger a direct reply - * from the device. In this case, the id of the command should be added - * to the command map with a commandData_t where maxDelayCycles is set - * to the maximum expected number of PST cycles the reply will take. - * Then, scanForReply returns the id of the command and the base class - * can handle time-out and missing replies. - * - * - Periodic, unrequested replies. These are replies that, once enabled, - * are sent by the device on its own in a defined interval. - * In this case, the id of the reply or a placeholder id should be added - * to the deviceCommandMap with a commandData_t where maxDelayCycles is - * set to the maximum expected number of PST cycles between two replies - * (also a tolerance should be added, as an FDIR message will be - * generated if it is missed). - * From then on, the base class handles the reception. - * Then, scanForReply returns the id of the reply or the placeholder id - * and the base class will take care of checking that all replies are - * received and the interval is correct. - * - * - Aperiodic, unrequested replies. These are replies that are sent - * by the device without any preceding command and not in a defined - * interval. These are not entered in the deviceCommandMap but - * handled by returning @c APERIODIC_REPLY in scanForReply(). - */ - virtual void fillCommandAndReplyMap() = 0; + /* Power handling functions */ + /** + * Return the switches connected to the device. + * + * The default implementation returns one switch set in the ctor. + * + * @param[out] switches pointer to an array of switches + * @param[out] numberOfSwitches length of returned array + * @return + * - @c RETURN_OK if the parameters were set + * - @c RETURN_FAILED if no switches exist + */ + virtual ReturnValue_t getSwitches(const uint8_t **switches, + uint8_t *numberOfSwitches); - /** - * This is a helper method to facilitate inserting entries in the command map. - * @param deviceCommand Identifier of the command to add. - * @param maxDelayCycles The maximum number of delay cycles the command - * waits until it times out. - * @param replyLen Will be supplied to the requestReceiveMessage call of - * the communication interface. - * @param periodic Indicates if the command is periodic (i.e. it is sent - * by the device repeatedly without request) or not. Default is aperiodic (0) - * @return - @c RETURN_OK when the command was successfully inserted, - * - @c RETURN_FAILED else. - */ - ReturnValue_t insertInCommandAndReplyMap(DeviceCommandId_t deviceCommand, - uint16_t maxDelayCycles, - LocalPoolDataSetBase* replyDataSet = nullptr, - size_t replyLen = 0, bool periodic = false, - bool hasDifferentReplyId = false, DeviceCommandId_t replyId = 0); + /** + * @brief Helper function to report a missed reply + * @details Can be overwritten by children to act on missed replies or to fake reporting Id. + * @param id of the missed reply + */ + virtual void missedReply(DeviceCommandId_t id); - /** - * @brief This is a helper method to insert replies in the reply map. - * @param deviceCommand Identifier of the reply to add. - * @param maxDelayCycles The maximum number of delay cycles the reply waits - * until it times out. - * @param periodic Indicates if the command is periodic (i.e. it is sent - * by the device repeatedly without request) or not. Default is aperiodic (0) - * @return - @c RETURN_OK when the command was successfully inserted, - * - @c RETURN_FAILED else. - */ - ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand, - uint16_t maxDelayCycles, LocalPoolDataSetBase* dataSet = nullptr, - size_t replyLen = 0, bool periodic = false); - - /** - * @brief A simple command to add a command to the commandList. - * @param deviceCommand The command to add - * @return - @c RETURN_OK when the command was successfully inserted, - * - @c RETURN_FAILED else. - */ - ReturnValue_t insertInCommandMap(DeviceCommandId_t deviceCommand); - /** - * @brief This is a helper method to facilitate updating entries - * in the reply map. - * @param deviceCommand Identifier of the reply to update. - * @param delayCycles The current number of delay cycles to wait. - * As stated in #fillCommandAndCookieMap, to disable periodic commands, - * this is set to zero. - * @param maxDelayCycles The maximum number of delay cycles the reply waits - * until it times out. By passing 0 the entry remains untouched. - * @param periodic Indicates if the command is periodic (i.e. it is sent - * by the device repeatedly without request) or not.Default is aperiodic (0). - * Warning: The setting always overrides the value that was entered in the map. - * @return - @c RETURN_OK when the command was successfully inserted, - * - @c RETURN_FAILED else. - */ - ReturnValue_t updateReplyMapEntry(DeviceCommandId_t deviceReply, - uint16_t delayCycles, uint16_t maxDelayCycles, - bool periodic = false); - - ReturnValue_t setReplyDataset(DeviceCommandId_t replyId, - LocalPoolDataSetBase* dataset); - - /** - * @brief Can be implemented by child handler to - * perform debugging - * @details Example: Calling this in performOperation - * to track values like mode. - * @param positionTracker Provide the child handler a way to know - * where the debugInterface was called - * @param objectId Provide the child handler object Id to - * specify actions for spefic devices - * @param parameter Supply a parameter of interest - * Please delete all debugInterface calls in DHB after debugging is finished ! - */ - virtual void debugInterface(uint8_t positionTracker = 0, - object_id_t objectId = 0, uint32_t parameter = 0); - - /** - * Get the time needed to transit from modeFrom to modeTo. - * - * Used for the following transitions: - * modeFrom -> modeTo: - * MODE_ON -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] - * MODE_NORMAL -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] - * MODE_RAW -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] - * _MODE_START_UP -> MODE_ON (do not include time to set the switches, - * the base class got you covered) - * - * The default implementation returns 0 ! - * @param modeFrom - * @param modeTo - * @return time in ms - */ - virtual uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) = 0; - - /** - * Return the switches connected to the device. - * - * The default implementation returns one switch set in the ctor. - * - * @param[out] switches pointer to an array of switches - * @param[out] numberOfSwitches length of returned array - * @return - * - @c RETURN_OK if the parameters were set - * - @c RETURN_FAILED if no switches exist - */ - virtual ReturnValue_t getSwitches(const uint8_t **switches, - uint8_t *numberOfSwitches); - - /** - * This function is used to initialize the local housekeeping pool - * entries. The default implementation leaves the pool empty. - * @param localDataPoolMap - * @return - */ - virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, - LocalDataPoolManager& poolManager) override; - - /** - * Required for HasLocalDataPoolIF, return a handle to the local pool manager. - * @return - */ - LocalDataPoolManager* getHkManagerHandle() override; - - /** - * @brief Hook function for child handlers which is called once per - * performOperation(). Default implementation is empty. - */ - virtual void performOperationHook(); + /* Miscellaneous functions */ + /** + * @brief Hook function for child handlers which is called once per + * performOperation(). Default implementation is empty. + */ + virtual void performOperationHook(); + /** + * @brief Can be implemented by child handler to + * perform debugging + * @details Example: Calling this in performOperation + * to track values like mode. + * @param positionTracker Provide the child handler a way to know + * where the debugInterface was called + * @param objectId Provide the child handler object Id to + * specify actions for spefic devices + * @param parameter Supply a parameter of interest + * Please delete all debugInterface calls in DHB after debugging is finished ! + */ + virtual void debugInterface(uint8_t positionTracker = 0, + object_id_t objectId = 0, uint32_t parameter = 0); protected: - /** - * The Returnvalues id of this class, required by HasReturnvaluesIF - */ - static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE; - static const ReturnValue_t INVALID_CHANNEL = MAKE_RETURN_CODE(0xA0); - /* Return codes for scanForReply */ - static const ReturnValue_t APERIODIC_REPLY = MAKE_RETURN_CODE(0xB0); //!< This is used to specify for replies from a device which are not replies to requests - static const ReturnValue_t IGNORE_REPLY_DATA = MAKE_RETURN_CODE(0xB1); //!< Ignore parts of the received packet - static const ReturnValue_t IGNORE_FULL_PACKET = MAKE_RETURN_CODE(0xB2); //!< Ignore full received packet - /* Return codes for command building */ - static const ReturnValue_t NOTHING_TO_SEND = MAKE_RETURN_CODE(0xC0); //!< Return this if no command sending in required - static const ReturnValue_t COMMAND_MAP_ERROR = MAKE_RETURN_CODE(0xC2); - // Return codes for getSwitches */ - static const ReturnValue_t NO_SWITCH = MAKE_RETURN_CODE(0xD0); - /* Mode handling error Codes */ - static const ReturnValue_t CHILD_TIMEOUT = MAKE_RETURN_CODE(0xE0); - static const ReturnValue_t SWITCH_FAILED = MAKE_RETURN_CODE(0xE1); + static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE; - static const MessageQueueId_t NO_COMMANDER = 0; + static const ReturnValue_t INVALID_CHANNEL = MAKE_RETURN_CODE(0xA0); + /* Return codes for scanForReply */ + //! This is used to specify for replies from a device which are not replies to requests + static const ReturnValue_t APERIODIC_REPLY = MAKE_RETURN_CODE(0xB0); + //! Ignore parts of the received packet + static const ReturnValue_t IGNORE_REPLY_DATA = MAKE_RETURN_CODE(0xB1); + //! Ignore full received packet + static const ReturnValue_t IGNORE_FULL_PACKET = MAKE_RETURN_CODE(0xB2); + /* Return codes for command building */ + //! Return this if no command sending in required + static const ReturnValue_t NOTHING_TO_SEND = MAKE_RETURN_CODE(0xC0); + static const ReturnValue_t COMMAND_MAP_ERROR = MAKE_RETURN_CODE(0xC2); + // Return codes for getSwitches */ + static const ReturnValue_t NO_SWITCH = MAKE_RETURN_CODE(0xD0); + /* Mode handling error Codes */ + static const ReturnValue_t CHILD_TIMEOUT = MAKE_RETURN_CODE(0xE0); + static const ReturnValue_t SWITCH_FAILED = MAKE_RETURN_CODE(0xE1); - /** Pointer to the raw packet that will be sent.*/ - uint8_t *rawPacket = nullptr; - /** Size of the #rawPacket. */ - uint32_t rawPacketLen = 0; + static const MessageQueueId_t NO_COMMANDER = 0; - /** - * The mode the device handler is currently in. - * This should never be changed directly but only with setMode() - */ - Mode_t mode; - /** - * The submode the device handler is currently in. - * This should never be changed directly but only with setMode() - */ - Submode_t submode; + //! Pointer to the raw packet that will be sent. + uint8_t *rawPacket = nullptr; + //! Size of the #rawPacket. + uint32_t rawPacketLen = 0; - /** This is the counter value from performOperation(). */ - uint8_t pstStep = 0; - uint8_t lastStep = 0; - uint32_t pstIntervalMs = 0; + /** + * The mode the device handler is currently in. + * This should never be changed directly but only with setMode() + */ + Mode_t mode; + /** + * The submode the device handler is currently in. + * This should never be changed directly but only with setMode() + */ + Submode_t submode; - /** - * Wiretapping flag: - * - * indicates either that all raw messages to and from the device should be - * sent to #defaultRawReceiver - * or that all device TM should be downlinked to #defaultRawReceiver. - */ - enum WiretappingMode { - OFF = 0, RAW = 1, TM = 2 - } wiretappingMode; - /** - * @brief A message queue that accepts raw replies - * - * Statically initialized in initialize() to a configurable object. - * Used when there is no method of finding a recipient, ie raw mode and - * reporting erroneous replies - */ - MessageQueueId_t defaultRawReceiver = MessageQueueIF::NO_QUEUE; - store_address_t storedRawData; + /** This is the counter value from performOperation(). */ + uint8_t pstStep = 0; + uint8_t lastStep = 0; + uint32_t pstIntervalMs = 0; - /** - * @brief The message queue which wants to read all raw traffic - * If #isWiretappingActive all raw communication from and to the device - * will be sent to this queue - */ - MessageQueueId_t requestedRawTraffic = 0; + /** + * Wiretapping flag: + * + * indicates either that all raw messages to and from the device should be + * sent to #defaultRawReceiver + * or that all device TM should be downlinked to #defaultRawReceiver. + */ + enum WiretappingMode { + OFF = 0, RAW = 1, TM = 2 + } wiretappingMode; + /** + * @brief A message queue that accepts raw replies + * + * Statically initialized in initialize() to a configurable object. + * Used when there is no method of finding a recipient, ie raw mode and + * reporting erroneous replies + */ + MessageQueueId_t defaultRawReceiver = MessageQueueIF::NO_QUEUE; + store_address_t storedRawData; - /** - * Pointer to the IPCStore. - * This caches the pointer received from the objectManager in the constructor. - */ - StorageManagerIF *IPCStore = nullptr; - /** The comIF object ID is cached for the intialize() function */ - object_id_t deviceCommunicationId; - /** Communication object used for device communication */ - DeviceCommunicationIF * communicationInterface = nullptr; - /** Cookie used for communication */ - CookieIF * comCookie; + /** + * @brief The message queue which wants to read all raw traffic + * If #isWiretappingActive all raw communication from and to the device + * will be sent to this queue + */ + MessageQueueId_t requestedRawTraffic = 0; - /** Health helper for HasHealthIF */ - HealthHelper healthHelper; - /** Mode helper for HasModesIF */ - ModeHelper modeHelper; - /** Parameter helper for ReceivesParameterMessagesIF */ - ParameterHelper parameterHelper; - /** Action helper for HasActionsIF */ - ActionHelper actionHelper; - /** Housekeeping Manager */ - LocalDataPoolManager poolManager; + /** + * Pointer to the IPCStore. + * This caches the pointer received from the objectManager in the constructor. + */ + StorageManagerIF *IPCStore = nullptr; + /** The comIF object ID is cached for the intialize() function */ + object_id_t deviceCommunicationId; + /** Communication object used for device communication */ + DeviceCommunicationIF * communicationInterface = nullptr; + /** Cookie used for communication */ + CookieIF * comCookie; - /** - * @brief Information about commands - */ - struct DeviceCommandInfo { - //! Indicates if the command is already executing. - bool isExecuting; - //! Dynamic value to indicate how many replies are expected. - //! Inititated with 0. - uint8_t expectedReplies; - //! if this is != NO_COMMANDER, DHB was commanded externally and shall - //! report everything to commander. - MessageQueueId_t sendReplyTo; - }; - using DeviceCommandMap = std::map ; - /** - * Information about commands - */ - DeviceCommandMap deviceCommandMap; + /** Health helper for HasHealthIF */ + HealthHelper healthHelper; + /** Mode helper for HasModesIF */ + ModeHelper modeHelper; + /** Parameter helper for ReceivesParameterMessagesIF */ + ParameterHelper parameterHelper; + /** Action helper for HasActionsIF */ + ActionHelper actionHelper; + /** Housekeeping Manager */ + LocalDataPoolManager poolManager; - /** - * @brief Information about expected replies - * This is used to keep track of pending replies. - */ - struct DeviceReplyInfo { - //! The maximum number of cycles the handler should wait for a reply - //! to this command. - uint16_t maxDelayCycles; - //! The currently remaining cycles the handler should wait for a reply, - //! 0 means there is no reply expected - uint16_t delayCycles; - size_t replyLen = 0; //!< Expected size of the reply. - //! if this is !=0, the delayCycles will not be reset to 0 but to - //! maxDelayCycles - bool periodic = false; - //! The dataset used to access housekeeping data related to the - //! respective device reply. Will point to a dataset held by - //! the child handler (if one is specified) - LocalPoolDataSetBase* dataSet = nullptr; - //! The command that expects this reply. - DeviceCommandMap::iterator command; - }; + /** + * @brief Information about commands + */ + struct DeviceCommandInfo { + //! Indicates if the command is already executing. + bool isExecuting; + //! Dynamic value to indicate how many replies are expected. + //! Inititated with 0. + uint8_t expectedReplies; + //! if this is != NO_COMMANDER, DHB was commanded externally and shall + //! report everything to commander. + MessageQueueId_t sendReplyTo; + }; + using DeviceCommandMap = std::map ; + /** + * Information about commands + */ + DeviceCommandMap deviceCommandMap; - using DeviceReplyMap = std::map ; - using DeviceReplyIter = DeviceReplyMap::iterator; - /** - * This map is used to check and track correct reception of all replies. - * - * It has multiple use: - * - It stores the information on pending replies. If a command is sent, - * the DeviceCommandInfo.count is incremented. - * - It is used to time-out missing replies. If a command is sent, the - * DeviceCommandInfo.DelayCycles is set to MaxDelayCycles. - * - It is queried to check if a reply from the device can be interpreted. - * scanForReply() returns the id of the command a reply was found for. - * The reply is ignored in the following cases: - * - No entry for the returned id was found - * - The deviceReplyInfo.delayCycles is == 0 - */ - DeviceReplyMap deviceReplyMap; + /** + * @brief Information about expected replies + * This is used to keep track of pending replies. + */ + struct DeviceReplyInfo { + //! The maximum number of cycles the handler should wait for a reply + //! to this command. + uint16_t maxDelayCycles; + //! The currently remaining cycles the handler should wait for a reply, + //! 0 means there is no reply expected + uint16_t delayCycles; + size_t replyLen = 0; //!< Expected size of the reply. + //! if this is !=0, the delayCycles will not be reset to 0 but to + //! maxDelayCycles + bool periodic = false; + //! The dataset used to access housekeeping data related to the + //! respective device reply. Will point to a dataset held by + //! the child handler (if one is specified) + LocalPoolDataSetBase* dataSet = nullptr; + //! The command that expects this reply. + DeviceCommandMap::iterator command; + }; - //! The MessageQueue used to receive device handler commands - //! and to send replies. - MessageQueueIF* commandQueue = nullptr; + using DeviceReplyMap = std::map ; + using DeviceReplyIter = DeviceReplyMap::iterator; + /** + * This map is used to check and track correct reception of all replies. + * + * It has multiple use: + * - It stores the information on pending replies. If a command is sent, + * the DeviceCommandInfo.count is incremented. + * - It is used to time-out missing replies. If a command is sent, the + * DeviceCommandInfo.DelayCycles is set to MaxDelayCycles. + * - It is queried to check if a reply from the device can be interpreted. + * scanForReply() returns the id of the command a reply was found for. + * The reply is ignored in the following cases: + * - No entry for the returned id was found + * - The deviceReplyInfo.delayCycles is == 0 + */ + DeviceReplyMap deviceReplyMap; - DeviceHandlerThermalSet* thermalSet = nullptr; + //! The MessageQueue used to receive device handler commands + //! and to send replies. + MessageQueueIF* commandQueue = nullptr; - /** - * Optional Error code. Can be set in doStartUp(), doShutDown() and - * doTransition() to signal cause for Transition failure. - */ - ReturnValue_t childTransitionFailure; + DeviceHandlerThermalSet* thermalSet = nullptr; - /** Counts if communication channel lost a reply, so some missed - * replys can be ignored. */ - uint32_t ignoreMissedRepliesCount = 0; + /** + * Optional Error code. Can be set in doStartUp(), doShutDown() and + * doTransition() to signal cause for Transition failure. + */ + ReturnValue_t childTransitionFailure; - /** Pointer to the used FDIR instance. If not provided by child, - * default class is instantiated. */ - FailureIsolationBase* fdirInstance; + /** Counts if communication channel lost a reply, so some missed + * replys can be ignored. */ + uint32_t ignoreMissedRepliesCount = 0; - HkSwitchHelper hkSwitcher; + /** Pointer to the used FDIR instance. If not provided by child, + * default class is instantiated. */ + FailureIsolationBase* fdirInstance; - bool defaultFDIRUsed; //!< To correctly delete the default instance. + //! To correctly delete the default instance. + bool defaultFDIRUsed; - bool switchOffWasReported; //!< Indicates if SWITCH_WENT_OFF was already thrown. + //! Indicates if SWITCH_WENT_OFF was already thrown. + bool switchOffWasReported; - //! Pointer to the task which executes this component, is invalid - //! before setTaskIF was called. - PeriodicTaskIF* executingTask = nullptr; + /** Pointer to the task which executes this component, + is invalid before setTaskIF was called. */ + PeriodicTaskIF* executingTask = nullptr; - //!< Object which switches power on and off. - static object_id_t powerSwitcherId; + //! Object which switches power on and off. + static object_id_t powerSwitcherId; - //!< Object which receives RAW data by default. - static object_id_t rawDataReceiverId; + //! Object which receives RAW data by default. + static object_id_t rawDataReceiverId; - //!< Object which may be the root cause of an identified fault. - static object_id_t defaultFdirParentId; + //! Object which may be the root cause of an identified fault. + static object_id_t defaultFdirParentId; - /** - * @brief Set all datapool variables that are update periodically in - * normal mode invalid - * @details - * The default implementation will set all datasets which have been added - * in #fillCommandAndReplyMap to invalid. It will also set all pool - * variables inside the dataset to invalid. The user can override this - * method optionally. - */ - virtual void setNormalDatapoolEntriesInvalid(); + /** + * @brief Send a reply to a received device handler command. + * + * This also resets #DeviceHandlerCommand to 0. + * + * @param reply the reply type + * @param parameter parameter for the reply + */ + void replyReturnvalueToCommand(ReturnValue_t status, uint32_t parameter = 0); + /** + * TODO: Whats the difference between this and the upper command? + * @param status + * @param parameter + */ + void replyToCommand(ReturnValue_t status, uint32_t parameter = 0); - MessageQueueId_t getCommanderId(DeviceCommandId_t replyId) const; + /** + * Do the transition to the main modes (MODE_ON, MODE_NORMAL and MODE_RAW). + * + * If the transition is complete, the mode should be set to the target mode, + * which can be deduced from the current mode which is + * [_MODE_TO_ON, _MODE_TO_NORMAL, _MODE_TO_RAW] + * + * The intended target submode is already set. + * The origin submode can be read in subModeFrom. + * + * If the transition can not be completed, the child class can try to reach + * an working mode by setting the mode either directly + * or setting the mode to an transitional mode (TO_ON, TO_NORMAL, TO_RAW) + * if the device needs to be reconfigured. + * + * If nothing works, the child class can wait for the timeout and the base + * class will reset the mode to the mode where the transition + * originated from (the child should report the reason for the failed transition). + * + * The intended way to send commands is to set a flag (enum) indicating + * which command is to be sent here and then to check in + * buildTransitionCommand() for the flag. This flag can also be used by + * doStartUp() and doShutDown() to get a nice and clean implementation of + * buildTransitionCommand() without switching through modes. + * + * When the the condition for the completion of the transition is met, the + * mode can be set, for example in the scanForReply() function. + * + * The default implementation goes into the target mode directly. + * + * #transitionFailure can be set to a failure code indicating the reason + * for a failed transition + * + * @param modeFrom + * The mode the transition originated from: + * [MODE_ON, MODE_NORMAL, MODE_RAW and _MODE_POWER_DOWN (if the mode changed + * from _MODE_START_UP to _MODE_TO_ON)] + * @param subModeFrom the subMode of modeFrom + */ + virtual void doTransition(Mode_t modeFrom, Submode_t subModeFrom); - /** - * Helper function to get pending command. This is useful for devices - * like SPI sensors to identify the last sent command. - * This only returns the command sent in the last SEND_WRITE cycle. - * @return - */ - DeviceCommandId_t getPendingCommand() const; + /** + * Get the communication action for the current step. + * The step number can be read from #pstStep. + * @return The communication action to execute in this step + */ + virtual CommunicationAction getComAction(); - /** - * Helper function to report a missed reply - * - * Can be overwritten by children to act on missed replies or to fake - * reporting Id. - * - * @param id of the missed reply - */ - virtual void missedReply(DeviceCommandId_t id); + /** + * Checks state of switches in conjunction with mode and triggers an event + * if they don't fit. + */ + virtual void checkSwitchState(); - /** - * Send a reply to a received device handler command. - * - * This also resets #DeviceHandlerCommand to 0. - * - * @param reply the reply type - * @param parameter parameter for the reply - */ - void replyReturnvalueToCommand(ReturnValue_t status, - uint32_t parameter = 0); + /** + * Reserved for the rare case where a device needs to perform additional + * operation cyclically in OFF mode. + */ + virtual void doOffActivity(); - void replyToCommand(ReturnValue_t status, uint32_t parameter = 0); + /** + * Reserved for the rare case where a device needs to perform additional + * operation cyclically in ON mode. + */ + virtual void doOnActivity(); - /** - * Set the device handler mode - * - * Sets #timeoutStart with every call. - * - * Sets #transitionTargetMode if necessary so transitional states can be - * entered from everywhere without breaking the state machine - * (which relies on a correct #transitionTargetMode). - * - * The submode is left unchanged. - * - * @param newMode - */ - void setMode(Mode_t newMode); + /** + * Required for HasLocalDataPoolIF, return a handle to the local pool manager. + * @return + */ + LocalDataPoolManager* getHkManagerHandle() override; - /** - * @overload - * @param submode - */ - void setMode(Mode_t newMode, Submode_t submode); + /** + * Returns the delay cycle count of a reply. + * A count != 0 indicates that the command is already executed. + * @param deviceCommand The command to look for + * @return + * The current delay count. If the command does not exist (should never + * happen) it returns 0. + */ + uint8_t getReplyDelayCycles(DeviceCommandId_t deviceCommand); - /** - * Do the transition to the main modes (MODE_ON, MODE_NORMAL and MODE_RAW). - * - * If the transition is complete, the mode should be set to the target mode, - * which can be deduced from the current mode which is - * [_MODE_TO_ON, _MODE_TO_NORMAL, _MODE_TO_RAW] - * - * The intended target submode is already set. - * The origin submode can be read in subModeFrom. - * - * If the transition can not be completed, the child class can try to reach - * an working mode by setting the mode either directly - * or setting the mode to an transitional mode (TO_ON, TO_NORMAL, TO_RAW) - * if the device needs to be reconfigured. - * - * If nothing works, the child class can wait for the timeout and the base - * class will reset the mode to the mode where the transition - * originated from (the child should report the reason for the failed transition). - * - * The intended way to send commands is to set a flag (enum) indicating - * which command is to be sent here and then to check in - * buildTransitionCommand() for the flag. This flag can also be used by - * doStartUp() and doShutDown() to get a nice and clean implementation of - * buildTransitionCommand() without switching through modes. - * - * When the the condition for the completion of the transition is met, the - * mode can be set, for example in the scanForReply() function. - * - * The default implementation goes into the target mode directly. - * - * #transitionFailure can be set to a failure code indicating the reason - * for a failed transition - * - * @param modeFrom - * The mode the transition originated from: - * [MODE_ON, MODE_NORMAL, MODE_RAW and _MODE_POWER_DOWN (if the mode changed - * from _MODE_START_UP to _MODE_TO_ON)] - * @param subModeFrom the subMode of modeFrom - */ - virtual void doTransition(Mode_t modeFrom, Submode_t subModeFrom); + /** + * Calls replyRawData() with #defaultRawReceiver, but checks if wiretapping + * is active and if so, does not send the data as the wiretapping will have + * sent it already + */ + void replyRawReplyIfnotWiretapped(const uint8_t *data, size_t len); - /** - * @param mode - * @param submode - * @return - * - @c RETURN_OK if valid - * - @c RETURN_FAILED if invalid - */ - virtual ReturnValue_t isModeCombinationValid(Mode_t mode, - Submode_t submode); + /** + * Enable the reply checking for a command + * + * Is only called, if the command was sent (i.e. the getWriteReply was + * successful). Must ensure that all replies are activated and correctly + * linked to the command that initiated it. + * The default implementation looks for a reply with the same id as the + * command id in the replyMap or uses the alternativeReplyId if flagged so. + * When found, copies maxDelayCycles to delayCycles in the reply information + * and sets the command to expect one reply. + * + * Can be overwritten by the child, if a command activates multiple replies + * or replyId differs from commandId. + * Notes for child implementations: + * - If the command was not found in the reply map, + * NO_REPLY_EXPECTED MUST be returned. + * - A failure code may be returned if something went fundamentally wrong. + * + * @param deviceCommand + * @return - RETURN_OK if a reply was activated. + * - NO_REPLY_EXPECTED if there was no reply found. This is not an + * error case as many commands do not expect a reply. + */ + virtual ReturnValue_t enableReplyInReplyMap(DeviceCommandMap::iterator cmd, + uint8_t expectedReplies = 1, bool useAlternateId = false, + DeviceCommandId_t alternateReplyID = 0); - /** - * Get the communication action for the current step. - * The step number can be read from #pstStep. - * @return The communication action to execute in this step - */ - virtual CommunicationAction getComAction(); + /** + * @brief Build the device command to send for raw mode. + * @details + * This is only called in @c MODE_RAW. It is for the rare case that in + * raw mode packets are to be sent by the handler itself. It is NOT needed + * for the raw commanding service. Its only current use is in the STR + * handler which gets its raw packets from a different source. + * Also it can be used for transitional commands, to get the device ready + * for @c MODE_RAW + * + * As it is almost never used, there is a default implementation + * returning @c NOTHING_TO_SEND. + * + * #rawPacket and #rawPacketLen must be set by this method to the packet + * to be sent. + * + * @param[out] id the device command id built + * @return + * - @c RETURN_OK when a command is to be sent + * - not @c NOTHING_TO_SEND when no command is to be sent + */ + virtual ReturnValue_t buildChildRawCommand(); - /** - * Build the device command to send for raw mode. - * - * This is only called in @c MODE_RAW. It is for the rare case that in - * raw mode packets are to be sent by the handler itself. It is NOT needed - * for the raw commanding service. Its only current use is in the STR - * handler which gets its raw packets from a different source. - * Also it can be used for transitional commands, to get the device ready - * for @c MODE_RAW - * - * As it is almost never used, there is a default implementation - * returning @c NOTHING_TO_SEND. - * - * #rawPacket and #rawPacketLen must be set by this method to the packet - * to be sent. - * - * @param[out] id the device command id built - * @return - * - @c RETURN_OK when a command is to be sent - * - not @c NOTHING_TO_SEND when no command is to be sent - */ - virtual ReturnValue_t buildChildRawCommand(); + /** + * @brief Construct a command reply containing a raw reply. + * @details + * It gets space in the #IPCStore, copies data there, then sends a raw reply + * containing the store address. This method is virtual, as devices can have different channels + * to send raw replies + * + * @param data data to send + * @param len length of @c data + * @param sendTo the messageQueueId of the one to send to + * @param isCommand marks the raw data as a command, the message then + * will be of type raw_command + */ + virtual void replyRawData(const uint8_t *data, size_t len, + MessageQueueId_t sendTo, bool isCommand = false); - /** - * Returns the delay cycle count of a reply. - * A count != 0 indicates that the command is already executed. - * @param deviceCommand The command to look for - * @return - * The current delay count. If the command does not exist (should never - * happen) it returns 0. - */ - uint8_t getReplyDelayCycles(DeviceCommandId_t deviceCommand); + /** + * Get the state of the PCDU switches in the local datapool + * @return + * - @c PowerSwitchIF::SWITCH_ON if all switches specified + * by #switches are on + * - @c PowerSwitchIF::SWITCH_OFF one of the switches specified by + * #switches are off + * - @c PowerSwitchIF::RETURN_FAILED if an error occured + */ + ReturnValue_t getStateOfSwitches(); - /** - * Construct a command reply containing a raw reply. - * - * It gets space in the #IPCStore, copies data there, then sends a raw reply - * containing the store address. - * - * This method is virtual, as devices can have different channels to send - * raw replies - * - * @param data data to send - * @param len length of @c data - * @param sendTo the messageQueueId of the one to send to - * @param isCommand marks the raw data as a command, the message then - * will be of type raw_command - */ - virtual void replyRawData(const uint8_t *data, size_t len, - MessageQueueId_t sendTo, bool isCommand = false); + /** + * Children can overwrite this function to suppress checking of the + * command Queue + * + * This can be used when the child does not want to receive a command in + * a certain situation. Care must be taken that checking is not + * permanentely disabled as this would render the handler unusable. + * + * @return whether checking the queue should NOT be done + */ + virtual bool dontCheckQueue(); - /** - * Calls replyRawData() with #defaultRawReceiver, but checks if wiretapping - * is active and if so, does not send the data as the wiretapping will have - * sent it already - */ - void replyRawReplyIfnotWiretapped(const uint8_t *data, size_t len); + Mode_t getBaseMode(Mode_t transitionMode); - /** - * @brief Notify child about mode change. - */ - virtual void modeChanged(void); + bool isAwaitingReply(); - /** - * Enable the reply checking for a command - * - * Is only called, if the command was sent (i.e. the getWriteReply was - * successful). Must ensure that all replies are activated and correctly - * linked to the command that initiated it. - * The default implementation looks for a reply with the same id as the - * command id in the replyMap or uses the alternativeReplyId if flagged so. - * When found, copies maxDelayCycles to delayCycles in the reply information - * and sets the command to expect one reply. - * - * Can be overwritten by the child, if a command activates multiple replies - * or replyId differs from commandId. - * Notes for child implementations: - * - If the command was not found in the reply map, - * NO_REPLY_EXPECTED MUST be returned. - * - A failure code may be returned if something went fundamentally wrong. - * - * @param deviceCommand - * @return - RETURN_OK if a reply was activated. - * - NO_REPLY_EXPECTED if there was no reply found. This is not an - * error case as many commands do not expect a reply. - */ - virtual ReturnValue_t enableReplyInReplyMap(DeviceCommandMap::iterator cmd, - uint8_t expectedReplies = 1, bool useAlternateId = false, - DeviceCommandId_t alternateReplyID = 0); + void handleDeviceTM(SerializeIF *dataSet, DeviceCommandId_t replyId, + bool forceDirectTm = false); + // void handleDeviceTM(uint8_t* data, size_t dataSize, DeviceCommandId_t replyId, + // bool forceDirectTm); - /** - * Get the state of the PCDU switches in the local datapool - * @return - * - @c PowerSwitchIF::SWITCH_ON if all switches specified - * by #switches are on - * - @c PowerSwitchIF::SWITCH_OFF one of the switches specified by - * #switches are off - * - @c PowerSwitchIF::RETURN_FAILED if an error occured - */ - ReturnValue_t getStateOfSwitches(void); + virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t *msToReachTheMode); - /** - * build a list of sids and pass it to the #hkSwitcher - */ - virtual void changeHK(Mode_t mode, Submode_t submode, bool enable); + virtual ReturnValue_t letChildHandleMessage(CommandMessage *message); - /** - * Children can overwrite this function to suppress checking of the - * command Queue - * - * This can be used when the child does not want to receive a command in - * a certain situation. Care must be taken that checking is not - * permanentely disabled as this would render the handler unusable. - * - * @return whether checking the queue should NOT be done - */ - virtual bool dontCheckQueue(); + /** + * Overwrites SystemObject::triggerEvent in order to inform FDIR"Helper" + * faster about executed events. + * This is a bit sneaky, but improves responsiveness of the device FDIR. + * @param event The event to be thrown + * @param parameter1 Optional parameter 1 + * @param parameter2 Optional parameter 2 + */ + void triggerEvent(Event event, uint32_t parameter1 = 0, + uint32_t parameter2 = 0); + /** + * Same as triggerEvent, but for forwarding if object is used as proxy. + */ + virtual void forwardEvent(Event event, uint32_t parameter1 = 0, + uint32_t parameter2 = 0) const; - Mode_t getBaseMode(Mode_t transitionMode); + /** + * Checks if current mode is transitional mode. + * @return true if mode is transitional, false else. + */ + bool isTransitionalMode(); - bool isAwaitingReply(); + /** + * Checks if current handler state allows reception of external device commands. + * Default implementation allows commands only in plain MODE_ON and MODE_NORMAL. + * @return RETURN_OK if commands are accepted, anything else otherwise. + */ + virtual ReturnValue_t acceptExternalDeviceCommands(); - void handleDeviceTM(SerializeIF *dataSet, DeviceCommandId_t replyId, - bool forceDirectTm = false); -// void handleDeviceTM(uint8_t* data, size_t dataSize, DeviceCommandId_t replyId, -// bool forceDirectTm); + bool commandIsExecuting(DeviceCommandId_t commandId); - virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, - uint32_t *msToReachTheMode); - - /* HasModesIF overrides */ - virtual void startTransition(Mode_t mode, Submode_t submode) override; - virtual void setToExternalControl() override; - virtual void announceMode(bool recursive) override; - - virtual ReturnValue_t letChildHandleMessage(CommandMessage *message); - - /** - * Overwrites SystemObject::triggerEvent in order to inform FDIR"Helper" - * faster about executed events. - * This is a bit sneaky, but improves responsiveness of the device FDIR. - * @param event The event to be thrown - * @param parameter1 Optional parameter 1 - * @param parameter2 Optional parameter 2 - */ - void triggerEvent(Event event, uint32_t parameter1 = 0, - uint32_t parameter2 = 0); - /** - * Same as triggerEvent, but for forwarding if object is used as proxy. - */ - virtual void forwardEvent(Event event, uint32_t parameter1 = 0, - uint32_t parameter2 = 0) const; - /** - * Checks state of switches in conjunction with mode and triggers an event - * if they don't fit. - */ - virtual void checkSwitchState(); - - /** - * Reserved for the rare case where a device needs to perform additional - * operation cyclically in OFF mode. - */ - virtual void doOffActivity(); - - /** - * Reserved for the rare case where a device needs to perform additional - * operation cyclically in ON mode. - */ - virtual void doOnActivity(); - - /** - * Checks if current mode is transitional mode. - * @return true if mode is transitional, false else. - */ - bool isTransitionalMode(); - - /** - * Checks if current handler state allows reception of external device commands. - * Default implementation allows commands only in plain MODE_ON and MODE_NORMAL. - * @return RETURN_OK if commands are accepted, anything else otherwise. - */ - virtual ReturnValue_t acceptExternalDeviceCommands(); - - bool commandIsExecuting(DeviceCommandId_t commandId); - - /** - * set all switches returned by getSwitches() - * - * @param onOff on == @c SWITCH_ON; off != @c SWITCH_ON - */ - void commandSwitch(ReturnValue_t onOff); + /** + * set all switches returned by getSwitches() + * + * @param onOff on == @c SWITCH_ON; off != @c SWITCH_ON + */ + void commandSwitch(ReturnValue_t onOff); private: - /** - * State a cookie is in. - * - * Used to keep track of the state of the RMAP communication. - */ - enum CookieState_t { - COOKIE_UNUSED, //!< The Cookie is unused - COOKIE_WRITE_READY, //!< There's data available to send. - COOKIE_READ_SENT, //!< A sendRead command was sent with this cookie - COOKIE_WRITE_SENT //!< A sendWrite command was sent with this cookie - }; - /** - * Information about a cookie. - * - * This is stored in a map for each cookie, to not only track the state, - * but also information about the sent command. Tracking this information - * is needed as the state of a commandId (waiting for reply) is done when a - * write reply is received. - */ - struct CookieInfo { - CookieState_t state; - DeviceCommandMap::iterator pendingCommand; - }; + /** + * State a cookie is in. + * + * Used to keep track of the state of the RMAP communication. + */ + enum CookieState_t { + COOKIE_UNUSED, //!< The Cookie is unused + COOKIE_WRITE_READY, //!< There's data available to send. + COOKIE_READ_SENT, //!< A sendRead command was sent with this cookie + COOKIE_WRITE_SENT //!< A sendWrite command was sent with this cookie + }; + /** + * Information about a cookie. + * + * This is stored in a map for each cookie, to not only track the state, + * but also information about the sent command. Tracking this information + * is needed as the state of a commandId (waiting for reply) is done when a + * write reply is received. + */ + struct CookieInfo { + CookieState_t state; + DeviceCommandMap::iterator pendingCommand; + }; - /** - * @brief Info about the #cookie - * Used to track the state of the communication - */ - CookieInfo cookieInfo; + /** + * @brief Info about the #cookie + * Used to track the state of the communication + */ + CookieInfo cookieInfo; - /** the object used to set power switches */ - PowerSwitchIF *powerSwitcher = nullptr; + /** the object used to set power switches */ + PowerSwitchIF *powerSwitcher = nullptr; - /** HK destination can also be set individually */ - object_id_t hkDestination = objects::NO_OBJECT; + /** HK destination can also be set individually */ + object_id_t hkDestination = objects::NO_OBJECT; - /** - * @brief Used for timing out mode transitions. - * Set when setMode() is called. - */ - uint32_t timeoutStart = 0; + /** + * @brief Used for timing out mode transitions. + * Set when setMode() is called. + */ + uint32_t timeoutStart = 0; - bool setStartupImmediately = false; + bool setStartupImmediately = false; - /** - * Delay for the current mode transition, used for time out - */ - uint32_t childTransitionDelay; + /** + * Delay for the current mode transition, used for time out + */ + uint32_t childTransitionDelay; - /** - * @brief The mode the current transition originated from - * - * This is private so the child can not change it and mess up the timeouts - * - * IMPORTANT: This is not valid during _MODE_SHUT_DOWN and _MODE_START_UP!! - * (it is _MODE_POWER_DOWN during this modes) - * - * is element of [MODE_ON, MODE_NORMAL, MODE_RAW] - */ - Mode_t transitionSourceMode; + /** + * @brief The mode the current transition originated from + * + * This is private so the child can not change it and mess up the timeouts + * + * IMPORTANT: This is not valid during _MODE_SHUT_DOWN and _MODE_START_UP!! + * (it is _MODE_POWER_DOWN during this modes) + * + * is element of [MODE_ON, MODE_NORMAL, MODE_RAW] + */ + Mode_t transitionSourceMode; - /** - * the submode of the source mode during a transition - */ - Submode_t transitionSourceSubMode; + /** + * the submode of the source mode during a transition + */ + Submode_t transitionSourceSubMode; - /** - * read the command queue - */ - void readCommandQueue(void); + /** + * read the command queue + */ + void readCommandQueue(void); - /** - * Handle the device handler mode. - * - * - checks whether commands are valid for the current mode, rejects - * them accordingly - * - checks whether commanded mode transitions are required and calls - * handleCommandedModeTransition() - * - does the necessary action for the current mode or calls - * doChildStateMachine in modes @c MODE_TO_ON and @c MODE_TO_OFF - * - actions that happen in transitions (e.g. setting a timeout) are - * handled in setMode() - */ - void doStateMachine(void); + /** + * Handle the device handler mode. + * + * - checks whether commands are valid for the current mode, rejects + * them accordingly + * - checks whether commanded mode transitions are required and calls + * handleCommandedModeTransition() + * - does the necessary action for the current mode or calls + * doChildStateMachine in modes @c MODE_TO_ON and @c MODE_TO_OFF + * - actions that happen in transitions (e.g. setting a timeout) are + * handled in setMode() + */ + void doStateMachine(void); - void buildRawDeviceCommand(CommandMessage* message); - void buildInternalCommand(void); + void buildRawDeviceCommand(CommandMessage* message); + void buildInternalCommand(void); - /** - * Decrement the counter for the timout of replies. - * - * This is called at the beginning of each cycle. It checks whether a - * reply has timed out (that means a reply was expected but not received). - */ - void decrementDeviceReplyMap(void); + /** + * Decrement the counter for the timout of replies. + * + * This is called at the beginning of each cycle. It checks whether a + * reply has timed out (that means a reply was expected but not received). + */ + void decrementDeviceReplyMap(void); - /** - * Convenience function to handle a reply. - * - * Called after scanForReply() has found a packet. Checks if the found ID - * is in the #deviceCommandMap, if so, calls - * #interpretDeviceReply for further action. - * - * It also resets the timeout counter for the command id. - * - * @param data the found packet - * @param id the found id - * @foundLen the length of the packet - */ - void handleReply(const uint8_t *data, DeviceCommandId_t id, uint32_t foundLen); + /** + * Convenience function to handle a reply. + * + * Called after scanForReply() has found a packet. Checks if the found ID + * is in the #deviceCommandMap, if so, calls + * #interpretDeviceReply for further action. + * + * It also resets the timeout counter for the command id. + * + * @param data the found packet + * @param id the found id + * @foundLen the length of the packet + */ + void handleReply(const uint8_t *data, DeviceCommandId_t id, uint32_t foundLen); - void replyToReply(DeviceReplyMap::iterator iter, ReturnValue_t status); - /** - * Build and send a command to the device. - * - * This routine checks whether a raw or direct command has been received, - * checks the content of the received command and calls - * buildCommandFromCommand() for direct commands or sets #rawpacket - * to the received raw packet. - * If no external command is received or the received command is invalid and - * the current mode is @c MODE_NORMAL or a transitional mode, it asks the - * child class to build a command (via getNormalDeviceCommand() or - * getTransitionalDeviceCommand() and buildCommand()) and - * sends the command via RMAP. - */ - void doSendWrite(void); + void replyToReply(DeviceReplyMap::iterator iter, ReturnValue_t status); + /** + * Build and send a command to the device. + * + * This routine checks whether a raw or direct command has been received, + * checks the content of the received command and calls + * buildCommandFromCommand() for direct commands or sets #rawpacket + * to the received raw packet. + * If no external command is received or the received command is invalid and + * the current mode is @c MODE_NORMAL or a transitional mode, it asks the + * child class to build a command (via getNormalDeviceCommand() or + * getTransitionalDeviceCommand() and buildCommand()) and + * sends the command via RMAP. + */ + void doSendWrite(void); - /** - * Check if the RMAP sendWrite action was successful. - * - * Depending on the result, the following is done - * - if the device command was external commanded, a reply is sent - * indicating the result - * - if the action was successful, the reply timout counter is initialized - */ - void doGetWrite(void); + /** + * Check if the RMAP sendWrite action was successful. + * + * Depending on the result, the following is done + * - if the device command was external commanded, a reply is sent + * indicating the result + * - if the action was successful, the reply timout counter is initialized + */ + void doGetWrite(void); - /** - * Send a RMAP getRead command. - * - * The size of the getRead command is #maxDeviceReplyLen. - * This is always executed, independently from the current mode. - */ - void doSendRead(void); + /** + * Send a RMAP getRead command. + * + * The size of the getRead command is #maxDeviceReplyLen. + * This is always executed, independently from the current mode. + */ + void doSendRead(void); - /** - * Check the getRead reply and the contained data. - * - * If data was received scanForReply() and, if successful, handleReply() - * are called. If the current mode is @c MODE_RAW, the received packet - * is sent to the commanding object via commandQueue. - */ - void doGetRead(void); + /** + * Check the getRead reply and the contained data. + * + * If data was received scanForReply() and, if successful, handleReply() + * are called. If the current mode is @c MODE_RAW, the received packet + * is sent to the commanding object via commandQueue. + */ + void doGetRead(void); - /** - * Retrive data from the #IPCStore. - * - * @param storageAddress - * @param[out] data - * @param[out] len - * @return - * - @c RETURN_OK @c data is valid - * - @c RETURN_FAILED IPCStore is nullptr - * - the return value from the IPCStore if it was not @c RETURN_OK - */ - ReturnValue_t getStorageData(store_address_t storageAddress, uint8_t **data, - uint32_t *len); + /** + * Retrive data from the #IPCStore. + * + * @param storageAddress + * @param[out] data + * @param[out] len + * @return + * - @c RETURN_OK @c data is valid + * - @c RETURN_FAILED IPCStore is nullptr + * - the return value from the IPCStore if it was not @c RETURN_OK + */ + ReturnValue_t getStorageData(store_address_t storageAddress, uint8_t **data, + uint32_t *len); - /** - * @param modeTo either @c MODE_ON, MODE_NORMAL or MODE_RAW, nothing else! - */ - void setTransition(Mode_t modeTo, Submode_t submodeTo); + /** + * @param modeTo either @c MODE_ON, MODE_NORMAL or MODE_RAW, nothing else! + */ + void setTransition(Mode_t modeTo, Submode_t submodeTo); - /** - * calls the right child function for the transitional submodes - */ - void callChildStatemachine(); + /** + * Calls the right child function for the transitional submodes + */ + void callChildStatemachine(); - ReturnValue_t handleDeviceHandlerMessage(CommandMessage *message); - - virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; + ReturnValue_t handleDeviceHandlerMessage(CommandMessage *message); virtual dur_millis_t getPeriodicOperationFrequency() const override; void parseReply(const uint8_t* receivedData, - size_t receivedDataLen); + size_t receivedDataLen); void handleTransitionToOnMode(Mode_t commandedMode, - Submode_t commandedSubmode); + Submode_t commandedSubmode); + /** + * Generic internal printer function which also handles printing the object ID. + * @param errorType + * @param functionName + * @param errorCode + * @param errorPrint + */ void printWarningOrError(sif::OutputTypes errorType, - const char* functionName, - ReturnValue_t errorCode = HasReturnvaluesIF::RETURN_FAILED, - const char* errorPrint = nullptr); + const char* functionName, + ReturnValue_t errorCode = HasReturnvaluesIF::RETURN_FAILED, + const char* errorPrint = nullptr); }; #endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */