2020-08-13 20:53:35 +02:00
|
|
|
#include "DeviceHandlerBase.h"
|
2020-08-27 19:50:02 +02:00
|
|
|
#include "AcceptsDeviceResponsesIF.h"
|
|
|
|
|
#include "DeviceTmReportingWrapper.h"
|
|
|
|
|
|
2021-01-13 11:53:34 +01:00
|
|
|
#include "../serviceinterface/ServiceInterface.h"
|
2020-08-13 20:53:35 +02:00
|
|
|
#include "../objectmanager/ObjectManager.h"
|
|
|
|
|
#include "../storagemanager/StorageManagerIF.h"
|
|
|
|
|
#include "../thermal/ThermalComponentIF.h"
|
|
|
|
|
#include "../globalfunctions/CRC.h"
|
2020-10-12 18:18:41 +02:00
|
|
|
#include "../housekeeping/HousekeepingMessage.h"
|
|
|
|
|
#include "../ipc/MessageQueueMessage.h"
|
2020-08-13 20:53:35 +02:00
|
|
|
#include "../ipc/QueueFactory.h"
|
2020-10-12 18:18:41 +02:00
|
|
|
#include "../subsystem/SubsystemBase.h"
|
2020-12-08 15:59:30 +01:00
|
|
|
#include "../datapoollocal/LocalPoolVariable.h"
|
2018-07-12 16:29:32 +02:00
|
|
|
|
2020-07-16 11:56:48 +02:00
|
|
|
object_id_t DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT;
|
|
|
|
|
object_id_t DeviceHandlerBase::rawDataReceiverId = objects::NO_OBJECT;
|
|
|
|
|
object_id_t DeviceHandlerBase::defaultFdirParentId = objects::NO_OBJECT;
|
2016-06-15 23:48:41 +02:00
|
|
|
|
2020-04-19 15:48:17 +02:00
|
|
|
DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId,
|
|
|
|
|
object_id_t deviceCommunication, CookieIF * comCookie,
|
2020-07-16 11:56:48 +02:00
|
|
|
FailureIsolationBase* fdirInstance, size_t cmdQueueSize) :
|
2020-04-19 15:15:33 +02:00
|
|
|
SystemObject(setObjectId), mode(MODE_OFF), submode(SUBMODE_NONE),
|
2020-04-19 15:57:39 +02:00
|
|
|
wiretappingMode(OFF), storedRawData(StorageManagerIF::INVALID_ADDRESS),
|
2020-05-17 15:28:00 +02:00
|
|
|
deviceCommunicationId(deviceCommunication), comCookie(comCookie),
|
2020-04-19 15:57:39 +02:00
|
|
|
healthHelper(this,setObjectId), modeHelper(this), parameterHelper(this),
|
2021-01-13 11:53:34 +01:00
|
|
|
actionHelper(this, nullptr), poolManager(this, nullptr),
|
2020-10-12 18:18:41 +02:00
|
|
|
childTransitionFailure(RETURN_OK), fdirInstance(fdirInstance),
|
|
|
|
|
hkSwitcher(this), defaultFDIRUsed(fdirInstance == nullptr),
|
|
|
|
|
switchOffWasReported(false), childTransitionDelay(5000),
|
|
|
|
|
transitionSourceMode(_MODE_POWER_DOWN),
|
2020-07-16 11:56:48 +02:00
|
|
|
transitionSourceSubMode(SUBMODE_NONE) {
|
2018-07-12 16:29:32 +02:00
|
|
|
commandQueue = QueueFactory::instance()->createMessageQueue(cmdQueueSize,
|
2020-07-16 11:56:48 +02:00
|
|
|
MessageQueueMessage::MAX_MESSAGE_SIZE);
|
2016-06-15 23:48:41 +02:00
|
|
|
insertInCommandMap(RAW_COMMAND_ID);
|
2020-06-06 20:56:09 +02:00
|
|
|
cookieInfo.state = COOKIE_UNUSED;
|
|
|
|
|
cookieInfo.pendingCommand = deviceCommandMap.end();
|
2020-05-17 17:46:27 +02:00
|
|
|
if (comCookie == nullptr) {
|
2021-01-13 11:53:34 +01:00
|
|
|
printWarningOrError(sif::OutputTypes::OUT_ERROR, "DeviceHandlerBase",
|
|
|
|
|
HasReturnvaluesIF::RETURN_FAILED, "Invalid cookie");
|
2020-05-17 17:46:27 +02:00
|
|
|
}
|
2020-04-19 15:15:33 +02:00
|
|
|
if (this->fdirInstance == nullptr) {
|
2018-07-12 16:29:32 +02:00
|
|
|
this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId,
|
2020-07-16 11:56:48 +02:00
|
|
|
defaultFdirParentId);
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-12 18:18:41 +02:00
|
|
|
void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) {
|
|
|
|
|
this->hkDestination = hkDestination;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-16 11:56:48 +02:00
|
|
|
void DeviceHandlerBase::setThermalStateRequestPoolIds(
|
2020-12-08 15:59:30 +01:00
|
|
|
lp_id_t thermalStatePoolId, lp_id_t heaterRequestPoolId,
|
|
|
|
|
uint32_t thermalSetId) {
|
|
|
|
|
thermalSet = new DeviceHandlerThermalSet(this, thermalSetId,
|
|
|
|
|
thermalStatePoolId, heaterRequestPoolId);
|
2020-07-16 11:56:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-06-15 23:48:41 +02:00
|
|
|
DeviceHandlerBase::~DeviceHandlerBase() {
|
2020-05-17 15:28:00 +02:00
|
|
|
delete comCookie;
|
2016-06-15 23:48:41 +02:00
|
|
|
if (defaultFDIRUsed) {
|
|
|
|
|
delete fdirInstance;
|
|
|
|
|
}
|
2018-07-12 16:29:32 +02:00
|
|
|
QueueFactory::instance()->deleteMessageQueue(commandQueue);
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
|
|
|
|
|
2018-07-12 16:29:32 +02:00
|
|
|
ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) {
|
2016-06-15 23:48:41 +02:00
|
|
|
this->pstStep = counter;
|
2020-10-12 18:28:07 +02:00
|
|
|
this->lastStep = this->pstStep;
|
2016-06-15 23:48:41 +02:00
|
|
|
|
2020-10-12 18:28:07 +02:00
|
|
|
if (getComAction() == CommunicationAction::NOTHING) {
|
|
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (getComAction() == CommunicationAction::PERFORM_OPERATION) {
|
2016-06-15 23:48:41 +02:00
|
|
|
cookieInfo.state = COOKIE_UNUSED;
|
|
|
|
|
readCommandQueue();
|
|
|
|
|
doStateMachine();
|
|
|
|
|
checkSwitchState();
|
|
|
|
|
decrementDeviceReplyMap();
|
|
|
|
|
fdirInstance->checkForFailures();
|
2018-07-12 16:29:32 +02:00
|
|
|
hkSwitcher.performOperation();
|
2020-04-19 22:17:14 +02:00
|
|
|
performOperationHook();
|
2020-10-12 18:28:07 +02:00
|
|
|
return RETURN_OK;
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
2020-10-12 18:28:07 +02:00
|
|
|
|
2016-06-15 23:48:41 +02:00
|
|
|
if (mode == MODE_OFF) {
|
2018-07-12 16:29:32 +02:00
|
|
|
return RETURN_OK;
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
2020-10-12 18:28:07 +02:00
|
|
|
|
2020-04-19 15:16:44 +02:00
|
|
|
switch (getComAction()) {
|
2020-10-12 18:28:07 +02:00
|
|
|
case CommunicationAction::SEND_WRITE:
|
|
|
|
|
if (cookieInfo.state == COOKIE_UNUSED) {
|
|
|
|
|
// if no external command was specified, build internal command.
|
2016-06-15 23:48:41 +02:00
|
|
|
buildInternalCommand();
|
|
|
|
|
}
|
|
|
|
|
doSendWrite();
|
|
|
|
|
break;
|
2020-10-12 18:28:07 +02:00
|
|
|
case CommunicationAction::GET_WRITE:
|
2016-06-15 23:48:41 +02:00
|
|
|
doGetWrite();
|
|
|
|
|
break;
|
2020-10-12 18:28:07 +02:00
|
|
|
case CommunicationAction::SEND_READ:
|
2016-06-15 23:48:41 +02:00
|
|
|
doSendRead();
|
|
|
|
|
break;
|
2020-10-12 18:28:07 +02:00
|
|
|
case CommunicationAction::GET_READ:
|
2016-06-15 23:48:41 +02:00
|
|
|
doGetRead();
|
2020-12-08 15:59:30 +01:00
|
|
|
// This will be performed after datasets have been updated by the
|
|
|
|
|
// custom device implementation.
|
2021-01-13 11:53:34 +01:00
|
|
|
poolManager.performHkOperation();
|
2016-06-15 23:48:41 +02:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2018-07-12 16:29:32 +02:00
|
|
|
return RETURN_OK;
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-19 14:03:47 +02:00
|
|
|
ReturnValue_t DeviceHandlerBase::initialize() {
|
|
|
|
|
ReturnValue_t result = SystemObject::initialize();
|
|
|
|
|
if (result != RETURN_OK) {
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
communicationInterface = objectManager->get<DeviceCommunicationIF>(
|
|
|
|
|
deviceCommunicationId);
|
2020-07-16 11:56:48 +02:00
|
|
|
if (communicationInterface == nullptr) {
|
2021-01-13 11:53:34 +01:00
|
|
|
printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize",
|
|
|
|
|
ObjectManagerIF::CHILD_INIT_FAILED,
|
|
|
|
|
"Passed communication IF invalid");
|
2020-07-16 11:56:48 +02:00
|
|
|
return ObjectManagerIF::CHILD_INIT_FAILED;
|
2020-04-19 14:03:47 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-19 15:48:17 +02:00
|
|
|
result = communicationInterface->initializeInterface(comCookie);
|
2020-04-19 14:03:47 +02:00
|
|
|
if (result != RETURN_OK) {
|
2021-01-13 11:53:34 +01:00
|
|
|
printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize",
|
|
|
|
|
ObjectManagerIF::CHILD_INIT_FAILED,
|
|
|
|
|
"ComIF initialization failed");
|
2020-10-12 18:18:41 +02:00
|
|
|
return result;
|
2020-04-19 14:03:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IPCStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
|
2020-07-16 11:56:48 +02:00
|
|
|
if (IPCStore == nullptr) {
|
2021-01-13 11:53:34 +01:00
|
|
|
printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize",
|
|
|
|
|
ObjectManagerIF::CHILD_INIT_FAILED, "IPC Store not set up");
|
2020-07-16 11:56:48 +02:00
|
|
|
return ObjectManagerIF::CHILD_INIT_FAILED;
|
2020-04-19 14:03:47 +02:00
|
|
|
}
|
|
|
|
|
|
2020-07-16 11:56:48 +02:00
|
|
|
if(rawDataReceiverId != objects::NO_OBJECT) {
|
|
|
|
|
AcceptsDeviceResponsesIF *rawReceiver = objectManager->get<
|
|
|
|
|
AcceptsDeviceResponsesIF>(rawDataReceiverId);
|
2020-04-19 14:03:47 +02:00
|
|
|
|
2020-07-16 11:56:48 +02:00
|
|
|
if (rawReceiver == nullptr) {
|
2021-01-13 11:53:34 +01:00
|
|
|
printWarningOrError(sif::OutputTypes::OUT_ERROR,
|
|
|
|
|
"initialize", ObjectManagerIF::CHILD_INIT_FAILED,
|
|
|
|
|
"Raw receiver object ID set but no valid object found.");
|
2021-01-03 14:16:52 +01:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2020-07-16 11:56:48 +02:00
|
|
|
sif::error << "Make sure the raw receiver object is set up properly"
|
|
|
|
|
" and implements AcceptsDeviceResponsesIF" << std::endl;
|
2021-01-13 11:53:34 +01:00
|
|
|
#else
|
|
|
|
|
sif::printError("Make sure the raw receiver object is set up "
|
|
|
|
|
"properly and implements AcceptsDeviceResponsesIF\n");
|
2021-01-03 13:58:18 +01:00
|
|
|
#endif
|
2020-07-16 11:56:48 +02:00
|
|
|
return ObjectManagerIF::CHILD_INIT_FAILED;
|
|
|
|
|
}
|
|
|
|
|
defaultRawReceiver = rawReceiver->getDeviceQueue();
|
2020-04-19 14:03:47 +02:00
|
|
|
}
|
|
|
|
|
|
2020-07-16 11:56:48 +02:00
|
|
|
if(powerSwitcherId != objects::NO_OBJECT) {
|
|
|
|
|
powerSwitcher = objectManager->get<PowerSwitchIF>(powerSwitcherId);
|
|
|
|
|
if (powerSwitcher == nullptr) {
|
2021-01-13 11:53:34 +01:00
|
|
|
printWarningOrError(sif::OutputTypes::OUT_ERROR,
|
|
|
|
|
"initialize", ObjectManagerIF::CHILD_INIT_FAILED,
|
|
|
|
|
"Power switcher set but no valid object found.");
|
2021-01-03 14:16:52 +01:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2021-01-13 11:53:34 +01:00
|
|
|
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");
|
2021-01-03 13:58:18 +01:00
|
|
|
#endif
|
2020-07-16 11:56:48 +02:00
|
|
|
return ObjectManagerIF::CHILD_INIT_FAILED;
|
|
|
|
|
}
|
2020-04-19 14:03:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = healthHelper.initialize();
|
2020-07-16 12:54:30 +02:00
|
|
|
if (result != RETURN_OK) {
|
|
|
|
|
return result;
|
2020-04-19 14:03:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 = hkSwitcher.initialize();
|
|
|
|
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-13 11:53:34 +01:00
|
|
|
result = poolManager.initialize(commandQueue);
|
2020-10-12 18:18:41 +02:00
|
|
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-19 14:03:47 +02:00
|
|
|
fillCommandAndReplyMap();
|
|
|
|
|
|
2020-12-08 15:59:30 +01:00
|
|
|
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;
|
2021-01-13 11:53:34 +01:00
|
|
|
thermalSet->heaterRequest.setValid(true);
|
|
|
|
|
thermalSet->commit();
|
2020-12-08 15:59:30 +01:00
|
|
|
}
|
2020-04-19 14:03:47 +02:00
|
|
|
|
2020-12-08 15:59:30 +01:00
|
|
|
}
|
2020-04-19 14:03:47 +02:00
|
|
|
|
2020-12-08 15:59:30 +01:00
|
|
|
return RETURN_OK;
|
2020-04-19 14:03:47 +02:00
|
|
|
}
|
|
|
|
|
|
2016-06-15 23:48:41 +02:00
|
|
|
void DeviceHandlerBase::decrementDeviceReplyMap() {
|
|
|
|
|
for (std::map<DeviceCommandId_t, DeviceReplyInfo>::iterator iter =
|
|
|
|
|
deviceReplyMap.begin(); iter != deviceReplyMap.end(); iter++) {
|
|
|
|
|
if (iter->second.delayCycles != 0) {
|
|
|
|
|
iter->second.delayCycles--;
|
|
|
|
|
if (iter->second.delayCycles == 0) {
|
2020-06-19 01:05:51 +02:00
|
|
|
if (iter->second.periodic) {
|
2016-06-15 23:48:41 +02:00
|
|
|
iter->second.delayCycles = iter->second.maxDelayCycles;
|
|
|
|
|
}
|
|
|
|
|
replyToReply(iter, TIMEOUT);
|
|
|
|
|
missedReply(iter->first);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceHandlerBase::readCommandQueue() {
|
|
|
|
|
|
|
|
|
|
if (dontCheckQueue()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-16 11:56:48 +02:00
|
|
|
CommandMessage command;
|
|
|
|
|
ReturnValue_t result = commandQueue->receiveMessage(&command);
|
2016-06-15 23:48:41 +02:00
|
|
|
if (result != RETURN_OK) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-16 12:54:30 +02:00
|
|
|
result = healthHelper.handleHealthCommand(&command);
|
|
|
|
|
if (result == RETURN_OK) {
|
|
|
|
|
return;
|
2020-07-16 11:56:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = modeHelper.handleModeCommand(&command);
|
2016-06-15 23:48:41 +02:00
|
|
|
if (result == RETURN_OK) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-16 11:56:48 +02:00
|
|
|
result = actionHelper.handleActionMessage(&command);
|
2016-06-15 23:48:41 +02:00
|
|
|
if (result == RETURN_OK) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-16 11:56:48 +02:00
|
|
|
result = parameterHelper.handleParameterMessage(&command);
|
2016-06-15 23:48:41 +02:00
|
|
|
if (result == RETURN_OK) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-13 11:53:34 +01:00
|
|
|
result = poolManager.handleHousekeepingMessage(&command);
|
2020-10-12 18:18:41 +02:00
|
|
|
if (result == RETURN_OK) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-06-15 23:48:41 +02:00
|
|
|
|
2020-07-16 11:56:48 +02:00
|
|
|
result = handleDeviceHandlerMessage(&command);
|
2016-06-15 23:48:41 +02:00
|
|
|
if (result == RETURN_OK) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-16 11:56:48 +02:00
|
|
|
result = letChildHandleMessage(&command);
|
2016-06-15 23:48:41 +02:00
|
|
|
if (result == RETURN_OK) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-16 11:56:48 +02:00
|
|
|
replyReturnvalueToCommand(CommandMessage::UNKNOWN_COMMAND);
|
2016-06-15 23:48:41 +02:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
2018-07-12 16:29:32 +02:00
|
|
|
Clock::getUptime(¤tUptime);
|
2016-06-15 23:48:41 +02:00
|
|
|
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;
|
2018-07-12 16:29:32 +02:00
|
|
|
Clock::getUptime(¤tUptime);
|
2020-07-16 11:56:48 +02:00
|
|
|
if (powerSwitcher != nullptr and currentUptime - timeoutStart >=
|
|
|
|
|
powerSwitcher->getSwitchDelayMs()) {
|
2016-06-15 23:48:41 +02:00
|
|
|
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;
|
2018-07-12 16:29:32 +02:00
|
|
|
Clock::getUptime(¤tUptime);
|
2020-07-16 11:56:48 +02:00
|
|
|
|
|
|
|
|
if(powerSwitcher == nullptr) {
|
|
|
|
|
setMode(MODE_OFF);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-15 23:48:41 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-16 11:56:48 +02:00
|
|
|
ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap(
|
|
|
|
|
DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles,
|
2020-10-12 18:18:41 +02:00
|
|
|
LocalPoolDataSetBase* replyDataSet, size_t replyLen, bool periodic,
|
|
|
|
|
bool hasDifferentReplyId, DeviceCommandId_t replyId) {
|
2020-04-19 15:01:27 +02:00
|
|
|
//No need to check, as we may try to insert multiple times.
|
2016-06-15 23:48:41 +02:00
|
|
|
insertInCommandMap(deviceCommand);
|
|
|
|
|
if (hasDifferentReplyId) {
|
2020-10-12 18:18:41 +02:00
|
|
|
return insertInReplyMap(replyId, maxDelayCycles,
|
|
|
|
|
replyDataSet, replyLen, periodic);
|
2016-06-15 23:48:41 +02:00
|
|
|
} else {
|
2020-10-12 18:18:41 +02:00
|
|
|
return insertInReplyMap(deviceCommand, maxDelayCycles,
|
|
|
|
|
replyDataSet, replyLen, periodic);
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId,
|
2020-10-12 18:18:41 +02:00
|
|
|
uint16_t maxDelayCycles, LocalPoolDataSetBase* dataSet,
|
|
|
|
|
size_t replyLen, bool periodic) {
|
2016-06-15 23:48:41 +02:00
|
|
|
DeviceReplyInfo info;
|
|
|
|
|
info.maxDelayCycles = maxDelayCycles;
|
|
|
|
|
info.periodic = periodic;
|
|
|
|
|
info.delayCycles = 0;
|
2020-04-19 15:01:27 +02:00
|
|
|
info.replyLen = replyLen;
|
2020-10-12 18:18:41 +02:00
|
|
|
info.dataSet = dataSet;
|
2016-06-15 23:48:41 +02:00
|
|
|
info.command = deviceCommandMap.end();
|
2020-05-17 15:47:17 +02:00
|
|
|
auto resultPair = deviceReplyMap.emplace(replyId, info);
|
|
|
|
|
if (resultPair.second) {
|
2016-06-15 23:48:41 +02:00
|
|
|
return RETURN_OK;
|
|
|
|
|
} else {
|
|
|
|
|
return RETURN_FAILED;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-16 11:56:48 +02:00
|
|
|
ReturnValue_t DeviceHandlerBase::insertInCommandMap(
|
|
|
|
|
DeviceCommandId_t deviceCommand) {
|
2016-06-15 23:48:41 +02:00
|
|
|
DeviceCommandInfo info;
|
|
|
|
|
info.expectedReplies = 0;
|
|
|
|
|
info.isExecuting = false;
|
|
|
|
|
info.sendReplyTo = NO_COMMANDER;
|
2020-05-17 15:47:17 +02:00
|
|
|
auto resultPair = deviceCommandMap.emplace(deviceCommand, info);
|
|
|
|
|
if (resultPair.second) {
|
2016-06-15 23:48:41 +02:00
|
|
|
return RETURN_OK;
|
|
|
|
|
} else {
|
|
|
|
|
return RETURN_FAILED;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-19 15:01:27 +02:00
|
|
|
ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceReply,
|
2020-06-19 01:05:51 +02:00
|
|
|
uint16_t delayCycles, uint16_t maxDelayCycles, bool periodic) {
|
2020-10-12 18:18:41 +02:00
|
|
|
auto replyIter = deviceReplyMap.find(deviceReply);
|
|
|
|
|
if (replyIter == deviceReplyMap.end()) {
|
2016-06-15 23:48:41 +02:00
|
|
|
triggerEvent(INVALID_DEVICE_COMMAND, deviceReply);
|
|
|
|
|
return RETURN_FAILED;
|
|
|
|
|
} else {
|
2020-10-12 18:18:41 +02:00
|
|
|
DeviceReplyInfo *info = &(replyIter->second);
|
2016-06-15 23:48:41 +02:00
|
|
|
if (maxDelayCycles != 0) {
|
|
|
|
|
info->maxDelayCycles = maxDelayCycles;
|
|
|
|
|
}
|
|
|
|
|
info->delayCycles = delayCycles;
|
|
|
|
|
info->periodic = periodic;
|
|
|
|
|
return RETURN_OK;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-12 18:18:41 +02:00
|
|
|
|
|
|
|
|
ReturnValue_t DeviceHandlerBase::setReplyDataset(DeviceCommandId_t replyId,
|
|
|
|
|
LocalPoolDataSetBase *dataSet) {
|
|
|
|
|
auto replyIter = deviceReplyMap.find(replyId);
|
|
|
|
|
if(replyIter == deviceReplyMap.end()) {
|
|
|
|
|
return HasReturnvaluesIF::RETURN_FAILED;
|
|
|
|
|
}
|
|
|
|
|
replyIter->second.dataSet = dataSet;
|
|
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-15 23:48:41 +02:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
2020-07-16 11:56:48 +02:00
|
|
|
// transitionTargetMode is set by setMode
|
2016-06-15 23:48:41 +02:00
|
|
|
setMode((modeTo | TRANSITION_MODE_CHILD_ACTION_MASK), submodeTo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
|
2018-07-12 16:29:32 +02:00
|
|
|
changeHK(mode, submode, false);
|
2016-06-15 23:48:41 +02:00
|
|
|
submode = newSubmode;
|
|
|
|
|
mode = newMode;
|
|
|
|
|
modeChanged();
|
|
|
|
|
setNormalDatapoolEntriesInvalid();
|
|
|
|
|
if (!isTransitionalMode()) {
|
|
|
|
|
modeHelper.modeChanged(newMode, newSubmode);
|
|
|
|
|
announceMode(false);
|
|
|
|
|
}
|
2018-07-12 16:29:32 +02:00
|
|
|
Clock::getUptime(&timeoutStart);
|
2016-06-15 23:48:41 +02:00
|
|
|
|
2020-12-08 15:59:30 +01:00
|
|
|
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);
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
2020-12-08 15:59:30 +01:00
|
|
|
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
2018-07-12 16:29:32 +02:00
|
|
|
changeHK(mode, submode, true);
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceHandlerBase::setMode(Mode_t newMode) {
|
|
|
|
|
setMode(newMode, submode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceHandlerBase::replyReturnvalueToCommand(ReturnValue_t status,
|
|
|
|
|
uint32_t parameter) {
|
2019-08-28 14:50:24 +02:00
|
|
|
//This is actually the reply protocol for raw and misc DH commands.
|
2016-06-15 23:48:41 +02:00
|
|
|
if (status == RETURN_OK) {
|
|
|
|
|
CommandMessage reply(CommandMessage::REPLY_COMMAND_OK, 0, parameter);
|
2018-07-12 16:29:32 +02:00
|
|
|
commandQueue->reply(&reply);
|
2016-06-15 23:48:41 +02:00
|
|
|
} else {
|
|
|
|
|
CommandMessage reply(CommandMessage::REPLY_REJECTED, status, parameter);
|
2018-07-12 16:29:32 +02:00
|
|
|
commandQueue->reply(&reply);
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceHandlerBase::replyToCommand(ReturnValue_t status,
|
|
|
|
|
uint32_t parameter) {
|
2021-01-13 11:53:34 +01:00
|
|
|
// Check if we reply to a raw command.
|
2016-06-15 23:48:41 +02:00
|
|
|
if (cookieInfo.pendingCommand->first == RAW_COMMAND_ID) {
|
|
|
|
|
if (status == NO_REPLY_EXPECTED) {
|
|
|
|
|
status = RETURN_OK;
|
|
|
|
|
}
|
|
|
|
|
replyReturnvalueToCommand(status, parameter);
|
2021-01-13 11:53:34 +01:00
|
|
|
// Always delete data from a raw command.
|
2016-06-15 23:48:41 +02:00
|
|
|
IPCStore->deleteData(storedRawData);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-01-13 11:53:34 +01:00
|
|
|
// Check if we were externally commanded.
|
2016-06-15 23:48:41 +02:00
|
|
|
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) {
|
|
|