Merge branch 'mueller_framework' into front_branch

This commit is contained in:
Robin Müller 2020-05-17 17:27:04 +02:00
commit 7c48274c9b
14 changed files with 487 additions and 422 deletions

View File

@ -1,14 +1,14 @@
#include <framework/datapool/DataSet.h>
#include <framework/datapool/PoolVariable.h>
#include <framework/datapool/PoolVector.h>
#include <framework/devicehandlers/AcceptsDeviceResponsesIF.h>
#include <framework/devicehandlers/DeviceHandlerBase.h> #include <framework/devicehandlers/DeviceHandlerBase.h>
#include <framework/devicehandlers/DeviceTmReportingWrapper.h>
#include <framework/globalfunctions/CRC.h>
#include <framework/objectmanager/ObjectManager.h> #include <framework/objectmanager/ObjectManager.h>
#include <framework/storagemanager/StorageManagerIF.h> #include <framework/storagemanager/StorageManagerIF.h>
#include <framework/subsystem/SubsystemBase.h>
#include <framework/thermal/ThermalComponentIF.h> #include <framework/thermal/ThermalComponentIF.h>
#include <framework/devicehandlers/AcceptsDeviceResponsesIF.h>
#include <framework/datapool/DataSet.h>
#include <framework/datapool/PoolVariable.h>
#include <framework/devicehandlers/DeviceTmReportingWrapper.h>
#include <framework/globalfunctions/CRC.h>
#include <framework/subsystem/SubsystemBase.h>
#include <framework/ipc/QueueFactory.h> #include <framework/ipc/QueueFactory.h>
#include <framework/serviceinterface/ServiceInterfaceStream.h> #include <framework/serviceinterface/ServiceInterfaceStream.h>
@ -17,33 +17,34 @@ object_id_t DeviceHandlerBase::rawDataReceiverId = 0;
object_id_t DeviceHandlerBase::defaultFDIRParentId = 0; object_id_t DeviceHandlerBase::defaultFDIRParentId = 0;
DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId,
object_id_t deviceCommunication, CookieIF * comCookie_, object_id_t deviceCommunication, CookieIF * comCookie,
uint8_t setDeviceSwitch, uint32_t thermalStatePoolId, uint8_t setDeviceSwitch, uint32_t thermalStatePoolId,
uint32_t thermalRequestPoolId, FailureIsolationBase* fdirInstance, uint32_t thermalRequestPoolId, FailureIsolationBase* fdirInstance,
size_t cmdQueueSize) : size_t cmdQueueSize) :
SystemObject(setObjectId), mode(MODE_OFF), submode(SUBMODE_NONE), SystemObject(setObjectId), mode(MODE_OFF), submode(SUBMODE_NONE),
wiretappingMode(OFF), storedRawData(StorageManagerIF::INVALID_ADDRESS), wiretappingMode(OFF), storedRawData(StorageManagerIF::INVALID_ADDRESS),
deviceCommunicationId(deviceCommunication), comCookie(comCookie_), deviceCommunicationId(deviceCommunication), comCookie(comCookie),
deviceThermalStatePoolId(thermalStatePoolId), deviceThermalRequestPoolId(thermalRequestPoolId), deviceThermalStatePoolId(thermalStatePoolId),
healthHelper(this, setObjectId), modeHelper(this), parameterHelper(this), deviceThermalRequestPoolId(thermalRequestPoolId),
fdirInstance(fdirInstance), hkSwitcher(this), healthHelper(this,setObjectId), modeHelper(this), parameterHelper(this),
defaultFDIRUsed(fdirInstance == nullptr), switchOffWasReported(false), childTransitionFailure(RETURN_OK), fdirInstance(fdirInstance),
executingTask(nullptr), actionHelper(this, nullptr), cookieInfo(), hkSwitcher(this), defaultFDIRUsed(fdirInstance == nullptr),
childTransitionDelay(5000), transitionSourceMode(_MODE_POWER_DOWN), switchOffWasReported(false), actionHelper(this, nullptr), cookieInfo(),
transitionSourceSubMode(SUBMODE_NONE), deviceSwitch(setDeviceSwitch) childTransitionDelay(5000),
{ transitionSourceMode(_MODE_POWER_DOWN), transitionSourceSubMode(
commandQueue = QueueFactory::instance()-> SUBMODE_NONE), deviceSwitch(setDeviceSwitch) {
createMessageQueue(cmdQueueSize, CommandMessage::MAX_MESSAGE_SIZE); commandQueue = QueueFactory::instance()->createMessageQueue(cmdQueueSize,
CommandMessage::MAX_MESSAGE_SIZE);
cookieInfo.state = COOKIE_UNUSED; cookieInfo.state = COOKIE_UNUSED;
insertInCommandMap(RAW_COMMAND_ID); insertInCommandMap(RAW_COMMAND_ID);
if (this->fdirInstance == nullptr) { if (this->fdirInstance == nullptr) {
this->fdirInstance = this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId,
new DeviceHandlerFailureIsolation(setObjectId, defaultFDIRParentId);
defaultFDIRParentId);
} }
} }
DeviceHandlerBase::~DeviceHandlerBase() { DeviceHandlerBase::~DeviceHandlerBase() {
//communicationInterface->close(cookie);
delete comCookie; delete comCookie;
if (defaultFDIRUsed) { if (defaultFDIRUsed) {
delete fdirInstance; delete fdirInstance;
@ -53,7 +54,8 @@ DeviceHandlerBase::~DeviceHandlerBase() {
ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) { ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) {
this->pstStep = counter; this->pstStep = counter;
if (counter == 0) {
if (getComAction() == SEND_WRITE) {
cookieInfo.state = COOKIE_UNUSED; cookieInfo.state = COOKIE_UNUSED;
readCommandQueue(); readCommandQueue();
doStateMachine(); doStateMachine();
@ -66,7 +68,6 @@ ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) {
if (mode == MODE_OFF) { if (mode == MODE_OFF) {
return RETURN_OK; return RETURN_OK;
} }
switch (getComAction()) { switch (getComAction()) {
case SEND_WRITE: case SEND_WRITE:
if ((cookieInfo.state == COOKIE_UNUSED)) { if ((cookieInfo.state == COOKIE_UNUSED)) {
@ -87,7 +88,6 @@ ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) {
default: default:
break; break;
} }
return RETURN_OK; return RETURN_OK;
} }
@ -116,7 +116,7 @@ ReturnValue_t DeviceHandlerBase::initialize() {
AcceptsDeviceResponsesIF *rawReceiver = objectManager->get< AcceptsDeviceResponsesIF *rawReceiver = objectManager->get<
AcceptsDeviceResponsesIF>(rawDataReceiverId); AcceptsDeviceResponsesIF>(rawDataReceiverId);
if (rawReceiver == nullptr) { if (rawReceiver == NULL) {
return RETURN_FAILED; return RETURN_FAILED;
} }
@ -166,6 +166,7 @@ ReturnValue_t DeviceHandlerBase::initialize() {
mySet.commit(PoolVariableIF::VALID); mySet.commit(PoolVariableIF::VALID);
return RETURN_OK; return RETURN_OK;
} }
void DeviceHandlerBase::decrementDeviceReplyMap() { void DeviceHandlerBase::decrementDeviceReplyMap() {
@ -353,8 +354,8 @@ ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId,
info.delayCycles = 0; info.delayCycles = 0;
info.replyLen = replyLen; info.replyLen = replyLen;
info.command = deviceCommandMap.end(); info.command = deviceCommandMap.end();
std::pair<DeviceReplyIter, bool> result = deviceReplyMap.emplace(replyId, info); auto resultPair = deviceReplyMap.emplace(replyId, info);
if (result.second) { if (resultPair.second) {
return RETURN_OK; return RETURN_OK;
} else { } else {
return RETURN_FAILED; return RETURN_FAILED;
@ -366,8 +367,8 @@ ReturnValue_t DeviceHandlerBase::insertInCommandMap(DeviceCommandId_t deviceComm
info.expectedReplies = 0; info.expectedReplies = 0;
info.isExecuting = false; info.isExecuting = false;
info.sendReplyTo = NO_COMMANDER; info.sendReplyTo = NO_COMMANDER;
std::pair<DeviceCommandIter, bool> result = deviceCommandMap.emplace(deviceCommand,info); auto resultPair = deviceCommandMap.emplace(deviceCommand, info);
if (result.second) { if (resultPair.second) {
return RETURN_OK; return RETURN_OK;
} else { } else {
return RETURN_FAILED; return RETURN_FAILED;
@ -487,7 +488,7 @@ void DeviceHandlerBase::replyToReply(DeviceReplyMap::iterator iter,
return; return;
} }
//Check if more replies are expected. If so, do nothing. //Check if more replies are expected. If so, do nothing.
DeviceCommandInfo * info = &(iter->second.command->second); DeviceCommandInfo* info = &(iter->second.command->second);
if (--info->expectedReplies == 0) { if (--info->expectedReplies == 0) {
//Check if it was transition or internal command. Don't send any replies in that case. //Check if it was transition or internal command. Don't send any replies in that case.
if (info->sendReplyTo != NO_COMMANDER) { if (info->sendReplyTo != NO_COMMANDER) {
@ -526,6 +527,7 @@ void DeviceHandlerBase::doGetWrite() {
if (wiretappingMode == RAW) { if (wiretappingMode == RAW) {
replyRawData(rawPacket, rawPacketLen, requestedRawTraffic, true); replyRawData(rawPacket, rawPacketLen, requestedRawTraffic, true);
} }
//We need to distinguish here, because a raw command never expects a reply. //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. //(Could be done in eRIRM, but then child implementations need to be careful.
result = enableReplyInReplyMap(cookieInfo.pendingCommand); result = enableReplyInReplyMap(cookieInfo.pendingCommand);
@ -541,25 +543,22 @@ void DeviceHandlerBase::doGetWrite() {
} }
void DeviceHandlerBase::doSendRead() { void DeviceHandlerBase::doSendRead() {
ReturnValue_t result = RETURN_FAILED; ReturnValue_t result;
size_t requestLen = 0; size_t requestLen = 0;
// If the device handler can only request replies after a command DeviceReplyIter iter = deviceReplyMap.find(cookieInfo.pendingCommand->first);
// has been sent, there should be only one reply enabled and the if(iter != deviceReplyMap.end()) {
// correct reply length will be mapped. requestLen = iter->second.replyLen;
for(DeviceReplyIter iter = deviceReplyMap.begin(); }
iter != deviceReplyMap.end();iter++) else {
{ requestLen = 0;
if(iter->second.delayCycles != 0) {
requestLen = iter->second.replyLen;
break;
}
} }
result = communicationInterface->requestReceiveMessage(comCookie, requestLen); result = communicationInterface->requestReceiveMessage(comCookie, requestLen);
if (result == RETURN_OK) { if (result == RETURN_OK) {
cookieInfo.state = COOKIE_READ_SENT; cookieInfo.state = COOKIE_READ_SENT;
} } else {
else {
triggerEvent(DEVICE_REQUESTING_REPLY_FAILED, result); triggerEvent(DEVICE_REQUESTING_REPLY_FAILED, result);
//We can't inform anyone, because we don't know which command was sent last. //We can't inform anyone, because we don't know which command was sent last.
//So, we need to wait for a timeout. //So, we need to wait for a timeout.
@ -583,8 +582,8 @@ void DeviceHandlerBase::doGetRead() {
cookieInfo.state = COOKIE_UNUSED; cookieInfo.state = COOKIE_UNUSED;
result = communicationInterface->readReceivedMessage(comCookie, &receivedData, result = communicationInterface->readReceivedMessage(comCookie,
&receivedDataLen); &receivedData, &receivedDataLen);
if (result != RETURN_OK) { if (result != RETURN_OK) {
triggerEvent(DEVICE_REQUESTING_REPLY_FAILED, result); triggerEvent(DEVICE_REQUESTING_REPLY_FAILED, result);
@ -644,7 +643,7 @@ void DeviceHandlerBase::doGetRead() {
} }
ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress, ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress,
uint8_t ** data, size_t * len) { uint8_t * *data, uint32_t * len) {
size_t lenTmp; size_t lenTmp;
if (IPCStore == NULL) { if (IPCStore == NULL) {
@ -663,10 +662,8 @@ ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress,
*len = 0; *len = 0;
return result; return result;
} }
} }
void DeviceHandlerBase::replyRawData(const uint8_t *data, size_t len, void DeviceHandlerBase::replyRawData(const uint8_t *data, size_t len,
MessageQueueId_t sendTo, bool isCommand) { MessageQueueId_t sendTo, bool isCommand) {
if (IPCStore == NULL || len == 0) { if (IPCStore == NULL || len == 0) {
@ -681,6 +678,7 @@ void DeviceHandlerBase::replyRawData(const uint8_t *data, size_t len,
} }
CommandMessage message; CommandMessage message;
DeviceHandlerMessage::setDeviceHandlerRawReplyMessage(&message, DeviceHandlerMessage::setDeviceHandlerRawReplyMessage(&message,
getObjectId(), address, isCommand); getObjectId(), address, isCommand);
@ -690,14 +688,12 @@ void DeviceHandlerBase::replyRawData(const uint8_t *data, size_t len,
if (result != RETURN_OK) { if (result != RETURN_OK) {
IPCStore->deleteData(address); IPCStore->deleteData(address);
// Silently discard data, this indicates heavy TM traffic which should //Silently discard data, this indicates heavy TM traffic which should not be increased by additional events.
// not be increased by additional events.
} }
} }
//Default child implementations //Default child implementations
DeviceHandlerIF::CommunicationAction_t DeviceHandlerBase::getComAction() {
DeviceHandlerBase::CommunicationAction_t DeviceHandlerBase::getComAction() {
switch (pstStep) { switch (pstStep) {
case 0: case 0:
return SEND_WRITE; return SEND_WRITE;
@ -762,8 +758,8 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData,
// DeviceCommunicationIF>(newChannelId); // DeviceCommunicationIF>(newChannelId);
// //
// if (newCommunication != NULL) { // if (newCommunication != NULL) {
// ReturnValue_t result = newCommunication->reOpen(cookie, logicalAddress, // ReturnValue_t result = newCommunication->reOpen(cookie, ioBoardAddress,
// maxDeviceReplyLen, comParameter1, comParameter2); // maxDeviceReplyLen);
// if (result != RETURN_OK) { // if (result != RETURN_OK) {
// return result; // return result;
// } // }
@ -780,8 +776,8 @@ void DeviceHandlerBase::buildRawDeviceCommand(CommandMessage* commandMessage) {
replyReturnvalueToCommand(result, RAW_COMMAND_ID); replyReturnvalueToCommand(result, RAW_COMMAND_ID);
storedRawData.raw = StorageManagerIF::INVALID_ADDRESS; storedRawData.raw = StorageManagerIF::INVALID_ADDRESS;
} else { } else {
cookieInfo.pendingCommand = deviceCommandMap. cookieInfo.pendingCommand = deviceCommandMap.find(
find((DeviceCommandId_t) RAW_COMMAND_ID); (DeviceCommandId_t) RAW_COMMAND_ID);
cookieInfo.pendingCommand->second.isExecuting = true; cookieInfo.pendingCommand->second.isExecuting = true;
cookieInfo.state = COOKIE_WRITE_READY; cookieInfo.state = COOKIE_WRITE_READY;
} }
@ -820,7 +816,7 @@ ReturnValue_t DeviceHandlerBase::enableReplyInReplyMap(
iter = deviceReplyMap.find(command->first); iter = deviceReplyMap.find(command->first);
} }
if (iter != deviceReplyMap.end()) { if (iter != deviceReplyMap.end()) {
DeviceReplyInfo * info = &(iter->second); DeviceReplyInfo *info = &(iter->second);
info->delayCycles = info->maxDelayCycles; info->delayCycles = info->maxDelayCycles;
info->command = command; info->command = command;
command->second.expectedReplies = expectedReplies; command->second.expectedReplies = expectedReplies;
@ -846,9 +842,8 @@ ReturnValue_t DeviceHandlerBase::getStateOfSwitches(void) {
ReturnValue_t result = getSwitches(&switches, &numberOfSwitches); ReturnValue_t result = getSwitches(&switches, &numberOfSwitches);
if ((result == RETURN_OK) && (numberOfSwitches != 0)) { if ((result == RETURN_OK) && (numberOfSwitches != 0)) {
while (numberOfSwitches > 0) { while (numberOfSwitches > 0) {
if (powerSwitcher-> getSwitchState(switches[numberOfSwitches - 1]) if (powerSwitcher->getSwitchState(switches[numberOfSwitches - 1])
== PowerSwitchIF::SWITCH_OFF) == PowerSwitchIF::SWITCH_OFF) {
{
return PowerSwitchIF::SWITCH_OFF; return PowerSwitchIF::SWITCH_OFF;
} }
numberOfSwitches--; numberOfSwitches--;
@ -1032,7 +1027,6 @@ void DeviceHandlerBase::replyRawReplyIfnotWiretapped(const uint8_t* data,
ReturnValue_t DeviceHandlerBase::handleDeviceHandlerMessage( ReturnValue_t DeviceHandlerBase::handleDeviceHandlerMessage(
CommandMessage * message) { CommandMessage * message) {
ReturnValue_t result;
switch (message->getCommand()) { switch (message->getCommand()) {
case DeviceHandlerMessage::CMD_WIRETAPPING: case DeviceHandlerMessage::CMD_WIRETAPPING:
switch (DeviceHandlerMessage::getWiretappingMode(message)) { switch (DeviceHandlerMessage::getWiretappingMode(message)) {
@ -1054,21 +1048,19 @@ ReturnValue_t DeviceHandlerBase::handleDeviceHandlerMessage(
} }
replyReturnvalueToCommand(RETURN_OK); replyReturnvalueToCommand(RETURN_OK);
return RETURN_OK; return RETURN_OK;
case DeviceHandlerMessage::CMD_SWITCH_ADDRESS: // case DeviceHandlerMessage::CMD_SWITCH_IOBOARD:
if (mode != MODE_OFF) { // if (mode != MODE_OFF) {
replyReturnvalueToCommand(WRONG_MODE_FOR_COMMAND); // replyReturnvalueToCommand(WRONG_MODE_FOR_COMMAND);
} else { // } else {
// rework in progress // result = switchCookieChannel(
result = RETURN_OK; // DeviceHandlerMessage::getIoBoardObjectId(message));
//result = switchCookieChannel( // if (result == RETURN_OK) {
// DeviceHandlerMessage::getIoBoardObjectId(message)); // replyReturnvalueToCommand(RETURN_OK);
if (result == RETURN_OK) { // } else {
replyReturnvalueToCommand(RETURN_OK); // replyReturnvalueToCommand(CANT_SWITCH_IO_ADDRESS);
} else { // }
replyReturnvalueToCommand(CANT_SWITCH_ADDRESS); // }
} // return RETURN_OK;
}
return RETURN_OK;
case DeviceHandlerMessage::CMD_RAW: case DeviceHandlerMessage::CMD_RAW:
if ((mode != MODE_RAW)) { if ((mode != MODE_RAW)) {
DeviceHandlerMessage::clear(message); DeviceHandlerMessage::clear(message);
@ -1124,7 +1116,8 @@ void DeviceHandlerBase::handleDeviceTM(SerializeIF* data,
// hiding of sender needed so the service will handle it as unexpected Data, no matter what state // hiding of sender needed so the service will handle it as unexpected Data, no matter what state
//(progress or completed) it is in //(progress or completed) it is in
actionHelper.reportData(defaultRawReceiver, replyId, &wrapper, true); actionHelper.reportData(defaultRawReceiver, replyId, &wrapper,
true);
} }
} else { //unrequested/aperiodic replies } else { //unrequested/aperiodic replies
@ -1152,7 +1145,6 @@ ReturnValue_t DeviceHandlerBase::executeAction(ActionId_t actionId,
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
DeviceCommandMap::iterator iter = deviceCommandMap.find(actionId); DeviceCommandMap::iterator iter = deviceCommandMap.find(actionId);
if (iter == deviceCommandMap.end()) { if (iter == deviceCommandMap.end()) {
result = COMMAND_NOT_SUPPORTED; result = COMMAND_NOT_SUPPORTED;
@ -1171,7 +1163,7 @@ ReturnValue_t DeviceHandlerBase::executeAction(ActionId_t actionId,
} }
void DeviceHandlerBase::buildInternalCommand(void) { void DeviceHandlerBase::buildInternalCommand(void) {
// Neither Raw nor Direct could build a command //Neither Raw nor Direct could build a command
ReturnValue_t result = NOTHING_TO_SEND; ReturnValue_t result = NOTHING_TO_SEND;
DeviceCommandId_t deviceCommandId = NO_COMMAND_ID; DeviceCommandId_t deviceCommandId = NO_COMMAND_ID;
if (mode == MODE_NORMAL) { if (mode == MODE_NORMAL) {
@ -1189,13 +1181,12 @@ void DeviceHandlerBase::buildInternalCommand(void) {
} else { } else {
return; return;
} }
if (result == NOTHING_TO_SEND) { if (result == NOTHING_TO_SEND) {
return; return;
} }
if (result == RETURN_OK) { if (result == RETURN_OK) {
DeviceCommandMap::iterator iter = DeviceCommandMap::iterator iter = deviceCommandMap.find(
deviceCommandMap.find(deviceCommandId); deviceCommandId);
if (iter == deviceCommandMap.end()) { if (iter == deviceCommandMap.end()) {
result = COMMAND_NOT_SUPPORTED; result = COMMAND_NOT_SUPPORTED;
} else if (iter->second.isExecuting) { } else if (iter->second.isExecuting) {
@ -1210,7 +1201,6 @@ void DeviceHandlerBase::buildInternalCommand(void) {
cookieInfo.state = COOKIE_WRITE_READY; cookieInfo.state = COOKIE_WRITE_READY;
} }
} }
if (result != RETURN_OK) { if (result != RETURN_OK) {
triggerEvent(DEVICE_BUILDING_COMMAND_FAILED, result, deviceCommandId); triggerEvent(DEVICE_BUILDING_COMMAND_FAILED, result, deviceCommandId);
} }
@ -1285,8 +1275,8 @@ void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task_){
executingTask = task_; executingTask = task_;
} }
void DeviceHandlerBase::debugInterface(uint8_t positionTracker, object_id_t objectId, uint32_t parameter) { // Default implementations empty.
} void DeviceHandlerBase::debugInterface(uint8_t positionTracker,
object_id_t objectId, uint32_t parameter) {}
void DeviceHandlerBase::performOperationHook() { void DeviceHandlerBase::performOperationHook() {}
}

View File

@ -1,26 +1,23 @@
#ifndef DEVICEHANDLERBASE_H_ #ifndef DEVICEHANDLERBASE_H_
#define DEVICEHANDLERBASE_H_ #define DEVICEHANDLERBASE_H_
#include <framework/action/ActionHelper.h> #include <framework/objectmanager/SystemObject.h>
#include <framework/tasks/ExecutableObjectIF.h>
#include <framework/devicehandlers/DeviceHandlerIF.h>
#include <framework/returnvalues/HasReturnvaluesIF.h>
#include <framework/action/HasActionsIF.h> #include <framework/action/HasActionsIF.h>
#include <framework/datapool/DataSet.h>
#include <framework/datapool/PoolVariableIF.h> #include <framework/datapool/PoolVariableIF.h>
#include <framework/devicehandlers/DeviceCommunicationIF.h> #include <framework/devicehandlers/DeviceCommunicationIF.h>
#include <framework/devicehandlers/DeviceHandlerIF.h>
#include <framework/health/HealthHelper.h>
#include <framework/modes/HasModesIF.h> #include <framework/modes/HasModesIF.h>
#include <framework/objectmanager/SystemObject.h>
#include <framework/objectmanager/SystemObjectIF.h>
#include <framework/parameters/ParameterHelper.h>
#include <framework/power/PowerSwitchIF.h> #include <framework/power/PowerSwitchIF.h>
#include <framework/returnvalues/HasReturnvaluesIF.h>
#include <framework/tasks/ExecutableObjectIF.h>
#include <framework/devicehandlers/DeviceHandlerFailureIsolation.h>
#include <framework/datapool/HkSwitchHelper.h>
#include <framework/devicehandlers/CookieIF.h>
#include <framework/serialize/SerialFixedArrayListAdapter.h>
#include <framework/ipc/MessageQueueIF.h> #include <framework/ipc/MessageQueueIF.h>
#include <framework/tasks/PeriodicTaskIF.h>
#include <framework/action/ActionHelper.h>
#include <framework/health/HealthHelper.h>
#include <framework/parameters/ParameterHelper.h>
#include <framework/datapool/HkSwitchHelper.h>
#include <framework/devicehandlers/DeviceHandlerFailureIsolation.h>
#include <map> #include <map>
namespace Factory{ namespace Factory{
@ -92,21 +89,22 @@ public:
* The constructor passes the objectId to the SystemObject(). * The constructor passes the objectId to the SystemObject().
* *
* @param setObjectId the ObjectId to pass to the SystemObject() Constructor * @param setObjectId the ObjectId to pass to the SystemObject() Constructor
* @param maxDeviceReplyLen the largest allowed reply size * @param maxDeviceReplyLen the length the RMAP getRead call will be sent with
* @param setDeviceSwitch the switch the device is connected to, * @param setDeviceSwitch the switch the device is connected to,
* for devices using two switches, overwrite getSwitches() * for devices using two switches, overwrite getSwitches()
* @param deviceCommuncation Communcation Interface object which is * @param deviceCommuncation Communcation Interface object which is used
* used to implement communication functions * to implement communication functions
* @param thermalStatePoolId * @param thermalStatePoolId
* @param thermalRequestPoolId * @param thermalRequestPoolId
* @param fdirInstance * @param fdirInstance
* @param cmdQueueSize * @param cmdQueueSize
*/ */
DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication,
CookieIF * comCookie_, uint8_t setDeviceSwitch, CookieIF * comCookie, uint8_t setDeviceSwitch,
uint32_t thermalStatePoolId = PoolVariableIF::NO_PARAMETER, uint32_t thermalStatePoolId = PoolVariableIF::NO_PARAMETER,
uint32_t thermalRequestPoolId = PoolVariableIF::NO_PARAMETER, uint32_t thermalRequestPoolId = PoolVariableIF::NO_PARAMETER,
FailureIsolationBase* fdirInstance = nullptr, size_t cmdQueueSize = 20); FailureIsolationBase* fdirInstance = nullptr,
size_t cmdQueueSize = 20);
/** /**
* @brief This function is the device handler base core component and is * @brief This function is the device handler base core component and is
@ -213,12 +211,13 @@ protected:
/** /**
* Build the device command to send for normal mode. * 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, * This is only called in @c MODE_NORMAL. If multiple submodes for
* different commands can built returned depending on the submode. * @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. * #rawPacket and #rawPacketLen must be set by this method to the
* If variable command frequence is required, a counter can be used and * packet to be sent. If variable command frequence is required, a counter
* the frequency in the reply map has to be set manually * can be used and the frequency in the reply map has to be set manually
* by calling updateReplyMap(). * by calling updateReplyMap().
* *
* @param[out] id the device command id that has been built * @param[out] id the device command id that has been built
@ -233,10 +232,13 @@ protected:
* Build the device command to send for a transitional mode. * 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, * This is only called in @c _MODE_TO_NORMAL, @c _MODE_TO_ON, @c _MODE_TO_RAW,
* @c _MODE_START_UP and @c _MODE_TO_POWER_DOWN. So it is used by doStartUp() and doShutDown() as well as doTransition() * @c _MODE_START_UP and @c _MODE_TO_POWER_DOWN. So it is used by doStartUp()
* and doShutDown() as well as doTransition()
* *
* 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 * A good idea is to implement a flag indicating a command has to be built
* and filling them in doStartUp(), doShutDown() and doTransition() so no modes have to be checked here. * 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. * #rawPacket and #rawPacketLen must be set by this method to the packet to be sent.
* *
@ -266,6 +268,63 @@ protected:
virtual ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, virtual ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand,
const uint8_t * commandData, size_t commandDataLen) = 0; const uint8_t * commandData, size_t commandDataLen) = 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;
/**
* @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 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;
/** /**
* @brief fill the #deviceCommandMap * @brief fill the #deviceCommandMap
* called by the initialize() of the base class * called by the initialize() of the base class
@ -312,85 +371,83 @@ protected:
virtual void fillCommandAndReplyMap() = 0; virtual void fillCommandAndReplyMap() = 0;
/** /**
* @brief Scans a buffer for a valid reply. * This is a helper method to facilitate inserting entries in the command map.
* @details * @param deviceCommand Identifier of the command to add.
* This is used by the base class to check the data received for valid packets. * @param maxDelayCycles The maximum number of delay cycles the command
* It only checks if a valid packet starts at @c start. * waits until it times out.
* It also only checks the structural validy of the packet, * @param periodic Indicates if the command is periodic (i.e. it is sent
* e.g. checksums lengths and protocol data. * by the device repeatedly without request) or not. Default is aperiodic (0)
* No information check is done, e.g. range checks etc. * @return - @c RETURN_OK when the command was successfully inserted,
* * - @c RETURN_FAILED else.
* Errors should be reported directly, the base class does NOT report
* any errors based on the returnvalue 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 remainingSize, ReturnValue_t insertInCommandAndReplyMap(DeviceCommandId_t deviceCommand,
DeviceCommandId_t *foundId, size_t *foundLen) = 0; uint16_t maxDelayCycles, size_t replyLen = 0, uint8_t periodic = 0,
bool hasDifferentReplyId = false, DeviceCommandId_t replyId = 0);
/** /**
* @brief Interpret a reply from the device. * @brief This is a helper method to insert replies in the reply map.
* @details * @param deviceCommand Identifier of the reply to add.
* This is called after scanForReply() found a valid packet, it can be assumed that the length and structure is valid. * @param maxDelayCycles The maximum number of delay cycles the reply waits
* This routine extracts the data from the packet into a DataSet and then calls handleDeviceTM(), which either sends * until it times out.
* a TM packet or stores the data in the DataPool depending on whether the it was an external command. * @param periodic Indicates if the command is periodic (i.e. it is sent
* No packet length is given, as it should be defined implicitly by the id. * by the device repeatedly without request) or not. Default is aperiodic (0)
* * @return - @c RETURN_OK when the command was successfully inserted,
* @param id the id found by scanForReply() * - @c RETURN_FAILED else.
* @param packet
* @return
* - @c RETURN_OK when the reply was interpreted.
* - @c RETURN_FAILED when the reply could not be interpreted, eg. logical errors or range violations occurred
*/ */
virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand,
const uint8_t *packet) = 0; uint16_t maxDelayCycles, size_t replyLen = 0, uint8_t periodic = 0);
/** /**
* set all datapool variables that are update periodically in normal mode invalid * @brief A simple command to add a command to the commandList.
* * @param deviceCommand The command to add
* Child classes should provide an implementation which sets all those variables invalid * @return - @c RETURN_OK when the command was successfully inserted,
* which are set periodically during any normal mode. * - @c RETURN_FAILED else.
*/ */
virtual void setNormalDatapoolEntriesInvalid() = 0; 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,
uint8_t periodic = 0);
/** /**
* @brief Can be implemented by child handler to * @brief Can be implemented by child handler to
* perform debugging * perform debugging
* @details Example: Calling this in performOperation * @details Example: Calling this in performOperation
* to track values like mode. * to track values like mode.
* @param positionTracker Provide the child handler a way to know where the debugInterface was called * @param positionTracker Provide the child handler a way to know
* @param objectId Provide the child handler object Id to specify actions for spefic devices * where the debugInterface was called
* @param parameter Supply a parameter of interest * @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 ! * 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); 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. * Get the time needed to transit from modeFrom to modeTo.
* *
* Used for the following transitions: * Used for the following transitions:
* modeFrom -> modeTo: * modeFrom -> modeTo:
* - MODE_ON -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] * MODE_ON -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN]
* - MODE_NORMAL -> [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_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) * _MODE_START_UP -> MODE_ON (do not include time to set the switches,
* the base class got you covered)
* *
* The default implementation returns 0 ! * The default implementation returns 0 !
* @param modeFrom * @param modeFrom
@ -408,39 +465,26 @@ protected:
* @param[out] numberOfSwitches length of returned array * @param[out] numberOfSwitches length of returned array
* @return * @return
* - @c RETURN_OK if the parameters were set * - @c RETURN_OK if the parameters were set
* - @c NO_SWITCH or any other returnvalue if no switches exist * - @c RETURN_FAILED if no switches exist
*/ */
virtual ReturnValue_t getSwitches(const uint8_t **switches, virtual ReturnValue_t getSwitches(const uint8_t **switches,
uint8_t *numberOfSwitches); uint8_t *numberOfSwitches);
/** /**
* Can be used to perform device specific periodic operations. * @brief Hook function for child handlers which is called once per
* This is called on the SEND_READ step of the performOperation() call * performOperation(). Default implementation is empty.
*/ */
virtual void performOperationHook(); virtual void performOperationHook();
/**
* The Returnvalues id of this class, required by HasReturnvaluesIF
*/
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE;
public: public:
/** /**
* @param parentQueueId * @param parentQueueId
*/ */
virtual void setParentQueue(MessageQueueId_t parentQueueId); virtual void setParentQueue(MessageQueueId_t parentQueueId);
/** /** @brief Implementation required for HasActionIF */
* This function call handles the execution of external commands as required
* by the HasActionIF.
* @param actionId
* @param commandedBy
* @param data
* @param size
* @return
*/
ReturnValue_t executeAction(ActionId_t actionId, ReturnValue_t executeAction(ActionId_t actionId,
MessageQueueId_t commandedBy, const uint8_t* data, size_t size); MessageQueueId_t commandedBy, const uint8_t* data,
size_t size) override;
Mode_t getTransitionSourceMode() const; Mode_t getTransitionSourceMode() const;
Submode_t getTransitionSourceSubMode() const; Submode_t getTransitionSourceSubMode() const;
@ -460,6 +504,28 @@ public:
virtual MessageQueueId_t getCommandQueue(void) const; virtual MessageQueueId_t getCommandQueue(void) const;
protected: protected:
/**
* The Returnvalues id of this class, required by HasReturnvaluesIF
*/
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE;
/**
* These returnvalues can be returned from abstract functions
* to alter the behaviour of DHB.For error values, refer to
* DeviceHandlerIF.h returnvalues.
*/
static const ReturnValue_t INVALID_CHANNEL = MAKE_RETURN_CODE(4);
// Returnvalues for scanForReply()
static const ReturnValue_t APERIODIC_REPLY = MAKE_RETURN_CODE(5); //!< 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(6); //!< Ignore parts of the received packet
static const ReturnValue_t IGNORE_FULL_PACKET = MAKE_RETURN_CODE(7); //!< Ignore full received packet
// static const ReturnValue_t ONE_SWITCH = MAKE_RETURN_CODE(8);
// static const ReturnValue_t TWO_SWITCHES = MAKE_RETURN_CODE(9);
static const ReturnValue_t NO_SWITCH = MAKE_RETURN_CODE(10);
static const ReturnValue_t COMMAND_MAP_ERROR = MAKE_RETURN_CODE(11);
static const ReturnValue_t NOTHING_TO_SEND = MAKE_RETURN_CODE(12);
//Mode handling error Codes //Mode handling error Codes
static const ReturnValue_t CHILD_TIMEOUT = MAKE_RETURN_CODE(0xE1); static const ReturnValue_t CHILD_TIMEOUT = MAKE_RETURN_CODE(0xE1);
static const ReturnValue_t SWITCH_FAILED = MAKE_RETURN_CODE(0xE2); static const ReturnValue_t SWITCH_FAILED = MAKE_RETURN_CODE(0xE2);
@ -475,7 +541,7 @@ protected:
/** /**
* Size of the #rawPacket. * Size of the #rawPacket.
*/ */
size_t rawPacketLen = 0; uint32_t rawPacketLen = 0;
/** /**
* The mode the device handler is currently in. * The mode the device handler is currently in.
@ -502,7 +568,7 @@ protected:
* indicates either that all raw messages to and from the device should be sent to #theOneWhoWantsToReadRawTraffic * indicates either that all raw messages to and from the device should be sent to #theOneWhoWantsToReadRawTraffic
* or that all device TM should be downlinked to #theOneWhoWantsToReadRawTraffic * or that all device TM should be downlinked to #theOneWhoWantsToReadRawTraffic
*/ */
enum WiretappingMode: uint8_t { enum WiretappingMode {
OFF = 0, RAW = 1, TM = 2 OFF = 0, RAW = 1, TM = 2
} wiretappingMode; } wiretappingMode;
@ -543,21 +609,19 @@ protected:
/** /**
* Communication object used for device communication * Communication object used for device communication
*/ */
DeviceCommunicationIF *communicationInterface = nullptr; DeviceCommunicationIF * communicationInterface = nullptr;
/** /**
* Cookie used for communication. This is passed to the communication * Cookie used for communication
* interface.
*/ */
CookieIF *comCookie; CookieIF * comCookie;
struct DeviceCommandInfo { struct DeviceCommandInfo {
bool isExecuting; //!< Indicates if the command is already executing. bool isExecuting; //!< Indicates if the command is already executing.
uint8_t expectedReplies; //!< Dynamic value to indicate how many replies are expected. Inititated with 0. uint8_t expectedReplies; //!< Dynamic value to indicate how many replies are expected. Inititated with 0.
MessageQueueId_t sendReplyTo; //!< if this is != NO_COMMANDER, DHB was commanded externally and shall report everything to commander. MessageQueueId_t sendReplyTo; //!< if this is != NO_COMMANDER, DHB was commanded externally and shall report everything to commander.
}; };
typedef std::map<DeviceCommandId_t, DeviceCommandInfo> DeviceCommandMap; using DeviceCommandMap = std::map<DeviceCommandId_t, DeviceCommandInfo> ;
typedef DeviceCommandMap::iterator DeviceCommandIter;
/** /**
* @brief Information about expected replies * @brief Information about expected replies
@ -568,15 +632,12 @@ protected:
uint16_t maxDelayCycles; //!< The maximum number of cycles the handler should wait for a reply to this command. uint16_t maxDelayCycles; //!< The maximum number of cycles the handler should wait for a reply to this command.
uint16_t delayCycles; //!< The currently remaining cycles the handler should wait for a reply, 0 means there is no reply expected uint16_t delayCycles; //!< The currently remaining cycles the handler should wait for a reply, 0 means there is no reply expected
size_t replyLen = 0; //!< Expected size of the reply. size_t replyLen = 0; //!< Expected size of the reply.
//(Robin): This is a flag, isnt it? could we declare it bool? uint8_t always
// gives away the impression that this variable is more than a simple flag
// and true/false are also more explicit.
uint8_t periodic; //!< if this is !=0, the delayCycles will not be reset to 0 but to maxDelayCycles uint8_t periodic; //!< if this is !=0, the delayCycles will not be reset to 0 but to maxDelayCycles
DeviceCommandMap::iterator command; //!< The command that expects this reply. DeviceCommandMap::iterator command; //!< The command that expects this reply.
}; };
typedef std::map<DeviceCommandId_t, DeviceReplyInfo> DeviceReplyMap; using DeviceReplyMap = std::map<DeviceCommandId_t, DeviceReplyInfo> ;
typedef DeviceReplyMap::iterator DeviceReplyIter; using DeviceReplyIter = DeviceReplyMap::iterator;
/** /**
* The MessageQueue used to receive device handler commands and to send replies. * The MessageQueue used to receive device handler commands and to send replies.
@ -610,7 +671,7 @@ protected:
* Optional Error code * Optional Error code
* Can be set in doStartUp(), doShutDown() and doTransition() to signal cause for Transition failure. * Can be set in doStartUp(), doShutDown() and doTransition() to signal cause for Transition failure.
*/ */
ReturnValue_t childTransitionFailure = RETURN_OK; ReturnValue_t childTransitionFailure;
uint32_t ignoreMissedRepliesCount = 0; //!< Counts if communication channel lost a reply, so some missed replys can be ignored. uint32_t ignoreMissedRepliesCount = 0; //!< Counts if communication channel lost a reply, so some missed replys can be ignored.
@ -622,35 +683,13 @@ protected:
bool switchOffWasReported; //!< Indicates if SWITCH_WENT_OFF was already thrown. bool switchOffWasReported; //!< Indicates if SWITCH_WENT_OFF was already thrown.
PeriodicTaskIF* executingTask;//!< 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.
static object_id_t powerSwitcherId; //!< Object which switches power on and off. static object_id_t powerSwitcherId; //!< Object which switches power on and off.
static object_id_t rawDataReceiverId; //!< Object which receives RAW data by default. static object_id_t rawDataReceiverId; //!< Object which receives RAW data by default.
static object_id_t defaultFDIRParentId; //!< 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.
/**
* 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);
/**
* @overload
* @param submode
*/
void setMode(Mode_t newMode, Submode_t submode);
/** /**
* Helper function to report a missed reply * Helper function to report a missed reply
* *
@ -671,14 +710,30 @@ protected:
void replyReturnvalueToCommand(ReturnValue_t status, void replyReturnvalueToCommand(ReturnValue_t status,
uint32_t parameter = 0); uint32_t parameter = 0);
/**
* Send reply to a command, differentiate between raw command
* and normal command.
* @param status
* @param parameter
*/
void replyToCommand(ReturnValue_t status, uint32_t parameter = 0); void replyToCommand(ReturnValue_t status, uint32_t parameter = 0);
/**
* 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);
/**
* @overload
* @param submode
*/
void setMode(Mode_t newMode, Submode_t submode);
/** /**
* Do the transition to the main modes (MODE_ON, MODE_NORMAL and MODE_RAW). * Do the transition to the main modes (MODE_ON, MODE_NORMAL and MODE_RAW).
* *
@ -708,55 +763,6 @@ protected:
*/ */
virtual void doTransition(Mode_t modeFrom, Submode_t subModeFrom); virtual void doTransition(Mode_t modeFrom, Submode_t subModeFrom);
/**
* 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 periodic Indicates if the reply is periodic (i.e. it is sent by the device repeatedly without request) or not.
* Default is aperiodic (0)
* @param hasDifferentReplyId
* @param replyId
* @return RETURN_OK when the command was successfully inserted, COMMAND_MAP_ERROR else.
*/
ReturnValue_t insertInCommandAndReplyMap(DeviceCommandId_t deviceCommand,
uint16_t maxDelayCycles, size_t replyLen = 0, uint8_t periodic = 0,
bool hasDifferentReplyId = false, DeviceCommandId_t replyId = 0);
/**
* 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 RETURN_OK when the command was successfully inserted, COMMAND_MAP_ERROR else.
*/
ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand,
uint16_t maxDelayCycles, size_t replyLen = 0, uint8_t periodic = 0);
/**
* A simple command to add a command to the commandList.
* @param deviceCommand The command to add
* @return RETURN_OK if the command was successfully inserted, RETURN_FAILED else.
*/
ReturnValue_t insertInCommandMap(DeviceCommandId_t deviceCommand);
/**
* 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 RETURN_OK when the reply was successfully updated, COMMAND_MAP_ERROR else.
*/
ReturnValue_t updateReplyMapEntry(DeviceCommandId_t deviceReply,
uint16_t delayCycles, uint16_t maxDelayCycles,
uint8_t periodic = 0);
/**
* 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);
/** /**
* Is the combination of mode and submode valid? * Is the combination of mode and submode valid?
* *
@ -776,6 +782,7 @@ protected:
* *
* @return The Rmap action to execute in this step * @return The Rmap action to execute in this step
*/ */
virtual CommunicationAction_t getComAction(); virtual CommunicationAction_t getComAction();
/** /**
@ -798,6 +805,14 @@ protected:
*/ */
virtual ReturnValue_t buildChildRawCommand(); virtual ReturnValue_t buildChildRawCommand();
/**
* 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);
/** /**
* Construct a command reply containing a raw reply. * Construct a command reply containing a raw reply.
* *
@ -861,6 +876,14 @@ protected:
*/ */
ReturnValue_t getStateOfSwitches(void); ReturnValue_t getStateOfSwitches(void);
/**
* set all datapool variables that are update periodically in normal mode invalid
*
* Child classes should provide an implementation which sets all those variables invalid
* which are set periodically during any normal mode.
*/
virtual void setNormalDatapoolEntriesInvalid() = 0;
/** /**
* build a list of sids and pass it to the #hkSwitcher * build a list of sids and pass it to the #hkSwitcher
*/ */
@ -889,6 +912,7 @@ protected:
virtual void startTransition(Mode_t mode, Submode_t submode); virtual void startTransition(Mode_t mode, Submode_t submode);
virtual void setToExternalControl(); virtual void setToExternalControl();
virtual void announceMode(bool recursive); virtual void announceMode(bool recursive);
virtual ReturnValue_t letChildHandleMessage(CommandMessage *message); virtual ReturnValue_t letChildHandleMessage(CommandMessage *message);
/** /**
@ -954,13 +978,12 @@ protected:
DeviceCommandMap deviceCommandMap; DeviceCommandMap deviceCommandMap;
ActionHelper actionHelper; ActionHelper actionHelper;
private: private:
/** /**
* State a cookie is in. * State a cookie is in.
* *
* Used to keep track of the state of the communication. * Used to keep track of the state of the RMAP communication.
*/ */
enum CookieState_t { enum CookieState_t {
COOKIE_UNUSED, //!< The Cookie is unused COOKIE_UNUSED, //!< The Cookie is unused
@ -1034,20 +1057,22 @@ private:
* - checks whether commanded mode transitions are required and calls handleCommandedModeTransition() * - 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 * - 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 (eg setting a timeout) are handled in setMode() * - actions that happen in transitions (eg setting a timeout) are handled in setMode()
* - Maybe export this into own class to increase modularity of software
* and reduce the massive class size ?
*/ */
void doStateMachine(void); void doStateMachine(void);
void buildRawDeviceCommand(CommandMessage* message); void buildRawDeviceCommand(CommandMessage* message);
void buildInternalCommand(void); void buildInternalCommand(void);
// /**
// * Send a reply with the current mode and submode.
// */
// void announceMode(void);
/** /**
* Decrement the counter for the timout of replies. * 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 * 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). * but not received).
* In case the reply is periodic, the counter is simply set back to a specified value.
*/ */
void decrementDeviceReplyMap(void); void decrementDeviceReplyMap(void);
@ -1114,8 +1139,8 @@ private:
* - @c RETURN_FAILED IPCStore is NULL * - @c RETURN_FAILED IPCStore is NULL
* - the return value from the IPCStore if it was not @c RETURN_OK * - the return value from the IPCStore if it was not @c RETURN_OK
*/ */
ReturnValue_t getStorageData(store_address_t storageAddress, ReturnValue_t getStorageData(store_address_t storageAddress, uint8_t **data,
uint8_t ** data, size_t * len); uint32_t *len);
/** /**
* set all switches returned by getSwitches() * set all switches returned by getSwitches()
@ -1144,16 +1169,9 @@ private:
* - @c RETURN_FAILED when cookies could not be changed, eg because the newChannel is not enabled * - @c RETURN_FAILED when cookies could not be changed, eg because the newChannel is not enabled
* - @c returnvalues of RMAPChannelIF::isActive() * - @c returnvalues of RMAPChannelIF::isActive()
*/ */
//ReturnValue_t switchCookieChannel(object_id_t newChannelId); ReturnValue_t switchCookieChannel(object_id_t newChannelId);
/**
* Handle device handler messages (e.g. commands sent by PUS Service 2)
* @param message
* @return
*/
ReturnValue_t handleDeviceHandlerMessage(CommandMessage *message); ReturnValue_t handleDeviceHandlerMessage(CommandMessage *message);
}; };
#endif /* DEVICEHANDLERBASE_H_ */ #endif /* DEVICEHANDLERBASE_H_ */

View File

@ -36,8 +36,8 @@ public:
* lastParnter information as destination. If there was no message received yet * lastParnter information as destination. If there was no message received yet
* (i.e. lastPartner is zero), an error code is returned. * (i.e. lastPartner is zero), an error code is returned.
* @param message A pointer to a previously created message, which is sent. * @param message A pointer to a previously created message, which is sent.
* \return RETURN_OK if ok * @return RETURN_OK if ok
* \return NO_REPLY_PARTNER Should return NO_REPLY_PARTNER if partner was found * @return NO_REPLY_PARTNER Should return NO_REPLY_PARTNER if partner was found
*/ */
virtual ReturnValue_t reply( MessageQueueMessage* message ) = 0; virtual ReturnValue_t reply( MessageQueueMessage* message ) = 0;
@ -53,10 +53,12 @@ public:
/** /**
* @brief This function reads available messages from the message queue. * @brief This function reads available messages from the message queue.
* @details If data is available it is stored in the passed message pointer. The message's * @details
* original content is overwritten and the sendFrom information is stored in the * If data is available it is stored in the passed message pointer.
* lastPartner attribute. Else, the lastPartner information remains untouched, the * The message's original content is overwritten and the sendFrom
* message's content is cleared and the function returns immediately. * information is stored in theblastPartner attribute. Else, the lastPartner
* information remains untouched, the message's content is cleared and the
* function returns immediately.
* @param message A pointer to a message in which the received data is stored. * @param message A pointer to a message in which the received data is stored.
* @return -@c RETURN_OK on success * @return -@c RETURN_OK on success
* -@c MessageQueueIF::EMPTY if queue is empty * -@c MessageQueueIF::EMPTY if queue is empty
@ -90,7 +92,9 @@ public:
* @return -@c RETURN_OK on success * @return -@c RETURN_OK on success
* -@c MessageQueueIF::FULL if queue is full * -@c MessageQueueIF::FULL if queue is full
*/ */
virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom, bool ignoreFault = false ) = 0; virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueId_t sentFrom,
bool ignoreFault = false ) = 0;
/** /**
* @brief This operation sends a message to the given destination. * @brief This operation sends a message to the given destination.
@ -100,7 +104,8 @@ public:
* @param message A pointer to a previously created message, which is sent. * @param message A pointer to a previously created message, which is sent.
* @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. * @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full.
*/ */
virtual ReturnValue_t sendMessage( MessageQueueId_t sendTo, MessageQueueMessage* message, bool ignoreFault = false ) = 0; virtual ReturnValue_t sendMessage( MessageQueueId_t sendTo,
MessageQueueMessage* message, bool ignoreFault = false ) = 0;
/** /**
* @brief The sendToDefaultFrom method sends a queue message to the default destination. * @brief The sendToDefaultFrom method sends a queue message to the default destination.
@ -111,7 +116,8 @@ public:
* @return -@c RETURN_OK on success * @return -@c RETURN_OK on success
* -@c MessageQueueIF::FULL if queue is full * -@c MessageQueueIF::FULL if queue is full
*/ */
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom, bool ignoreFault = false ) = 0; virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message,
MessageQueueId_t sentFrom, bool ignoreFault = false ) = 0;
/** /**
* @brief This operation sends a message to the default destination. * @brief This operation sends a message to the default destination.
* @details As in the sendMessage method, this function uses the sendToDefault call of the * @details As in the sendMessage method, this function uses the sendToDefault call of the

View File

@ -8,6 +8,20 @@ MessageQueueMessage::MessageQueueMessage() :
memset(this->internalBuffer, 0, sizeof(this->internalBuffer)); memset(this->internalBuffer, 0, sizeof(this->internalBuffer));
} }
MessageQueueMessage::MessageQueueMessage(uint8_t* data, size_t size) :
messageSize(this->HEADER_SIZE + size) {
if (size <= this->MAX_DATA_SIZE) {
memcpy(this->getData(), data, size);
this->messageSize = this->HEADER_SIZE + size;
}
else {
sif::warning << "MessageQueueMessage: Passed size larger than maximum"
"allowed size! Setting content to 0" << std::endl;
memset(this->internalBuffer, 0, sizeof(this->internalBuffer));
this->messageSize = this->HEADER_SIZE;
}
}
MessageQueueMessage::~MessageQueueMessage() { MessageQueueMessage::~MessageQueueMessage() {
} }
@ -37,23 +51,13 @@ void MessageQueueMessage::setSender(MessageQueueId_t setId) {
memcpy(this->internalBuffer, &setId, sizeof(MessageQueueId_t)); memcpy(this->internalBuffer, &setId, sizeof(MessageQueueId_t));
} }
MessageQueueMessage::MessageQueueMessage(uint8_t* data, uint32_t size) :
messageSize(this->HEADER_SIZE + size) {
if (size <= this->MAX_DATA_SIZE) {
memcpy(this->getData(), data, size);
} else {
memset(this->internalBuffer, 0, sizeof(this->internalBuffer));
this->messageSize = this->HEADER_SIZE;
}
}
size_t MessageQueueMessage::getMinimumMessageSize() { size_t MessageQueueMessage::getMinimumMessageSize() {
return this->HEADER_SIZE; return this->HEADER_SIZE;
} }
void MessageQueueMessage::print() { void MessageQueueMessage::print() {
sif::debug << "MessageQueueMessage has size: " << this->messageSize << std::hex sif::debug << "MessageQueueMessage has size: " << this->messageSize <<
<< std::endl; std::hex << std::endl;
for (uint8_t count = 0; count < this->messageSize; count++) { for (uint8_t count = 0; count < this->messageSize; count++) {
sif::debug << (uint32_t) this->internalBuffer[count] << ":"; sif::debug << (uint32_t) this->internalBuffer[count] << ":";
} }

View File

@ -5,111 +5,129 @@
#include <stddef.h> #include <stddef.h>
/** /**
* \brief This class is the representation and data organizer for interprocess messages. * @brief This class is the representation and data organizer
* for interprocess messages.
* *
* \details To facilitate and standardize interprocess communication, this class was created * @details
* to handle a lightweight "interprocess message protocol". It adds a header with the * To facilitate and standardize interprocess communication, this class was
* sender's queue id to every sent message and defines the maximum total message size. * created to handle a lightweight "interprocess message protocol".
* Specialized messages, such as device commanding messages, can be created by inheriting *
* from this class and filling the buffer provided by getData with additional content. * It adds a header with the sender's queue id to every sent message and
* If larger amounts of data must be sent between processes, the data shall be stored in * defines the maximum total message size. Specialized messages, such as
* the IPC Store object and only the storage id is passed in a queue message. * device commanding messages, can be created by inheriting from this class
* The class is used both to generate and send messages and to receive messages from * and filling the buffer provided by getData with additional content.
* other tasks. *
* \ingroup message_queue * If larger amounts of data must be sent between processes, the data shall
* be stored in the IPC Store object and only the storage id is passed in a
* queue message.The class is used both to generate and send messages and to
* receive messages from other tasks.
* @ingroup message_queue
*/ */
class MessageQueueMessage { class MessageQueueMessage {
public: public:
/** /**
* \brief This constant defines the maximum size of the data content, excluding the header. * @brief The class is initialized empty with this constructor.
* \details It may be changed if necessary, but in general should be kept as small as possible. * @details The messageSize attribute is set to the header's size and the
* whole content is set to zero.
*/
MessageQueueMessage();
/**
* @brief With this constructor the class is initialized with the given content.
* @details
* If the passed message size fits into the buffer, the passed data is
* copied to the internal buffer and the messageSize information is set.
* Otherwise, messageSize is set to the header's size and the whole
* content is set to zero.
* @param data The data to be put in the message.
* @param size Size of the data to be copied. Must be smaller than
* MAX_MESSAGE_SIZE and larger than MIN_MESSAGE_SIZE.
*/
MessageQueueMessage(uint8_t* data, size_t size);
/**
* @brief The size information of each message is stored in this attribute.
* @details
* It is public to simplify usage and to allow for passing the size
* address as a pointer. Care must be taken when inheriting from this class,
* as every child class is responsible for managing the size information by
* itself. When using the class to receive a message, the size information
* is updated automatically.
*
* Please note that the minimum size is limited by the size of the header
* while the maximum size is limited by the maximum allowed message size.
*/
size_t messageSize;
/**
* @brief This constant defines the maximum size of the data content, excluding the header.
* @details It may be changed if necessary, but in general should be kept as small as possible.
*/ */
static const size_t MAX_DATA_SIZE = 24; static const size_t MAX_DATA_SIZE = 24;
/** /**
* \brief This constants defines the size of the header, which is added to every message. * @brief This constants defines the size of the header, which is added to every message.
*/ */
static const size_t HEADER_SIZE = sizeof(MessageQueueId_t); static const size_t HEADER_SIZE = sizeof(MessageQueueId_t);
/** /**
* \brief This constant defines the maximum total size in bytes of a sent message. * @brief This constant defines the maximum total size in bytes of a sent message.
* \details It is the sum of the maximum data and the header size. Be aware that this constant * @details It is the sum of the maximum data and the header size. Be aware that this constant
* is used to define the buffer sizes for every message queue in the system. So, a change * is used to define the buffer sizes for every message queue in the system. So, a change
* here may have significant impact on the required resources. * here may have significant impact on the required resources.
*/ */
static const size_t MAX_MESSAGE_SIZE = MAX_DATA_SIZE + HEADER_SIZE; static const size_t MAX_MESSAGE_SIZE = MAX_DATA_SIZE + HEADER_SIZE;
/**
* @brief Defines the minimum size of a message where only the
* header is included
*/
static const size_t MIN_MESSAGE_SIZE = HEADER_SIZE;
private: private:
/** /**
* \brief This is the internal buffer that contains the actual message data. * @brief This is the internal buffer that contains the actual message data.
*/ */
uint8_t internalBuffer[MAX_MESSAGE_SIZE]; uint8_t internalBuffer[MAX_MESSAGE_SIZE];
public: public:
/** /**
* \brief The size information of each message is stored in this attribute. * @brief As no memory is allocated in this class, the destructor is empty.
* \details It is public to simplify usage and to allow for passing the variable's address as a
* pointer. Care must be taken when inheriting from this class, as every child class is
* responsible for managing the size information by itself. When using the class to
* receive a message, the size information is updated automatically.
*/
size_t messageSize;
/**
* \brief The class is initialized empty with this constructor.
* \details The messageSize attribute is set to the header's size and the whole content is set to
* zero.
*/
MessageQueueMessage();
/**
* \brief With this constructor the class is initialized with the given content.
* \details If the passed message size fits into the buffer, the passed data is copied to the
* internal buffer and the messageSize information is set. Otherwise, messageSize
* is set to the header's size and the whole content is set to zero.
* \param data The data to be put in the message.
* \param size Size of the data to be copied. Must be smaller than MAX_MESSAGE_SIZE.
*/
MessageQueueMessage(uint8_t* data, uint32_t size);
/**
* \brief As no memory is allocated in this class, the destructor is empty.
*/ */
virtual ~MessageQueueMessage(); virtual ~MessageQueueMessage();
/** /**
* \brief This method is used to get the complete data of the message. * @brief This method is used to get the complete data of the message.
*/ */
const uint8_t* getBuffer() const; const uint8_t* getBuffer() const;
/** /**
* \brief This method is used to get the complete data of the message. * @brief This method is used to get the complete data of the message.
*/ */
uint8_t* getBuffer(); uint8_t* getBuffer();
/** /**
* \brief This method is used to fetch the data content of the message. * @brief This method is used to fetch the data content of the message.
* \details It shall be used by child classes to add data at the right position. * @details It shall be used by child classes to add data at the right position.
*/ */
const uint8_t* getData() const; const uint8_t* getData() const;
/** /**
* \brief This method is used to fetch the data content of the message. * @brief This method is used to fetch the data content of the message.
* \details It shall be used by child classes to add data at the right position. * @details It shall be used by child classes to add data at the right position.
*/ */
uint8_t* getData(); uint8_t* getData();
/** /**
* \brief This method is used to extract the sender's message queue id information from a * @brief This method is used to extract the sender's message queue id information from a
* received message. * received message.
*/ */
MessageQueueId_t getSender() const; MessageQueueId_t getSender() const;
/** /**
* \brief With this method, the whole content and the message size is set to zero. * @brief With this method, the whole content and the message size is set to zero.
*/ */
void clear(); void clear();
/** /**
* \brief This is a debug method that prints the content (till messageSize) to the debug output. * @brief This is a debug method that prints the content (till messageSize) to the debug output.
*/ */
void print(); void print();
/** /**
* \brief This method is used to set the sender's message queue id information prior to * @brief This method is used to set the sender's message queue id information prior to
* sending the message. * sending the message.
* \param setId The message queue id that identifies the sending message queue. * @param setId The message queue id that identifies the sending message queue.
*/ */
void setSender(MessageQueueId_t setId); void setSender(MessageQueueId_t setId);
/** /**
* \brief This helper function is used by the MessageQueue class to check the size of an * @brief This helper function is used by the MessageQueue class to check the size of an
* incoming message. * incoming message.
* \details The method must be overwritten by child classes if size checks shall be more strict. * @details The method must be overwritten by child classes if size checks shall be more strict.
* @return The default implementation returns HEADER_SIZE. * @return The default implementation returns HEADER_SIZE.
*/ */
virtual size_t getMinimumMessageSize(); virtual size_t getMinimumMessageSize();

View File

@ -2,7 +2,7 @@
#define FRAMEWORK_IPC_QUEUEFACTORY_H_ #define FRAMEWORK_IPC_QUEUEFACTORY_H_
#include <framework/ipc/MessageQueueIF.h> #include <framework/ipc/MessageQueueIF.h>
#include <stdint.h> #include <cstdint>
/** /**
* Creates message queues. * Creates message queues.
* This class is a "singleton" interface, i.e. it provides an * This class is a "singleton" interface, i.e. it provides an
@ -18,8 +18,8 @@ public:
*/ */
static QueueFactory* instance(); static QueueFactory* instance();
MessageQueueIF* createMessageQueue(uint32_t message_depth = 3, MessageQueueIF* createMessageQueue(size_t messageDepth = 3,
uint32_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE); size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE);
void deleteMessageQueue(MessageQueueIF* queue); void deleteMessageQueue(MessageQueueIF* queue);
private: private:

View File

@ -2,12 +2,14 @@
#include <framework/serviceinterface/ServiceInterfaceStream.h> #include <framework/serviceinterface/ServiceInterfaceStream.h>
// TODO I guess we should have a way of checking if we are in an ISR and then use the "fromISR" versions of all calls // TODO I guess we should have a way of checking if we are in an ISR and then
// As a first step towards this, introduces system context variable which needs to be switched manually // use the "fromISR" versions of all calls
// As a first step towards this, introduces system context variable which needs
// to be switched manually
// Haven't found function to find system context. // Haven't found function to find system context.
MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) : MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize) :
defaultDestination(0),lastPartner(0), callContext(CallContext::task) { defaultDestination(0),lastPartner(0), callContext(CallContext::task) {
handle = xQueueCreate(message_depth, max_message_size); handle = xQueueCreate(messageDepth, maxMessageSize);
if (handle == NULL) { if (handle == NULL) {
sif::error << "MessageQueue creation failed" << std::endl; sif::error << "MessageQueue creation failed" << std::endl;
} }

View File

@ -1,6 +1,7 @@
#include "PeriodicTask.h"
#include <framework/serviceinterface/ServiceInterfaceStream.h> #include <framework/serviceinterface/ServiceInterfaceStream.h>
#include <framework/tasks/ExecutableObjectIF.h> #include <framework/tasks/ExecutableObjectIF.h>
#include "PeriodicTask.h"
PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod, TaskStackSize setStack, TaskPeriod setPeriod,
@ -31,7 +32,7 @@ void PeriodicTask::taskEntryPoint(void* argument) {
// if it is not set and we get here, the scheduler was started before #startTask() was called and we need to suspend // if it is not set and we get here, the scheduler was started before #startTask() was called and we need to suspend
// if it is set, the scheduler was not running before #startTask() was called and we can continue // if it is set, the scheduler was not running before #startTask() was called and we can continue
if (!originalTask->started) { if (not originalTask->started) {
vTaskSuspend(NULL); vTaskSuspend(NULL);
} }
@ -70,8 +71,19 @@ void PeriodicTask::taskFunctionality() {
it != objectList.end(); ++it) { it != objectList.end(); ++it) {
(*it)->performOperation(); (*it)->performOperation();
} }
//TODO deadline missed check
/* If all operations are finished and the difference of the
* current time minus the last wake time is larger than the
* wait period, a deadline was missed. */
if(xTaskGetTickCount() - xLastWakeTime >= xPeriod) {
sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) <<
" missed deadline!\n" << std::flush;
if(deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
}
vTaskDelayUntil(&xLastWakeTime, xPeriod); vTaskDelayUntil(&xLastWakeTime, xPeriod);
} }
} }

View File

@ -5,8 +5,10 @@
#include <framework/tasks/PeriodicTaskIF.h> #include <framework/tasks/PeriodicTaskIF.h>
#include <framework/tasks/Typedef.h> #include <framework/tasks/Typedef.h>
#include <FreeRTOS.h> extern "C" {
#include "task.h" #include <freertos/FreeRTOS.h>
#include <freertos/task.h>
}
#include <vector> #include <vector>

View File

@ -3,16 +3,18 @@
#include <framework/osal/FreeRTOS/MessageQueue.h> #include <framework/osal/FreeRTOS/MessageQueue.h>
QueueFactory* QueueFactory::factoryInstance = NULL; QueueFactory* QueueFactory::factoryInstance = nullptr;
ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueId_t sentFrom,bool ignoreFault) { MessageQueueMessage* message, MessageQueueId_t sentFrom,
return MessageQueue::sendMessageFromMessageQueue(sendTo,message,sentFrom,ignoreFault); bool ignoreFault) {
return MessageQueue::sendMessageFromMessageQueue(sendTo,message,
sentFrom,ignoreFault);
} }
QueueFactory* QueueFactory::instance() { QueueFactory* QueueFactory::instance() {
if (factoryInstance == NULL) { if (factoryInstance == nullptr) {
factoryInstance = new QueueFactory; factoryInstance = new QueueFactory;
} }
return factoryInstance; return factoryInstance;
@ -24,9 +26,9 @@ QueueFactory::QueueFactory() {
QueueFactory::~QueueFactory() { QueueFactory::~QueueFactory() {
} }
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t message_depth, MessageQueueIF* QueueFactory::createMessageQueue(size_t messageDepth,
uint32_t max_message_size) { size_t maxMessageSize) {
return new MessageQueue(message_depth, max_message_size); return new MessageQueue(messageDepth, maxMessageSize);
} }
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) {

View File

@ -7,15 +7,15 @@
#include <framework/osal/linux/MessageQueue.h> #include <framework/osal/linux/MessageQueue.h>
MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) : MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize) :
id(0), lastPartner(0), defaultDestination(NO_QUEUE) { id(0), lastPartner(0), defaultDestination(NO_QUEUE) {
//debug << "MessageQueue::MessageQueue: Creating a queue" << std::endl; //debug << "MessageQueue::MessageQueue: Creating a queue" << std::endl;
mq_attr attributes; mq_attr attributes;
this->id = 0; this->id = 0;
//Set attributes //Set attributes
attributes.mq_curmsgs = 0; attributes.mq_curmsgs = 0;
attributes.mq_maxmsg = message_depth; attributes.mq_maxmsg = messageDepth;
attributes.mq_msgsize = max_message_size; attributes.mq_msgsize = maxMessageSize;
attributes.mq_flags = 0; //Flags are ignored on Linux during mq_open attributes.mq_flags = 0; //Flags are ignored on Linux during mq_open
//Set the name of the queue //Set the name of the queue
sprintf(name, "/Q%u\n", queueCounter++); sprintf(name, "/Q%u\n", queueCounter++);
@ -265,7 +265,11 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
<< strerror(errno) << " in mq_send" << std::endl; << strerror(errno) << " in mq_send" << std::endl;
/*NO BREAK*/ /*NO BREAK*/
case EMSGSIZE: case EMSGSIZE:
//The msg_len is greater than the msgsize associated with the specified queue. // The msg_len is greater than the msgsize associated with
//the specified queue.
sif::error << "MessageQueue::sendMessage: Size error [" <<
strerror(errno) << "] in mq_send" << std::endl;
/*NO BREAK*/
default: default:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }

View File

@ -5,20 +5,23 @@
#include <framework/ipc/MessageQueueIF.h> #include <framework/ipc/MessageQueueIF.h>
#include <framework/ipc/MessageQueueMessage.h> #include <framework/ipc/MessageQueueMessage.h>
/** /**
* @brief This class manages sending and receiving of message queue messages. * @brief This class manages sending and receiving of message queue messages.
* *
* @details Message queues are used to pass asynchronous messages between processes. * @details
* They work like post boxes, where all incoming messages are stored in FIFO * Message queues are used to pass asynchronous messages between processes.
* order. This class creates a new receiving queue and provides methods to fetch * They work like post boxes, where all incoming messages are stored in FIFO
* received messages. Being a child of MessageQueueSender, this class also provides * order. This class creates a new receiving queue and provides methods to fetch
* methods to send a message to a user-defined or a default destination. In addition * received messages. Being a child of MessageQueueSender, this class also
* it also provides a reply method to answer to the queue it received its last message * provides methods to send a message to a user-defined or a default destination.
* from. * In addition it also provides a reply method to answer to the queue it
* The MessageQueue should be used as "post box" for a single owning object. So all * received its last message from.
* message queue communication is "n-to-one". *
* For creating the queue, as well as sending and receiving messages, the class makes * The MessageQueue should be used as "post box" for a single owning object.
* use of the operating system calls provided. * So all message queue communication is "n-to-one".
* \ingroup message_queue *
* The creation of message queues, as well as sending and receiving messages,
* makes use of the operating system calls provided.
* @ingroup message_queue
*/ */
class MessageQueue : public MessageQueueIF { class MessageQueue : public MessageQueueIF {
friend class MessageQueueSenderIF; friend class MessageQueueSenderIF;
@ -35,7 +38,8 @@ public:
* @param max_message_size With this parameter, the maximum message size can be adjusted. * @param max_message_size With this parameter, the maximum message size can be adjusted.
* This should be left default. * This should be left default.
*/ */
MessageQueue( size_t message_depth = 3, size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE ); MessageQueue(size_t messageDepth = 3,
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE );
/** /**
* @brief The destructor deletes the formerly created message queue. * @brief The destructor deletes the formerly created message queue.
* @details This is accomplished by using the delete call provided by the operating system. * @details This is accomplished by using the delete call provided by the operating system.

View File

@ -3,9 +3,10 @@
#include <errno.h> #include <errno.h>
#include <framework/osal/linux/PeriodicPosixTask.h> #include <framework/osal/linux/PeriodicPosixTask.h>
PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, uint32_t period_, void(deadlineMissedFunc_)()):PosixThread(name_,priority_,stackSize_),objectList(),started(false),periodMs(period_),deadlineMissedFunc( PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_,
deadlineMissedFunc_) { size_t stackSize_, uint32_t period_, void(deadlineMissedFunc_)()):
PosixThread(name_,priority_,stackSize_),objectList(),started(false),
periodMs(period_),deadlineMissedFunc(deadlineMissedFunc_) {
} }
PeriodicPosixTask::~PeriodicPosixTask() { PeriodicPosixTask::~PeriodicPosixTask() {

View File

@ -5,16 +5,18 @@
#include <framework/serviceinterface/ServiceInterfaceStream.h> #include <framework/serviceinterface/ServiceInterfaceStream.h>
#include <cstring> #include <cstring>
QueueFactory* QueueFactory::factoryInstance = NULL; QueueFactory* QueueFactory::factoryInstance = nullptr;
ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueId_t sentFrom,bool ignoreFault) { MessageQueueMessage* message, MessageQueueId_t sentFrom,
return MessageQueue::sendMessageFromMessageQueue(sendTo,message,sentFrom,ignoreFault); bool ignoreFault) {
return MessageQueue::sendMessageFromMessageQueue(sendTo,message,
sentFrom,ignoreFault);
} }
QueueFactory* QueueFactory::instance() { QueueFactory* QueueFactory::instance() {
if (factoryInstance == NULL) { if (factoryInstance == nullptr) {
factoryInstance = new QueueFactory; factoryInstance = new QueueFactory;
} }
return factoryInstance; return factoryInstance;
@ -26,9 +28,9 @@ QueueFactory::QueueFactory() {
QueueFactory::~QueueFactory() { QueueFactory::~QueueFactory() {
} }
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t message_depth, MessageQueueIF* QueueFactory::createMessageQueue(size_t messageDepth,
uint32_t max_message_size) { size_t maxMessageSize) {
return new MessageQueue(message_depth, max_message_size); return new MessageQueue(messageDepth, maxMessageSize);
} }
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) {