diff --git a/devicehandlers/ChildHandlerBase.cpp b/devicehandlers/ChildHandlerBase.cpp index 50a5c07e..7144db8f 100644 --- a/devicehandlers/ChildHandlerBase.cpp +++ b/devicehandlers/ChildHandlerBase.cpp @@ -2,15 +2,16 @@ #include #include -ChildHandlerBase::ChildHandlerBase(uint32_t ioBoardAddress, - object_id_t setObjectId, object_id_t deviceCommunication, - uint32_t maxDeviceReplyLen, uint8_t setDeviceSwitch, - uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId, - uint32_t parent, FailureIsolationBase* customFdir, uint32_t cmdQueueSize) : - DeviceHandlerBase(ioBoardAddress, setObjectId, maxDeviceReplyLen, - setDeviceSwitch, deviceCommunication, thermalStatePoolId, - thermalRequestPoolId, (customFdir == NULL? &childHandlerFdir : customFdir), cmdQueueSize), parentId( - parent), childHandlerFdir(setObjectId) { +ChildHandlerBase::ChildHandlerBase(object_id_t setObjectId, + object_id_t deviceCommunication, CookieIF * comCookie, + uint8_t setDeviceSwitch, uint32_t thermalStatePoolId, + uint32_t thermalRequestPoolId, uint32_t parent, + FailureIsolationBase* customFdir, size_t cmdQueueSize) : + DeviceHandlerBase(setObjectId, deviceCommunication, comCookie, + setDeviceSwitch, thermalStatePoolId,thermalRequestPoolId, + (customFdir == nullptr? &childHandlerFdir : customFdir), + cmdQueueSize), + parentId(parent), childHandlerFdir(setObjectId) { } ChildHandlerBase::~ChildHandlerBase() { diff --git a/devicehandlers/ChildHandlerBase.h b/devicehandlers/ChildHandlerBase.h index 3879f66f..59cf26b1 100644 --- a/devicehandlers/ChildHandlerBase.h +++ b/devicehandlers/ChildHandlerBase.h @@ -6,12 +6,12 @@ class ChildHandlerBase: public DeviceHandlerBase { public: - ChildHandlerBase(uint32_t ioBoardAddress, object_id_t setObjectId, - object_id_t deviceCommunication, uint32_t maxDeviceReplyLen, + ChildHandlerBase(object_id_t setObjectId, + object_id_t deviceCommunication, CookieIF * comCookie, uint8_t setDeviceSwitch, uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId, uint32_t parent, - FailureIsolationBase* customFdir = NULL, - uint32_t cmdQueueSize = 20); + FailureIsolationBase* customFdir = nullptr, + size_t cmdQueueSize = 20); virtual ~ChildHandlerBase(); virtual ReturnValue_t initialize(); diff --git a/devicehandlers/Cookie.h b/devicehandlers/Cookie.h deleted file mode 100644 index 495c8c40..00000000 --- a/devicehandlers/Cookie.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef COOKIE_H_ -#define COOKIE_H_ - -class Cookie{ -public: - virtual ~Cookie(){} -}; - - -#endif /* COOKIE_H_ */ diff --git a/devicehandlers/CookieIF.h b/devicehandlers/CookieIF.h new file mode 100644 index 00000000..496cf0d2 --- /dev/null +++ b/devicehandlers/CookieIF.h @@ -0,0 +1,34 @@ +#ifndef COOKIE_H_ +#define COOKIE_H_ +#include + +/** + * @brief Physical address type + */ +typedef std::uint32_t address_t; + +/** + * @brief This datatype is used to identify different connection over a + * single interface (like RMAP or I2C) + * @details + * To use this class, implement a communication specific child cookie which + * inherits Cookie. Cookie instances are created in config/Factory.cpp by + * calling @code{.cpp} CookieIF* childCookie = new ChildCookie(...) + * @endcode . + * + * [not implemented yet] + * This cookie is then passed to the child device handlers, which stores the + * pointer and passes it to the communication interface functions. + * + * The cookie can be used to store all kinds of information + * about the communication, like slave addresses, communication status, + * communication parameters etc. + * + * @ingroup comm + */ +class CookieIF { +public: + virtual ~CookieIF() {}; +}; + +#endif /* COOKIE_H_ */ diff --git a/devicehandlers/DeviceCommunicationIF.h b/devicehandlers/DeviceCommunicationIF.h index e0aca573..9ca31a9b 100644 --- a/devicehandlers/DeviceCommunicationIF.h +++ b/devicehandlers/DeviceCommunicationIF.h @@ -1,63 +1,131 @@ #ifndef DEVICECOMMUNICATIONIF_H_ #define DEVICECOMMUNICATIONIF_H_ -#include +#include #include +#include +/** + * @defgroup interfaces Interfaces + * @brief Interfaces for flight software objects + */ +/** + * @defgroup comm Communication + * @brief Communication software components. + */ + +/** + * @brief This is an interface to decouple device communication from + * the device handler to allow reuse of these components. + * @details + * Documentation: Dissertation Baetz p.138. + * It works with the assumption that received data + * is polled by a component. There are four generic steps of device communication: + * + * 1. Send data to a device + * 2. Get acknowledgement for sending + * 3. Request reading data from a device + * 4. Read received data + * + * To identify different connection over a single interface can return + * so-called cookies to components. + * The CommunicationMessage message type can be used to extend the + * functionality of the ComIF if a separate polling task is required. + * @ingroup interfaces + * @ingroup comm + */ class DeviceCommunicationIF: public HasReturnvaluesIF { public: static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_COMMUNICATION_IF; - static const ReturnValue_t INVALID_COOKIE_TYPE = MAKE_RETURN_CODE(0x01); - static const ReturnValue_t NOT_ACTIVE = MAKE_RETURN_CODE(0x02); - static const ReturnValue_t INVALID_ADDRESS = MAKE_RETURN_CODE(0x03); - static const ReturnValue_t TOO_MUCH_DATA = MAKE_RETURN_CODE(0x04); - static const ReturnValue_t NULLPOINTER = MAKE_RETURN_CODE(0x05); - static const ReturnValue_t PROTOCOL_ERROR = MAKE_RETURN_CODE(0x06); - static const ReturnValue_t CANT_CHANGE_REPLY_LEN = MAKE_RETURN_CODE(0x07); + //! Standard Error Codes + //! General protocol error. Define more concrete errors in child handler + static const ReturnValue_t PROTOCOL_ERROR = MAKE_RETURN_CODE(0x01); + //! If cookie is a null pointer + static const ReturnValue_t NULLPOINTER = MAKE_RETURN_CODE(0x02); + static const ReturnValue_t INVALID_COOKIE_TYPE = MAKE_RETURN_CODE(0x03); + // is this needed if there is no open/close call? + static const ReturnValue_t NOT_ACTIVE = MAKE_RETURN_CODE(0x05); + static const ReturnValue_t INVALID_ADDRESS = MAKE_RETURN_CODE(0x06); + static const ReturnValue_t TOO_MUCH_DATA = MAKE_RETURN_CODE(0x07); + static const ReturnValue_t CANT_CHANGE_REPLY_LEN = MAKE_RETURN_CODE(0x08); - virtual ~DeviceCommunicationIF() { + //! Can be used in readReceivedMessage() if no reply was received. + static const ReturnValue_t NO_REPLY_RECEIVED = MAKE_RETURN_CODE(0xA1); - } + virtual ~DeviceCommunicationIF() {} - virtual ReturnValue_t open(Cookie **cookie, uint32_t address, - uint32_t maxReplyLen) = 0; /** - * Use an existing cookie to open a connection to a new DeviceCommunication. - * The previous connection must not be closed. - * If the returnvalue is not RETURN_OK, the cookie is unchanged and - * can be used with the previous connection. + * @brief Device specific initialization, using the cookie. + * @details + * The cookie is already prepared in the factory. If the communication + * interface needs to be set up in some way and requires cookie information, + * this can be performed in this function, which is called on device handler + * initialization. + * @param cookie + * @return + * - @c RETURN_OK if initialization was successfull + * - Everything else triggers failure event with returnvalue as parameter 1 + */ + virtual ReturnValue_t initializeInterface(CookieIF * cookie) = 0; + + /** + * Called by DHB in the SEND_WRITE doSendWrite(). + * This function is used to send data to the physical device + * by implementing and calling related drivers or wrapper functions. + * @param cookie + * @param data + * @param len + * @return + * - @c RETURN_OK for successfull send + * - Everything else triggers failure event with returnvalue as parameter 1 + */ + virtual ReturnValue_t sendMessage(CookieIF *cookie, const uint8_t * sendData, + size_t sendLen) = 0; + + /** + * Called by DHB in the GET_WRITE doGetWrite(). + * Get send confirmation that the data in sendMessage() was sent successfully. + * @param cookie + * @return - @c RETURN_OK if data was sent successfull + * - Everything else triggers falure event with + * returnvalue as parameter 1 + */ + virtual ReturnValue_t getSendSuccess(CookieIF *cookie) = 0; + + /** + * Called by DHB in the SEND_WRITE doSendRead(). + * It is assumed that it is always possible to request a reply + * from a device. If a requestLen of 0 is supplied, no reply was enabled + * and communication specific action should be taken (e.g. read nothing + * or read everything). * * @param cookie - * @param address - * @param maxReplyLen - * @return + * @param requestLen Size of data to read + * @return - @c RETURN_OK to confirm the request for data has been sent. + * - Everything else triggers failure event with + * returnvalue as parameter 1 */ - virtual ReturnValue_t reOpen(Cookie *cookie, uint32_t address, - uint32_t maxReplyLen) = 0; - - virtual void close(Cookie *cookie) = 0; - - //SHOULDDO can data be const? - virtual ReturnValue_t sendMessage(Cookie *cookie, uint8_t *data, - uint32_t len) = 0; - - virtual ReturnValue_t getSendSuccess(Cookie *cookie) = 0; - - virtual ReturnValue_t requestReceiveMessage(Cookie *cookie) = 0; - - virtual ReturnValue_t readReceivedMessage(Cookie *cookie, uint8_t **buffer, - uint32_t *size) = 0; - - virtual ReturnValue_t setAddress(Cookie *cookie, uint32_t address) = 0; - - virtual uint32_t getAddress(Cookie *cookie) = 0; - - virtual ReturnValue_t setParameter(Cookie *cookie, uint32_t parameter) = 0; - - virtual uint32_t getParameter(Cookie *cookie) = 0; + virtual ReturnValue_t requestReceiveMessage(CookieIF *cookie, + size_t requestLen) = 0; + /** + * Called by DHB in the GET_WRITE doGetRead(). + * This function is used to receive data from the physical device + * by implementing and calling related drivers or wrapper functions. + * @param cookie + * @param buffer [out] Set reply here (by using *buffer = ...) + * @param size [out] size pointer to set (by using *size = ...). + * Set to 0 if no reply was received + * @return - @c RETURN_OK for successfull receive + * - @c NO_REPLY_RECEIVED if not reply was received. Setting size to + * 0 has the same effect + * - Everything else triggers failure event with + * returnvalue as parameter 1 + */ + virtual ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer, + size_t *size) = 0; }; #endif /* DEVICECOMMUNICATIONIF_H_ */ diff --git a/devicehandlers/DeviceHandlerBase.cpp b/devicehandlers/DeviceHandlerBase.cpp index 90875838..fe6152cf 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/devicehandlers/DeviceHandlerBase.cpp @@ -1,52 +1,60 @@ -#include -#include -#include -#include #include -#include -#include #include #include -#include #include +#include + +#include +#include +#include +#include +#include #include #include +#include + object_id_t DeviceHandlerBase::powerSwitcherId = 0; object_id_t DeviceHandlerBase::rawDataReceiverId = 0; object_id_t DeviceHandlerBase::defaultFDIRParentId = 0; -DeviceHandlerBase::DeviceHandlerBase(uint32_t ioBoardAddress, - object_id_t setObjectId, uint32_t maxDeviceReplyLen, - uint8_t setDeviceSwitch, object_id_t deviceCommunication, - uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId, - FailureIsolationBase* fdirInstance, uint32_t cmdQueueSize) : - SystemObject(setObjectId), rawPacket(0), rawPacketLen(0), mode( - MODE_OFF), submode(SUBMODE_NONE), pstStep(0), maxDeviceReplyLen( - maxDeviceReplyLen), wiretappingMode(OFF), defaultRawReceiver(0), storedRawData( - StorageManagerIF::INVALID_ADDRESS), requestedRawTraffic(0), powerSwitcher( - NULL), IPCStore(NULL), deviceCommunicationId(deviceCommunication), communicationInterface( - NULL), cookie( - NULL), commandQueue(NULL), deviceThermalStatePoolId(thermalStatePoolId), deviceThermalRequestPoolId( - thermalRequestPoolId), healthHelper(this, setObjectId), modeHelper( - this), parameterHelper(this), childTransitionFailure(RETURN_OK), ignoreMissedRepliesCount( - 0), fdirInstance(fdirInstance), hkSwitcher(this), defaultFDIRUsed( - fdirInstance == NULL), switchOffWasReported(false),executingTask(NULL), actionHelper(this, NULL), cookieInfo(), ioBoardAddress( - ioBoardAddress), timeoutStart(0), childTransitionDelay(5000), transitionSourceMode( - _MODE_POWER_DOWN), transitionSourceSubMode(SUBMODE_NONE), deviceSwitch( - setDeviceSwitch) { +DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, + object_id_t deviceCommunication, CookieIF * comCookie, + uint8_t setDeviceSwitch, uint32_t thermalStatePoolId, + uint32_t thermalRequestPoolId, FailureIsolationBase* fdirInstance, + size_t cmdQueueSize) : + SystemObject(setObjectId), mode(MODE_OFF), submode(SUBMODE_NONE), + wiretappingMode(OFF), storedRawData(StorageManagerIF::INVALID_ADDRESS), + deviceCommunicationId(deviceCommunication), comCookie(comCookie), + deviceThermalStatePoolId(thermalStatePoolId), + deviceThermalRequestPoolId(thermalRequestPoolId), + healthHelper(this,setObjectId), modeHelper(this), parameterHelper(this), + childTransitionFailure(RETURN_OK), fdirInstance(fdirInstance), + hkSwitcher(this), defaultFDIRUsed(fdirInstance == nullptr), + switchOffWasReported(false), actionHelper(this, nullptr), + childTransitionDelay(5000), + transitionSourceMode(_MODE_POWER_DOWN), transitionSourceSubMode( + SUBMODE_NONE), deviceSwitch(setDeviceSwitch) { commandQueue = QueueFactory::instance()->createMessageQueue(cmdQueueSize, CommandMessage::MAX_MESSAGE_SIZE); - cookieInfo.state = COOKIE_UNUSED; insertInCommandMap(RAW_COMMAND_ID); - if (this->fdirInstance == NULL) { + cookieInfo.state = COOKIE_UNUSED; + cookieInfo.pendingCommand = deviceCommandMap.end(); + if (comCookie == nullptr) { + sif::error << "DeviceHandlerBase: ObjectID 0x" << std::hex << + std::setw(8) << std::setfill('0') << this->getObjectId() << + std::dec << ": Do not pass nullptr as a cookie, consider " + << std::setfill(' ') << "passing a dummy cookie instead!" << + std::endl; + } + if (this->fdirInstance == nullptr) { this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, defaultFDIRParentId); } } DeviceHandlerBase::~DeviceHandlerBase() { - communicationInterface->close(cookie); + delete comCookie; if (defaultFDIRUsed) { delete fdirInstance; } @@ -56,7 +64,7 @@ DeviceHandlerBase::~DeviceHandlerBase() { ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) { this->pstStep = counter; - if (counter == 0) { + if (getComAction() == SEND_WRITE) { cookieInfo.state = COOKIE_UNUSED; readCommandQueue(); doStateMachine(); @@ -64,11 +72,12 @@ ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) { decrementDeviceReplyMap(); fdirInstance->checkForFailures(); hkSwitcher.performOperation(); + performOperationHook(); } if (mode == MODE_OFF) { return RETURN_OK; } - switch (getRmapAction()) { + switch (getComAction()) { case SEND_WRITE: if ((cookieInfo.state == COOKIE_UNUSED)) { buildInternalCommand(); @@ -91,13 +100,91 @@ ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) { return RETURN_OK; } +ReturnValue_t DeviceHandlerBase::initialize() { + ReturnValue_t result = SystemObject::initialize(); + if (result != RETURN_OK) { + return result; + } + + communicationInterface = objectManager->get( + deviceCommunicationId); + if (communicationInterface == NULL) { + return RETURN_FAILED; + } + + result = communicationInterface->initializeInterface(comCookie); + if (result != RETURN_OK) { + return result; + } + + IPCStore = objectManager->get(objects::IPC_STORE); + if (IPCStore == NULL) { + return RETURN_FAILED; + } + + AcceptsDeviceResponsesIF *rawReceiver = objectManager->get< + AcceptsDeviceResponsesIF>(rawDataReceiverId); + + if (rawReceiver == NULL) { + return RETURN_FAILED; + } + + defaultRawReceiver = rawReceiver->getDeviceQueue(); + + powerSwitcher = objectManager->get(powerSwitcherId); + if (powerSwitcher == NULL) { + return RETURN_FAILED; + } + + result = healthHelper.initialize(); + if (result != RETURN_OK) { + return result; + } + + result = modeHelper.initialize(); + if (result != RETURN_OK) { + return result; + } + result = actionHelper.initialize(commandQueue); + if (result != RETURN_OK) { + return result; + } + result = fdirInstance->initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + result = parameterHelper.initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + result = hkSwitcher.initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + fillCommandAndReplyMap(); + + //Set temperature target state to NON_OP. + DataSet mySet; + PoolVariable thermalRequest(deviceThermalRequestPoolId, &mySet, + PoolVariableIF::VAR_WRITE); + mySet.read(); + thermalRequest = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; + mySet.commit(PoolVariableIF::VALID); + + return RETURN_OK; + +} + void DeviceHandlerBase::decrementDeviceReplyMap() { for (std::map::iterator iter = deviceReplyMap.begin(); iter != deviceReplyMap.end(); iter++) { if (iter->second.delayCycles != 0) { iter->second.delayCycles--; if (iter->second.delayCycles == 0) { - if (iter->second.periodic != 0) { + if (iter->second.periodic) { iter->second.delayCycles = iter->second.maxDelayCycles; } replyToReply(iter, TIMEOUT); @@ -256,55 +343,49 @@ ReturnValue_t DeviceHandlerBase::isModeCombinationValid(Mode_t mode, } } -ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap( - DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, - uint8_t periodic, bool hasDifferentReplyId, DeviceCommandId_t replyId) { -//No need to check, as we may try to insert multiple times. +ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap(DeviceCommandId_t deviceCommand, + uint16_t maxDelayCycles, size_t replyLen, bool periodic, + bool hasDifferentReplyId, DeviceCommandId_t replyId) { + //No need to check, as we may try to insert multiple times. insertInCommandMap(deviceCommand); if (hasDifferentReplyId) { - return insertInReplyMap(replyId, maxDelayCycles, periodic); + return insertInReplyMap(replyId, maxDelayCycles, replyLen, periodic); } else { - return insertInReplyMap(deviceCommand, maxDelayCycles, periodic); + return insertInReplyMap(deviceCommand, maxDelayCycles, replyLen, periodic); } } ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId, - uint16_t maxDelayCycles, uint8_t periodic) { + uint16_t maxDelayCycles, size_t replyLen, bool periodic) { DeviceReplyInfo info; info.maxDelayCycles = maxDelayCycles; info.periodic = periodic; info.delayCycles = 0; + info.replyLen = replyLen; info.command = deviceCommandMap.end(); - std::pair::iterator, bool> returnValue; - returnValue = deviceReplyMap.insert( - std::pair(replyId, info)); - if (returnValue.second) { + auto resultPair = deviceReplyMap.emplace(replyId, info); + if (resultPair.second) { return RETURN_OK; } else { return RETURN_FAILED; } } -ReturnValue_t DeviceHandlerBase::insertInCommandMap( - DeviceCommandId_t deviceCommand) { +ReturnValue_t DeviceHandlerBase::insertInCommandMap(DeviceCommandId_t deviceCommand) { DeviceCommandInfo info; info.expectedReplies = 0; info.isExecuting = false; info.sendReplyTo = NO_COMMANDER; - std::pair::iterator, bool> returnValue; - returnValue = deviceCommandMap.insert( - std::pair(deviceCommand, - info)); - if (returnValue.second) { + auto resultPair = deviceCommandMap.emplace(deviceCommand, info); + if (resultPair.second) { return RETURN_OK; } else { return RETURN_FAILED; } } -ReturnValue_t DeviceHandlerBase::updateReplyMapEntry( - DeviceCommandId_t deviceReply, uint16_t delayCycles, - uint16_t maxDelayCycles, uint8_t periodic) { +ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceReply, + uint16_t delayCycles, uint16_t maxDelayCycles, bool periodic) { std::map::iterator iter = deviceReplyMap.find(deviceReply); if (iter == deviceReplyMap.end()) { @@ -429,7 +510,7 @@ void DeviceHandlerBase::replyToReply(DeviceReplyMap::iterator iter, void DeviceHandlerBase::doSendWrite() { if (cookieInfo.state == COOKIE_WRITE_READY) { - ReturnValue_t result = communicationInterface->sendMessage(cookie, + ReturnValue_t result = communicationInterface->sendMessage(comCookie, rawPacket, rawPacketLen); if (result == RETURN_OK) { @@ -450,12 +531,14 @@ void DeviceHandlerBase::doGetWrite() { return; } cookieInfo.state = COOKIE_UNUSED; - ReturnValue_t result = communicationInterface->getSendSuccess(cookie); + ReturnValue_t result = communicationInterface->getSendSuccess(comCookie); if (result == RETURN_OK) { if (wiretappingMode == RAW) { replyRawData(rawPacket, rawPacketLen, requestedRawTraffic, true); } - //We need to distinguish here, because a raw command never expects a reply. (Could be done in eRIRM, but then child implementations need to be careful. + + //We need to distinguish here, because a raw command never expects a reply. + //(Could be done in eRIRM, but then child implementations need to be careful. result = enableReplyInReplyMap(cookieInfo.pendingCommand); } else { //always generate a failure event, so that FDIR knows what's up @@ -471,7 +554,17 @@ void DeviceHandlerBase::doGetWrite() { void DeviceHandlerBase::doSendRead() { ReturnValue_t result; - result = communicationInterface->requestReceiveMessage(cookie); + size_t requestLen = 0; + if(cookieInfo.pendingCommand != deviceCommandMap.end()) { + DeviceReplyIter iter = deviceReplyMap.find( + cookieInfo.pendingCommand->first); + if(iter != deviceReplyMap.end()) { + requestLen = iter->second.replyLen; + } + } + + result = communicationInterface->requestReceiveMessage(comCookie, requestLen); + if (result == RETURN_OK) { cookieInfo.state = COOKIE_READ_SENT; } else { @@ -485,10 +578,10 @@ void DeviceHandlerBase::doSendRead() { } void DeviceHandlerBase::doGetRead() { - uint32_t receivedDataLen; + size_t receivedDataLen; uint8_t *receivedData; DeviceCommandId_t foundId = 0xFFFFFFFF; - uint32_t foundLen = 0; + size_t foundLen = 0; ReturnValue_t result; if (cookieInfo.state != COOKIE_READ_SENT) { @@ -498,8 +591,8 @@ void DeviceHandlerBase::doGetRead() { cookieInfo.state = COOKIE_UNUSED; - result = communicationInterface->readReceivedMessage(cookie, &receivedData, - &receivedDataLen); + result = communicationInterface->readReceivedMessage(comCookie, + &receivedData, &receivedDataLen); if (result != RETURN_OK) { triggerEvent(DEVICE_REQUESTING_REPLY_FAILED, result); @@ -508,7 +601,7 @@ void DeviceHandlerBase::doGetRead() { return; } - if (receivedDataLen == 0) + if (receivedDataLen == 0 or result == DeviceCommunicationIF::NO_REPLY_RECEIVED) return; if (wiretappingMode == RAW) { @@ -539,6 +632,8 @@ void DeviceHandlerBase::doGetRead() { break; case IGNORE_REPLY_DATA: break; + case IGNORE_FULL_PACKET: + return; default: //We need to wait for timeout.. don't know what command failed and who sent it. replyRawReplyIfnotWiretapped(receivedData, foundLen); @@ -560,8 +655,8 @@ ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress, uint8_t * *data, uint32_t * len) { size_t lenTmp; - if (IPCStore == NULL) { - *data = NULL; + if (IPCStore == nullptr) { + *data = nullptr; *len = 0; return RETURN_FAILED; } @@ -572,90 +667,10 @@ ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress, } else { triggerEvent(StorageManagerIF::GET_DATA_FAILED, result, storageAddress.raw); - *data = NULL; + *data = nullptr; *len = 0; return result; } - -} - -ReturnValue_t DeviceHandlerBase::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != RETURN_OK) { - return result; - } - - communicationInterface = objectManager->get( - deviceCommunicationId); - if (communicationInterface == NULL) { - return RETURN_FAILED; - } - - result = communicationInterface->open(&cookie, ioBoardAddress, - maxDeviceReplyLen); - if (result != RETURN_OK) { - return result; - } - - IPCStore = objectManager->get(objects::IPC_STORE); - if (IPCStore == NULL) { - return RETURN_FAILED; - } - - AcceptsDeviceResponsesIF *rawReceiver = objectManager->get< - AcceptsDeviceResponsesIF>(rawDataReceiverId); - - if (rawReceiver == NULL) { - return RETURN_FAILED; - } - - defaultRawReceiver = rawReceiver->getDeviceQueue(); - - powerSwitcher = objectManager->get(powerSwitcherId); - if (powerSwitcher == NULL) { - return RETURN_FAILED; - } - - result = healthHelper.initialize(); - if (result != RETURN_OK) { - return result; - } - - result = modeHelper.initialize(); - if (result != RETURN_OK) { - return result; - } - result = actionHelper.initialize(commandQueue); - if (result != RETURN_OK) { - return result; - } - result = fdirInstance->initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - result = parameterHelper.initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - result = hkSwitcher.initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - fillCommandAndReplyMap(); - - //Set temperature target state to NON_OP. - DataSet mySet; - PoolVariable thermalRequest(deviceThermalRequestPoolId, &mySet, - PoolVariableIF::VAR_WRITE); - mySet.read(); - thermalRequest = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; - mySet.commit(PoolVariableIF::VALID); - - return RETURN_OK; - } void DeviceHandlerBase::replyRawData(const uint8_t *data, size_t len, @@ -687,8 +702,7 @@ void DeviceHandlerBase::replyRawData(const uint8_t *data, size_t len, } //Default child implementations - -DeviceHandlerBase::RmapAction_t DeviceHandlerBase::getRmapAction() { +DeviceHandlerIF::CommunicationAction_t DeviceHandlerBase::getComAction() { switch (pstStep) { case 0: return SEND_WRITE; @@ -727,7 +741,7 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, if (info->delayCycles != 0) { - if (info->periodic != 0) { + if (info->periodic) { info->delayCycles = info->maxDelayCycles; } else { info->delayCycles = 0; @@ -748,20 +762,20 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, } } -ReturnValue_t DeviceHandlerBase::switchCookieChannel(object_id_t newChannelId) { - DeviceCommunicationIF *newCommunication = objectManager->get< - DeviceCommunicationIF>(newChannelId); - - if (newCommunication != NULL) { - ReturnValue_t result = newCommunication->reOpen(cookie, ioBoardAddress, - maxDeviceReplyLen); - if (result != RETURN_OK) { - return result; - } - return RETURN_OK; - } - return RETURN_FAILED; -} +//ReturnValue_t DeviceHandlerBase::switchCookieChannel(object_id_t newChannelId) { +// DeviceCommunicationIF *newCommunication = objectManager->get< +// DeviceCommunicationIF>(newChannelId); +// +// if (newCommunication != NULL) { +// ReturnValue_t result = newCommunication->reOpen(cookie, ioBoardAddress, +// maxDeviceReplyLen); +// if (result != RETURN_OK) { +// return result; +// } +// return RETURN_OK; +// } +// return RETURN_FAILED; +//} void DeviceHandlerBase::buildRawDeviceCommand(CommandMessage* commandMessage) { storedRawData = DeviceHandlerMessage::getStoreAddress(commandMessage); @@ -1022,7 +1036,6 @@ void DeviceHandlerBase::replyRawReplyIfnotWiretapped(const uint8_t* data, ReturnValue_t DeviceHandlerBase::handleDeviceHandlerMessage( CommandMessage * message) { - ReturnValue_t result; switch (message->getCommand()) { case DeviceHandlerMessage::CMD_WIRETAPPING: switch (DeviceHandlerMessage::getWiretappingMode(message)) { @@ -1044,19 +1057,19 @@ ReturnValue_t DeviceHandlerBase::handleDeviceHandlerMessage( } replyReturnvalueToCommand(RETURN_OK); return RETURN_OK; - case DeviceHandlerMessage::CMD_SWITCH_IOBOARD: - if (mode != MODE_OFF) { - replyReturnvalueToCommand(WRONG_MODE_FOR_COMMAND); - } else { - result = switchCookieChannel( - DeviceHandlerMessage::getIoBoardObjectId(message)); - if (result == RETURN_OK) { - replyReturnvalueToCommand(RETURN_OK); - } else { - replyReturnvalueToCommand(CANT_SWITCH_IOBOARD); - } - } - return RETURN_OK; +// case DeviceHandlerMessage::CMD_SWITCH_IOBOARD: +// if (mode != MODE_OFF) { +// replyReturnvalueToCommand(WRONG_MODE_FOR_COMMAND); +// } else { +// result = switchCookieChannel( +// DeviceHandlerMessage::getIoBoardObjectId(message)); +// if (result == RETURN_OK) { +// replyReturnvalueToCommand(RETURN_OK); +// } else { +// replyReturnvalueToCommand(CANT_SWITCH_IO_ADDRESS); +// } +// } +// return RETURN_OK; case DeviceHandlerMessage::CMD_RAW: if ((mode != MODE_RAW)) { DeviceHandlerMessage::clear(message); @@ -1270,3 +1283,9 @@ void DeviceHandlerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) { void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task_){ executingTask = task_; } + +// Default implementations empty. +void DeviceHandlerBase::debugInterface(uint8_t positionTracker, + object_id_t objectId, uint32_t parameter) {} + +void DeviceHandlerBase::performOperationHook() {} diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index 756ad530..435f8e06 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -1,26 +1,24 @@ #ifndef DEVICEHANDLERBASE_H_ #define DEVICEHANDLERBASE_H_ -#include +#include +#include +#include +#include #include -#include #include #include -#include -#include #include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include #include -#include + +#include +#include +#include +#include +#include + +#include namespace Factory{ void setStaticFrameworkObjectIds(); @@ -29,29 +27,53 @@ void setStaticFrameworkObjectIds(); class StorageManagerIF; /** - * \defgroup devices Devices + * @defgroup devices Devices * Contains all devices and the DeviceHandlerBase class. */ /** - * \brief This is the abstract base class for device handlers. - * + * @brief This is the abstract base class for device handlers. + * @details * Documentation: Dissertation Baetz p.138,139, p.141-149 - * SpaceWire Remote Memory Access Protocol (RMAP) * - * It features handling of @link DeviceHandlerIF::Mode_t Modes @endlink, the RMAP communication and the - * communication with commanding objects. + * It features handling of @link DeviceHandlerIF::Mode_t Modes @endlink, + * communication with physical devices, using the @link DeviceCommunicationIF @endlink, + * and communication with commanding objects. * It inherits SystemObject and thus can be created by the ObjectManagerIF. * * This class uses the opcode of ExecutableObjectIF to perform a step-wise execution. - * For each step an RMAP action is selected and executed. If data has been received (eg in case of an RMAP Read), the data will be interpreted. - * The action for each step can be defined by the child class but as most device handlers share a 4-call (Read-getRead-write-getWrite) structure, - * a default implementation is provided. + * For each step an RMAP action is selected and executed. + * If data has been received (GET_READ), the data will be interpreted. + * The action for each step can be defined by the child class but as most + * device handlers share a 4-call (sendRead-getRead-sendWrite-getWrite) structure, + * a default implementation is provided. NOTE: RMAP is a standard which is used for FLP. + * RMAP communication is not mandatory for projects implementing the FSFW. + * However, the communication principles are similar to RMAP as there are + * two write and two send calls involved. * * Device handler instances should extend this class and implement the abstract functions. * Components and drivers can send so called cookies which are used for communication + * and contain information about the communcation (e.g. slave address for I2C or RMAP structs). + * The following abstract methods must be implemented by a device handler: + * 1. doStartUp() + * 2. doShutDown() + * 3. buildTransitionDeviceCommand() + * 4. buildNormalDeviceCommand() + * 5. buildCommandFromCommand() + * 6. fillCommandAndReplyMap() + * 7. scanForReply() + * 8. interpretDeviceReply() * - * \ingroup devices + * Other important virtual methods with a default implementation + * are the getTransitionDelayMs() function and the getSwitches() function. + * Please ensure that getSwitches() returns DeviceHandlerIF::NO_SWITCHES if + * power switches are not implemented yet. Otherwise, the device handler will + * not transition to MODE_ON, even if setMode(MODE_ON) is called. + * If a transition to MODE_ON is desired without commanding, override the + * intialize() function and call setMode(_MODE_START_UP) before calling + * DeviceHandlerBase::initialize(). + * + * @ingroup devices */ class DeviceHandlerBase: public DeviceHandlerIF, public HasReturnvaluesIF, @@ -68,59 +90,402 @@ public: * * @param setObjectId the ObjectId to pass to the SystemObject() Constructor * @param maxDeviceReplyLen the length the RMAP getRead call will be sent with - * @param setDeviceSwitch the switch the device is connected to, for devices using two switches, overwrite getSwitches() + * @param setDeviceSwitch the switch the device is connected to, + * for devices using two switches, overwrite getSwitches() + * @param deviceCommuncation Communcation Interface object which is used + * to implement communication functions + * @param thermalStatePoolId + * @param thermalRequestPoolId + * @param fdirInstance + * @param cmdQueueSize */ - DeviceHandlerBase(uint32_t ioBoardAddress, object_id_t setObjectId, - uint32_t maxDeviceReplyLen, uint8_t setDeviceSwitch, - object_id_t deviceCommunication, uint32_t thermalStatePoolId = - PoolVariableIF::NO_PARAMETER, + DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, + CookieIF * comCookie, uint8_t setDeviceSwitch, + uint32_t thermalStatePoolId = PoolVariableIF::NO_PARAMETER, uint32_t thermalRequestPoolId = PoolVariableIF::NO_PARAMETER, - FailureIsolationBase* fdirInstance = NULL, uint32_t cmdQueueSize = 20); - - virtual MessageQueueId_t getCommandQueue(void) const; - + FailureIsolationBase* fdirInstance = nullptr, + size_t cmdQueueSize = 20); /** - * This function is a core component and is called periodically. - * General sequence: - * If the State is SEND_WRITE: - * 1. Set the cookie state to COOKIE_UNUSED and read the command queue - * 2. Handles Device State Modes by calling doStateMachine(). - * This function calls callChildStatemachine() which calls the abstract functions - * doStartUp() and doShutDown() - * 3. Check switch states by calling checkSwitchStates() - * 4. Decrements counter for timeout of replies by calling decrementDeviceReplyMap() - * 5. Performs FDIR check for failures - * 6. Calls hkSwitcher.performOperation() - * 7. If the device mode is MODE_OFF, return RETURN_OK. Otherwise, perform the Action property - * and performs depending on value specified - * by input value counter. The child class tells base class what to do by setting this value. - * - SEND_WRITE: Send data or commands to device by calling doSendWrite() - * Calls abstract funtions buildNomalDeviceCommand() - * or buildTransitionDeviceCommand() - * - GET_WRITE: Get ackknowledgement for sending by calling doGetWrite(). - * Calls abstract functions scanForReply() and interpretDeviceReply(). - * - SEND_READ: Request reading data from device by calling doSendRead() - * - GET_READ: Access requested reading data by calling doGetRead() - * @param counter Specifies which Action to perform - * @return RETURN_OK for successful execution - */ + * @brief This function is the device handler base core component and is + * called periodically. + * @details + * General sequence, showing where abstract virtual functions are called: + * If the State is SEND_WRITE: + * 1. Set the cookie state to COOKIE_UNUSED and read the command queue + * 2. Handles Device State Modes by calling doStateMachine(). + * This function calls callChildStatemachine() which calls the + * abstract functions doStartUp() and doShutDown() + * 3. Check switch states by calling checkSwitchStates() + * 4. Decrements counter for timeout of replies by calling + * decrementDeviceReplyMap() + * 5. Performs FDIR check for failures + * 6. Calls hkSwitcher.performOperation() + * 7. If the device mode is MODE_OFF, return RETURN_OK. + * Otherwise, perform the Action property and performs depending + * on value specified by input value counter (incremented in PST). + * The child class tells base class what to do by setting this value. + * - SEND_WRITE: Send data or commands to device by calling + * doSendWrite() which calls sendMessage function + * of #communicationInterface + * and calls buildInternalCommand if the cookie state is COOKIE_UNUSED + * - GET_WRITE: Get ackknowledgement for sending by calling doGetWrite() + * which calls getSendSuccess of #communicationInterface. + * Calls abstract functions scanForReply() and interpretDeviceReply(). + * - SEND_READ: Request reading data from device by calling doSendRead() + * which calls requestReceiveMessage of #communcationInterface + * - GET_READ: Access requested reading data by calling doGetRead() + * which calls readReceivedMessage of #communicationInterface + * @param counter Specifies which Action to perform + * @return RETURN_OK for successful execution + */ virtual ReturnValue_t performOperation(uint8_t counter); + /** + * @brief Initializes the device handler + * @details + * Initialize Device Handler as system object and + * initializes all important helper classes. + * Calls fillCommandAndReplyMap(). + * @return + */ virtual ReturnValue_t initialize(); - /** - * - * @param parentQueueId - */ - virtual void setParentQueue(MessageQueueId_t parentQueueId); /** * Destructor. */ virtual ~DeviceHandlerBase(); +protected: + /** + * @brief This is used to let the child class handle the transition from + * mode @c _MODE_START_UP to @c MODE_ON + * @details + * It is only called when the device handler is in mode @c _MODE_START_UP. + * That means, the device switch(es) are already set to on. + * Device handler commands are read and can be handled by the child class. + * If the child class handles a command, it should also send + * an reply accordingly. + * If an Command is not handled (ie #DeviceHandlerCommand is not @c CMD_NONE, + * the base class handles rejecting the command and sends a reply. + * The replies for mode transitions are handled by the base class. + * + * - If the device is started and ready for operation, the mode should be + * set to MODE_ON. It is possible to set the mode to _MODE_TO_ON to + * use the to on transition if available. + * - If the power-up fails, the mode should be set to _MODE_POWER_DOWN + * which will lead to the device being powered off. + * - If the device does not change the mode, the mode will be changed + * to _MODE_POWER_DOWN, after the timeout (from getTransitionDelay()) + * has passed. + * + * #transitionFailure can be set to a failure code indicating the reason + * for a failed transition + */ + virtual void doStartUp() = 0; + /** + * @brief This is used to let the child class handle the transition + * from mode @c _MODE_SHUT_DOWN to @c _MODE_POWER_DOWN + * @details + * It is only called when the device handler is in mode @c _MODE_SHUT_DOWN. + * Device handler commands are read and can be handled by the child class. + * If the child class handles a command, it should also send an reply + * accordingly. + * If an Command is not handled (ie #DeviceHandlerCommand is not + * @c CMD_NONE, the base class handles rejecting the command and sends a + * reply. The replies for mode transitions are handled by the base class. + * + * - If the device ready to be switched off, + * the mode should be set to _MODE_POWER_DOWN. + * - If the device should not be switched off, the mode can be changed to + * _MODE_TO_ON (or MODE_ON if no transition is needed). + * - If the device does not change the mode, the mode will be changed to + * _MODE_POWER_DOWN, when the timeout (from getTransitionDelay()) + * has passed. + * + * #transitionFailure can be set to a failure code indicating the reason + * for a failed transition + */ + virtual void doShutDown() = 0; + + /** + * Build the device command to send for normal mode. + * + * This is only called in @c MODE_NORMAL. If multiple submodes for + * @c MODE_NORMAL are supported, different commands can built, + * depending on the submode. + * + * #rawPacket and #rawPacketLen must be set by this method to the + * packet to be sent. If variable command frequence is required, a counter + * can be used and the frequency in the reply map has to be set manually + * by calling updateReplyMap(). + * + * @param[out] id the device command id that has been built + * @return + * - @c RETURN_OK to send command after setting #rawPacket and #rawPacketLen. + * - @c NOTHING_TO_SEND when no command is to be sent. + * - Anything else triggers an even with the returnvalue as a parameter. + */ + virtual ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t * id) = 0; + + /** + * Build the device command to send for a transitional mode. + * + * This is only called in @c _MODE_TO_NORMAL, @c _MODE_TO_ON, @c _MODE_TO_RAW, + * @c _MODE_START_UP and @c _MODE_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 + * and filling them in doStartUp(), doShutDown() and doTransition() so no + * modes have to be checked here. + * + * #rawPacket and #rawPacketLen must be set by this method to the packet to be sent. + * + * @param[out] id the device command id built + * @return + * - @c RETURN_OK when a command is to be sent + * - @c NOTHING_TO_SEND when no command is to be sent + * - Anything else triggers an even with the returnvalue as a parameter + */ + virtual ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t * id) = 0; + + /** + * @brief Build a device command packet from data supplied by a direct command. + * + * @details + * #rawPacket and #rawPacketLen should be set by this method to the packet to be sent. + * The existence of the command in the command map and the command size check + * against 0 are done by the base class. + * + * @param deviceCommand the command to build, already checked against deviceCommandMap + * @param commandData pointer to the data from the direct command + * @param commandDataLen length of commandData + * @return + * - @c RETURN_OK to send command after #rawPacket and #rawPacketLen have been set. + * - Anything else triggers an event with the returnvalue as a parameter + */ + virtual ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, + 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 + * called by the initialize() of the base class + * @details + * This is used to let the base class know which replies are expected. + * There are different scenarios regarding this: + * + * - "Normal" commands. These are commands, that trigger a direct reply + * from the device. In this case, the id of the command should be added + * to the command map with a commandData_t where maxDelayCycles is set + * to the maximum expected number of PST cycles the reply will take. + * Then, scanForReply returns the id of the command and the base class + * can handle time-out and missing replies. + * + * - Periodic, unrequested replies. These are replies that, once enabled, + * are sent by the device on its own in a defined interval. + * In this case, the id of the reply or a placeholder id should be added + * to the deviceCommandMap with a commandData_t where maxDelayCycles is + * set to the maximum expected number of PST cycles between two replies + * (also a tolerance should be added, as an FDIR message will be + * generated if it is missed). + * + * (Robin) This part confuses me. "must do as soon as" implies that + * the developer must do something somewhere else in the code. Is + * that really the case? If I understood correctly, DHB performs + * almost everything (e.g. in erirm function) as long as the commands + * are inserted correctly. + * + * As soon as the replies are enabled, DeviceCommandInfo.periodic must + * be set to true, DeviceCommandInfo.delayCycles to + * DeviceCommandInfo.maxDelayCycles. + * From then on, the base class handles the reception. + * Then, scanForReply returns the id of the reply or the placeholder id + * and the base class will take care of checking that all replies are + * received and the interval is correct. + * When the replies are disabled, DeviceCommandInfo.periodic must be set + * to 0, DeviceCommandInfo.delayCycles to 0; + * + * - Aperiodic, unrequested replies. These are replies that are sent + * by the device without any preceding command and not in a defined + * interval. These are not entered in the deviceCommandMap but + * handled by returning @c APERIODIC_REPLY in scanForReply(). + */ + virtual void fillCommandAndReplyMap() = 0; + + /** + * This is a helper method to facilitate inserting entries in the command map. + * @param deviceCommand Identifier of the command to add. + * @param maxDelayCycles The maximum number of delay cycles the command + * waits until it times out. + * @param periodic Indicates if the command is periodic (i.e. it is sent + * by the device repeatedly without request) or not. Default is aperiodic (0) + * @return - @c RETURN_OK when the command was successfully inserted, + * - @c RETURN_FAILED else. + */ + ReturnValue_t insertInCommandAndReplyMap(DeviceCommandId_t deviceCommand, + uint16_t maxDelayCycles, size_t replyLen = 0, bool periodic = false, + bool hasDifferentReplyId = false, DeviceCommandId_t replyId = 0); + + /** + * @brief This is a helper method to insert replies in the reply map. + * @param deviceCommand Identifier of the reply to add. + * @param maxDelayCycles The maximum number of delay cycles the reply waits + * until it times out. + * @param periodic Indicates if the command is periodic (i.e. it is sent + * by the device repeatedly without request) or not. Default is aperiodic (0) + * @return - @c RETURN_OK when the command was successfully inserted, + * - @c RETURN_FAILED else. + */ + ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand, + uint16_t maxDelayCycles, size_t replyLen = 0, bool periodic = false); + + /** + * @brief A simple command to add a command to the commandList. + * @param deviceCommand The command to add + * @return - @c RETURN_OK when the command was successfully inserted, + * - @c RETURN_FAILED else. + */ + ReturnValue_t insertInCommandMap(DeviceCommandId_t deviceCommand); + /** + * @brief This is a helper method to facilitate updating entries + * in the reply map. + * @param deviceCommand Identifier of the reply to update. + * @param delayCycles The current number of delay cycles to wait. + * As stated in #fillCommandAndCookieMap, to disable periodic commands, + * this is set to zero. + * @param maxDelayCycles The maximum number of delay cycles the reply waits + * until it times out. By passing 0 the entry remains untouched. + * @param periodic Indicates if the command is periodic (i.e. it is sent + * by the device repeatedly without request) or not.Default is aperiodic (0). + * Warning: The setting always overrides the value that was entered in the map. + * @return - @c RETURN_OK when the command was successfully inserted, + * - @c RETURN_FAILED else. + */ + ReturnValue_t updateReplyMapEntry(DeviceCommandId_t deviceReply, + uint16_t delayCycles, uint16_t maxDelayCycles, + bool periodic = false); + + /** + * @brief Can be implemented by child handler to + * perform debugging + * @details Example: Calling this in performOperation + * to track values like mode. + * @param positionTracker Provide the child handler a way to know + * where the debugInterface was called + * @param objectId Provide the child handler object Id to + * specify actions for spefic devices + * @param parameter Supply a parameter of interest + * Please delete all debugInterface calls in DHB after debugging is finished ! + */ + virtual void debugInterface(uint8_t positionTracker = 0, + object_id_t objectId = 0, uint32_t parameter = 0); + + /** + * Get the time needed to transit from modeFrom to modeTo. + * + * Used for the following transitions: + * modeFrom -> modeTo: + * MODE_ON -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] + * MODE_NORMAL -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] + * MODE_RAW -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] + * _MODE_START_UP -> MODE_ON (do not include time to set the switches, + * the base class got you covered) + * + * The default implementation returns 0 ! + * @param modeFrom + * @param modeTo + * @return time in ms + */ + virtual uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo); + + /** + * Return the switches connected to the device. + * + * The default implementation returns one switch set in the ctor. + * + * @param[out] switches pointer to an array of switches + * @param[out] numberOfSwitches length of returned array + * @return + * - @c RETURN_OK if the parameters were set + * - @c RETURN_FAILED if no switches exist + */ + virtual ReturnValue_t getSwitches(const uint8_t **switches, + uint8_t *numberOfSwitches); + + /** + * @brief Hook function for child handlers which is called once per + * performOperation(). Default implementation is empty. + */ + virtual void performOperationHook(); +public: + /** + * @param parentQueueId + */ + virtual void setParentQueue(MessageQueueId_t parentQueueId); + + /** @brief Implementation required for HasActionIF */ ReturnValue_t executeAction(ActionId_t actionId, - MessageQueueId_t commandedBy, const uint8_t* data, uint32_t size); + MessageQueueId_t commandedBy, const uint8_t* data, + uint32_t size) override; + Mode_t getTransitionSourceMode() const; Submode_t getTransitionSourceSubMode() const; virtual void getMode(Mode_t *mode, Submode_t *submode); @@ -136,24 +501,27 @@ public: * @param task_ Pointer to the taskIF of this task */ virtual void setTaskIF(PeriodicTaskIF* task_); + virtual MessageQueueId_t getCommandQueue(void) const; + protected: /** - * The Returnvalues id of this class, required by HasReturnvaluesIF + * The Returnvalues ID of this class, required by HasReturnvaluesIF */ static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE; - static const ReturnValue_t INVALID_CHANNEL = MAKE_RETURN_CODE(4); - static const ReturnValue_t APERIODIC_REPLY = MAKE_RETURN_CODE(5); - static const ReturnValue_t IGNORE_REPLY_DATA = MAKE_RETURN_CODE(6); -// 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 - static const ReturnValue_t CHILD_TIMEOUT = MAKE_RETURN_CODE(0xE1); - static const ReturnValue_t SWITCH_FAILED = MAKE_RETURN_CODE(0xE2); + static const ReturnValue_t INVALID_CHANNEL = MAKE_RETURN_CODE(0xA0); + // Returnvalues for scanForReply() + static const ReturnValue_t APERIODIC_REPLY = MAKE_RETURN_CODE(0xB0); //!< This is used to specify for replies from a device which are not replies to requests + static const ReturnValue_t IGNORE_REPLY_DATA = MAKE_RETURN_CODE(0xB1); //!< Ignore parts of the received packet + static const ReturnValue_t IGNORE_FULL_PACKET = MAKE_RETURN_CODE(0xB2); //!< Ignore full received packet + // Returnvalues for command building + static const ReturnValue_t NOTHING_TO_SEND = MAKE_RETURN_CODE(0xC0); //!< Return this if no command sending in required + static const ReturnValue_t COMMAND_MAP_ERROR = MAKE_RETURN_CODE(0xC2); + // Returnvalues for getSwitches() + static const ReturnValue_t NO_SWITCH = MAKE_RETURN_CODE(0xD0); + // Mode handling error Codes + static const ReturnValue_t CHILD_TIMEOUT = MAKE_RETURN_CODE(0xE0); + static const ReturnValue_t SWITCH_FAILED = MAKE_RETURN_CODE(0xE1); static const DeviceCommandId_t RAW_COMMAND_ID = -1; static const DeviceCommandId_t NO_COMMAND_ID = -2; @@ -162,11 +530,11 @@ protected: /** * Pointer to the raw packet that will be sent. */ - uint8_t *rawPacket; + uint8_t *rawPacket = nullptr; /** * Size of the #rawPacket. */ - uint32_t rawPacketLen; + uint32_t rawPacketLen = 0; /** * The mode the device handler is currently in. @@ -185,12 +553,7 @@ protected: /** * This is the counter value from performOperation(). */ - uint8_t pstStep; - - /** - * This will be used in the RMAP getRead command as expected length, is set by the constructor, can be modiefied at will. - */ - const uint32_t maxDeviceReplyLen; + uint8_t pstStep = 0; /** * wiretapping flag: @@ -208,7 +571,7 @@ protected: * Statically initialized in initialize() to a configurable object. Used when there is no method * of finding a recipient, ie raw mode and reporting erreonous replies */ - MessageQueueId_t defaultRawReceiver; + MessageQueueId_t defaultRawReceiver = 0; store_address_t storedRawData; @@ -217,19 +580,19 @@ protected: * * if #isWiretappingActive all raw communication from and to the device will be sent to this queue */ - MessageQueueId_t requestedRawTraffic; + MessageQueueId_t requestedRawTraffic = 0; /** * the object used to set power switches */ - PowerSwitchIF *powerSwitcher; + PowerSwitchIF *powerSwitcher = nullptr; /** * Pointer to the IPCStore. * * This caches the pointer received from the objectManager in the constructor. */ - StorageManagerIF *IPCStore; + StorageManagerIF *IPCStore = nullptr; /** * cached for init @@ -239,17 +602,40 @@ protected: /** * Communication object used for device communication */ - DeviceCommunicationIF *communicationInterface; + DeviceCommunicationIF * communicationInterface = nullptr; /** * Cookie used for communication */ - Cookie *cookie; + CookieIF * comCookie; + + struct DeviceCommandInfo { + bool isExecuting; //!< Indicates if the command is already executing. + 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. + }; + using DeviceCommandMap = std::map ; + + /** + * @brief Information about expected replies + * + * This is used to keep track of pending replies + */ + struct DeviceReplyInfo { + 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 + size_t replyLen = 0; //!< Expected size of the reply. + bool 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. + }; + + using DeviceReplyMap = std::map ; + using DeviceReplyIter = DeviceReplyMap::iterator; /** * The MessageQueue used to receive device handler commands and to send replies. */ - MessageQueueIF* commandQueue; + MessageQueueIF* commandQueue = nullptr; /** * this is the datapool variable with the thermal state of the device @@ -280,7 +666,7 @@ protected: */ ReturnValue_t childTransitionFailure; - uint32_t ignoreMissedRepliesCount; //!< 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. FailureIsolationBase* fdirInstance; //!< Pointer to the used FDIR instance. If not provided by child, default class is instantiated. @@ -290,7 +676,7 @@ protected: 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. @@ -317,11 +703,6 @@ protected: void replyReturnvalueToCommand(ReturnValue_t status, uint32_t parameter = 0); - /** - * - - * @param parameter2 additional parameter - */ void replyToCommand(ReturnValue_t status, uint32_t parameter = 0); /** @@ -329,7 +710,8 @@ protected: * * Sets #timeoutStart with every call. * - * Sets #transitionTargetMode if necessary so transitional states can be entered from everywhere without breaking the state machine + * 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. @@ -345,41 +727,6 @@ protected: */ void setMode(Mode_t newMode, Submode_t submode); - /** - * This is used to let the child class handle the transition from mode @c _MODE_START_UP to @c MODE_ON - * - * It is only called when the device handler is in mode @c _MODE_START_UP. That means, the device switch(es) are already set to on. - * Device handler commands are read and can be handled by the child class. If the child class handles a command, it should also send - * an reply accordingly. - * If an Command is not handled (ie #DeviceHandlerCommand is not @c CMD_NONE, the base class handles rejecting the command and sends a reply. - * The replies for mode transitions are handled by the base class. - * - * If the device is started and ready for operation, the mode should be set to MODE_ON. It is possible to set the mode to _MODE_TO_ON to - * use the to on transition if available. - * If the power-up fails, the mode should be set to _MODE_POWER_DOWN which will lead to the device being powered off. - * If the device does not change the mode, the mode will be changed to _MODE_POWER_DOWN, after the timeout (from getTransitionDelay()) has passed. - * - * #transitionFailure can be set to a failure code indicating the reason for a failed transition - */ - virtual void doStartUp() = 0; - - /** - * This is used to let the child class handle the transition from mode @c _MODE_SHUT_DOWN to @c _MODE_POWER_DOWN - * - * It is only called when the device handler is in mode @c _MODE_SHUT_DOWN. - * Device handler commands are read and can be handled by the child class. If the child class handles a command, it should also send - * an reply accordingly. - * If an Command is not handled (ie #DeviceHandlerCommand is not @c CMD_NONE, the base class handles rejecting the command and sends a reply. - * The replies for mode transitions are handled by the base class. - * - * If the device ready to be switched off, the mode should be set to _MODE_POWER_DOWN. - * If the device should not be switched off, the mode can be changed to _MODE_TO_ON (or MODE_ON if no transition is needed). - * If the device does not change the mode, the mode will be changed to _MODE_POWER_DOWN, when the timeout (from getTransitionDelay()) has passed. - * - * #transitionFailure can be set to a failure code indicating the reason for a failed transition - */ - virtual void doShutDown() = 0; - /** * Do the transition to the main modes (MODE_ON, MODE_NORMAL and MODE_RAW). * @@ -409,24 +756,6 @@ protected: */ virtual void doTransition(Mode_t modeFrom, Submode_t subModeFrom); - /** - * Get the time needed to transit from modeFrom to modeTo. - * - * Used for the following transitions: - * modeFrom -> modeTo: - * MODE_ON -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] - * MODE_NORMAL -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] - * MODE_RAW -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] - * _MODE_START_UP -> MODE_ON (do not include time to set the switches, the base class got you covered) - * - * The default implementation returns 0; - * - * @param modeFrom - * @param modeTo - * @return time in ms - */ - virtual uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo); - /** * Is the combination of mode and submode valid? * @@ -446,41 +775,8 @@ protected: * * @return The Rmap action to execute in this step */ - virtual RmapAction_t getRmapAction(); - /** - * Build the device command to send for normal mode. - * - * This is only called in @c MODE_NORMAL. If multiple submodes for @c MODE_NORMAL are supported, - * different commands can built returned depending on the submode. - * - * #rawPacket and #rawPacketLen must be set by this method to the packet to be sent. - * - * @param[out] id the device command id that has been built - * @return - * - @c RETURN_OK when a command is to be sent - * - not @c RETURN_OK when no command is to be sent - */ - virtual ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t * id) = 0; - - /** - * Build the device command to send for a transitional mode. - * - * This is only called in @c _MODE_TO_NORMAL, @c _MODE_TO_ON, @c _MODE_TO_RAW, - * @c _MODE_START_UP and @c _MODE_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 - * and filling them in doStartUp(), doShutDown() and doTransition() so no modes have to be checked here. - * - * #rawPacket and #rawPacketLen must be set by this method to the packet to be sent. - * - * @param[out] id the device command id built - * @return - * - @c RETURN_OK when a command is to be sent - * - not @c RETURN_OK when no command is to be sent - */ - virtual ReturnValue_t buildTransitionDeviceCommand( - DeviceCommandId_t * id) = 0; + virtual CommunicationAction_t getComAction(); /** * Build the device command to send for raw mode. @@ -502,80 +798,6 @@ protected: */ virtual ReturnValue_t buildChildRawCommand(); - /** - * Build a device command packet from data supplied by a direct command. - * - * #rawPacket and #rawPacketLen should be set by this method to the packet to be sent. - * - * @param deviceCommand the command to build, already checked against deviceCommandMap - * @param commandData pointer to the data from the direct command - * @param commandDataLen length of commandData - * @return - * - @c RETURN_OK when #rawPacket is valid - * - @c RETURN_FAILED when #rawPacket is invalid and no data should be sent - */ - virtual ReturnValue_t buildCommandFromCommand( - DeviceCommandId_t deviceCommand, const uint8_t * commandData, - size_t commandDataLen) = 0; - - /** - * fill the #deviceCommandMap - * - * called by the initialize() of the base class - * - * This is used to let the base class know which replies are expected. - * There are different scenarios regarding this: - * - "Normal" commands. These are commands, that trigger a direct reply from the device. In this case, the id of the command should be added to the command map - * with a commandData_t where maxDelayCycles is set to the maximum expected number of PST cycles the reply will take. Then, scanForReply returns the id of the command and the base class can handle time-out and missing replies. - * - Periodic, unrequested replies. These are replies that, once enabled, are sent by the device on its own in a defined interval. In this case, the id of the reply or a placeholder id should be added to the deviceCommandMap - * with a commandData_t where maxDelayCycles is set to the maximum expected number of PST cycles between two replies (also a tolerance should be added, as an FDIR message will be generated if it is missed). - * As soon as the replies are enabled, DeviceCommandInfo.periodic must be set to 1, DeviceCommandInfo.delayCycles to DeviceCommandInfo.MaxDelayCycles. From then on, the base class handles the reception. - * Then, scanForReply returns the id of the reply or the placeholder id and the base class will take care of checking that all replies are received and the interval is correct. - * When the replies are disabled, DeviceCommandInfo.periodic must be set to 0, DeviceCommandInfo.delayCycles to 0; - * - Aperiodic, unrequested replies. These are replies that are sent by the device without any preceding command and not in a defined interval. These are not entered in the deviceCommandMap but handled by returning @c APERIODIC_REPLY in scanForReply(). - * - */ - virtual void fillCommandAndReplyMap() = 0; - - /** - * This is a helper method to facilitate inserting entries in the command map. - * @param deviceCommand Identifier of the command to add. - * @param maxDelayCycles The maximum number of delay cycles the command waits until it times out. - * @param 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 insertInCommandAndReplyMap(DeviceCommandId_t deviceCommand, - uint16_t maxDelayCycles, 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, 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. @@ -583,48 +805,6 @@ protected: * @return The current delay count. If the command does not exist (should never happen) it returns 0. */ uint8_t getReplyDelayCycles(DeviceCommandId_t deviceCommand); - /** - * Scans a buffer for a valid reply. - * - * This is used by the base class to check the data received from the RMAP stack for valid packets. - * It only checks if a valid packet starts at @c start. - * It also only checks the structural validy of the packet, eg checksums lengths and protocol data. No - * information check is done, eg 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 data - * @param len length of data - * @param[out] foundId the id of the packet starting at @c start - * @param[out] foundLen length of the packet found - * @return - * - @c RETURN_OK a valid packet was found at @c start, @c foundLen is valid - * - @c NO_VALID_REPLY no reply could be found starting at @c start, implies @c foundLen is not valid, base class will call scanForReply() again with ++start - * - @c INVALID_REPLY a packet was found but it is invalid, eg checksum error, implies @c foundLen is valid, can be used to skip some bytes - * - @c TOO_SHORT @c len is too short for any valid 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, uint32_t len, - DeviceCommandId_t *foundId, uint32_t *foundLen) = 0; - - /** - * Interpret a reply from the device. - * - * 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 the 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 - * @param commander the one who initiated the command, is 0 if not external commanded - * @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, - const uint8_t *packet) = 0; /** * Construct a command reply containing a raw reply. @@ -649,33 +829,11 @@ protected: */ void replyRawReplyIfnotWiretapped(const uint8_t *data, size_t len); - /** - * Return the switches connected to the device. - * - * The default implementation returns one switch set in the ctor. - * - * - * @param[out] switches pointer to an array of switches - * @param[out] numberOfSwitches length of returned array - * @return - * - @c RETURN_OK if the parameters were set - * - @c RETURN_FAILED if no switches exist - */ - virtual ReturnValue_t getSwitches(const uint8_t **switches, - uint8_t *numberOfSwitches); - /** * notify child about mode change */ virtual void modeChanged(void); - struct DeviceCommandInfo { - bool isExecuting; //!< Indicates if the command is already executing. - uint8_t expectedReplies; //!< Dynamic value to indicate how many replies are expected. - MessageQueueId_t sendReplyTo; //!< if this is != NO_COMMANDER, DHB was commanded externally and shall report everything to commander. - }; - - typedef std::map DeviceCommandMap; /** * Enable the reply checking for a command * @@ -686,16 +844,16 @@ protected: * When found, copies maxDelayCycles to delayCycles in the reply information and sets the command to * expect one reply. * - * Can be overwritten by the child, if a command activates multiple replies or replyId differs from - * commandId. + * Can be overwritten by the child, if a command activates multiple replies + * or replyId differs from commandId. * Notes for child implementations: * - If the command was not found in the reply map, NO_REPLY_EXPECTED MUST be returned. * - A failure code may be returned if something went fundamentally wrong. * * @param deviceCommand * @return - RETURN_OK if a reply was activated. - * - NO_REPLY_EXPECTED if there was no reply found. This is not an error case as many commands - * do not expect a reply. + * - NO_REPLY_EXPECTED if there was no reply found. This is not an + * error case as many commands do not expect a reply. */ virtual ReturnValue_t enableReplyInReplyMap(DeviceCommandMap::iterator cmd, uint8_t expectedReplies = 1, bool useAlternateId = false, @@ -794,22 +952,6 @@ protected: bool commandIsExecuting(DeviceCommandId_t commandId); - /** - * Information about expected replies - * - * This is used to keep track of pending replies - */ - struct DeviceReplyInfo { - 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 - 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. - }; - - /** - * Definition for the important reply Map. - */ - typedef std::map DeviceReplyMap; /** * This map is used to check and track correct reception of all replies. * @@ -861,17 +1003,12 @@ private: */ CookieInfo cookieInfo; - /** - * cached from ctor for initialize() - */ - const uint32_t ioBoardAddress; - /** * Used for timing out mode transitions. * * Set when setMode() is called. */ - uint32_t timeoutStart; + uint32_t timeoutStart = 0; /** * Delay for the current mode transition, used for time out diff --git a/devicehandlers/DeviceHandlerIF.h b/devicehandlers/DeviceHandlerIF.h index fe0ee8e8..666d9efc 100644 --- a/devicehandlers/DeviceHandlerIF.h +++ b/devicehandlers/DeviceHandlerIF.h @@ -8,7 +8,8 @@ #include /** - * This is the Interface used to communicate with a device handler. + * @brief This is the Interface used to communicate with a device handler. + * @details Includes all expected return values, events and modes. * */ class DeviceHandlerIF { @@ -22,93 +23,127 @@ public: * * @details The mode of the device handler must not be confused with the mode the device is in. * The mode of the device itself is transparent to the user but related to the mode of the handler. + * MODE_ON and MODE_OFF are included in hasModesIF.h */ -// MODE_ON = 0, //!< The device is powered and ready to perform operations. In this mode, no commands are sent by the device handler itself, but direct commands van be commanded and will be interpreted -// MODE_OFF = 1, //!< The device is powered off. The only command accepted in this mode is a mode change to on. - static const Mode_t MODE_NORMAL = 2; //!< The device is powered on and the device handler periodically sends commands. The commands to be sent are selected by the handler according to the submode. - static const Mode_t MODE_RAW = 3; //!< The device is powered on and ready to perform operations. In this mode, raw commands can be sent. The device handler will send all replies received from the command back to the commanding object. - static const Mode_t MODE_ERROR_ON = 4; //!4< The device is shut down but the switch could not be turned off, so the device still is powered. In this mode, only a mode change to @c MODE_OFF can be commanded, which tries to switch off the device again. - static const Mode_t _MODE_START_UP = TRANSITION_MODE_CHILD_ACTION_MASK | 5; //!< This is a transitional state which can not be commanded. The device handler performs all commands to get the device in a state ready to perform commands. When this is completed, the mode changes to @c MODE_ON. - static const Mode_t _MODE_SHUT_DOWN = TRANSITION_MODE_CHILD_ACTION_MASK | 6; //!< This is a transitional state which can not be commanded. The device handler performs all actions and commands to get the device shut down. When the device is off, the mode changes to @c MODE_OFF. - static const Mode_t _MODE_TO_ON = TRANSITION_MODE_CHILD_ACTION_MASK | HasModesIF::MODE_ON; - static const Mode_t _MODE_TO_RAW = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_RAW; - static const Mode_t _MODE_TO_NORMAL = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_NORMAL; - static const Mode_t _MODE_POWER_DOWN = TRANSITION_MODE_BASE_ACTION_MASK | 1; //!< This is a transitional state which can not be commanded. The device is shut down and ready to be switched off. After the command to set the switch off has been sent, the mode changes to @c MODE_WAIT_OFF - static const Mode_t _MODE_POWER_ON = TRANSITION_MODE_BASE_ACTION_MASK | 2; //!< This is a transitional state which can not be commanded. The device will be switched on in this state. After the command to set the switch on has been sent, the mode changes to @c MODE_WAIT_ON - static const Mode_t _MODE_WAIT_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 3; //!< This is a transitional state which can not be commanded. The switch has been commanded off and the handler waits for it to be off. When the switch is off, the mode changes to @c MODE_OFF. - static const Mode_t _MODE_WAIT_ON = TRANSITION_MODE_BASE_ACTION_MASK | 4; //!< This is a transitional state which can not be commanded. The switch has been commanded on and the handler waits for it to be on. When the switch is on, the mode changes to @c MODE_TO_ON. - static const Mode_t _MODE_SWITCH_IS_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 5; //!< This is a transitional state which can not be commanded. The switch has been commanded off and is off now. This state is only to do an RMAP cycle once more where the doSendRead() function will set the mode to MODE_OFF. The reason to do this is to get rid of stuck packets in the IO Board - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CDH; - static const Event DEVICE_BUILDING_COMMAND_FAILED = MAKE_EVENT(0, SEVERITY::LOW); - static const Event DEVICE_SENDING_COMMAND_FAILED = MAKE_EVENT(1, SEVERITY::LOW); - static const Event DEVICE_REQUESTING_REPLY_FAILED = MAKE_EVENT(2, SEVERITY::LOW); - static const Event DEVICE_READING_REPLY_FAILED = MAKE_EVENT(3, SEVERITY::LOW); - static const Event DEVICE_INTERPRETING_REPLY_FAILED = MAKE_EVENT(4, SEVERITY::LOW); - static const Event DEVICE_MISSED_REPLY = MAKE_EVENT(5, SEVERITY::LOW); - static const Event DEVICE_UNKNOWN_REPLY = MAKE_EVENT(6, SEVERITY::LOW); - static const Event DEVICE_UNREQUESTED_REPLY = MAKE_EVENT(7, SEVERITY::LOW); - static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, SEVERITY::LOW); //!< Indicates a SW bug in child class. - static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, SEVERITY::LOW); - static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, SEVERITY::HIGH); + // MODE_ON = 0, //!< The device is powered and ready to perform operations. In this mode, no commands are sent by the device handler itself, but direct commands van be commanded and will be interpreted + // MODE_OFF = 1, //!< The device is powered off. The only command accepted in this mode is a mode change to on. + //! The device is powered on and the device handler periodically sends + //! commands. The commands to be sent are selected by the handler + //! according to the submode. + static const Mode_t MODE_NORMAL = 2; + //! The device is powered on and ready to perform operations. In this mode, + //! raw commands can be sent. The device handler will send all replies + //! received from the command back to the commanding object. + static const Mode_t MODE_RAW = 3; + //! The device is shut down but the switch could not be turned off, so the + //! device still is powered. In this mode, only a mode change to @c MODE_OFF + //! can be commanded, which tries to switch off the device again. + static const Mode_t MODE_ERROR_ON = 4; + //! This is a transitional state which can not be commanded. The device + //! handler performs all commands to get the device in a state ready to + //! perform commands. When this is completed, the mode changes to @c MODE_ON. + static const Mode_t _MODE_START_UP = TRANSITION_MODE_CHILD_ACTION_MASK | 5; + //! This is a transitional state which can not be commanded. + //! The device handler performs all actions and commands to get the device + //! shut down. When the device is off, the mode changes to @c MODE_OFF. + static const Mode_t _MODE_SHUT_DOWN = TRANSITION_MODE_CHILD_ACTION_MASK | 6; + //! It is possible to set the mode to _MODE_TO_ON to use the to on + //! transition if available. + static const Mode_t _MODE_TO_ON = TRANSITION_MODE_CHILD_ACTION_MASK | HasModesIF::MODE_ON; + //! It is possible to set the mode to _MODE_TO_RAW to use the to raw + //! transition if available. + static const Mode_t _MODE_TO_RAW = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_RAW; + //! It is possible to set the mode to _MODE_TO_NORMAL to use the to normal + //! transition if available. + static const Mode_t _MODE_TO_NORMAL = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_NORMAL; + //! This is a transitional state which can not be commanded. + //! The device is shut down and ready to be switched off. + //! After the command to set the switch off has been sent, + //! the mode changes to @c MODE_WAIT_OFF + static const Mode_t _MODE_POWER_DOWN = TRANSITION_MODE_BASE_ACTION_MASK | 1; + //! This is a transitional state which can not be commanded. The device + //! will be switched on in this state. After the command to set the switch + //! on has been sent, the mode changes to @c MODE_WAIT_ON. + static const Mode_t _MODE_POWER_ON = TRANSITION_MODE_BASE_ACTION_MASK | 2; + //! This is a transitional state which can not be commanded. The switch has + //! been commanded off and the handler waits for it to be off. + //! When the switch is off, the mode changes to @c MODE_OFF. + static const Mode_t _MODE_WAIT_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 3; + //! This is a transitional state which can not be commanded. The switch + //! has been commanded on and the handler waits for it to be on. + //! When the switch is on, the mode changes to @c MODE_TO_ON. + static const Mode_t _MODE_WAIT_ON = TRANSITION_MODE_BASE_ACTION_MASK | 4; + //! This is a transitional state which can not be commanded. The switch has + //! been commanded off and is off now. This state is only to do an RMAP + //! cycle once more where the doSendRead() function will set the mode to + //! MODE_OFF. The reason to do this is to get rid of stuck packets in the IO Board. + static const Mode_t _MODE_SWITCH_IS_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 5; - static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_IF; - static const ReturnValue_t NO_COMMAND_DATA = MAKE_RETURN_CODE(0xA0); - static const ReturnValue_t COMMAND_NOT_SUPPORTED = MAKE_RETURN_CODE(0xA1); - static const ReturnValue_t COMMAND_ALREADY_SENT = MAKE_RETURN_CODE(0xA2); - static const ReturnValue_t COMMAND_WAS_NOT_SENT = MAKE_RETURN_CODE(0xA3); - static const ReturnValue_t CANT_SWITCH_IOBOARD = MAKE_RETURN_CODE(0xA4); - static const ReturnValue_t WRONG_MODE_FOR_COMMAND = MAKE_RETURN_CODE(0xA5); - static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(0xA6); - static const ReturnValue_t BUSY = MAKE_RETURN_CODE(0xA7); - static const ReturnValue_t NO_REPLY_EXPECTED = MAKE_RETURN_CODE(0xA8); //!< Used to indicate that this is a command-only command. - static const ReturnValue_t NON_OP_TEMPERATURE = MAKE_RETURN_CODE(0xA9); - static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xAA); + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CDH; + static const Event DEVICE_BUILDING_COMMAND_FAILED = MAKE_EVENT(0, SEVERITY::LOW); + static const Event DEVICE_SENDING_COMMAND_FAILED = MAKE_EVENT(1, SEVERITY::LOW); + static const Event DEVICE_REQUESTING_REPLY_FAILED = MAKE_EVENT(2, SEVERITY::LOW); + static const Event DEVICE_READING_REPLY_FAILED = MAKE_EVENT(3, SEVERITY::LOW); + static const Event DEVICE_INTERPRETING_REPLY_FAILED = MAKE_EVENT(4, SEVERITY::LOW); + static const Event DEVICE_MISSED_REPLY = MAKE_EVENT(5, SEVERITY::LOW); + static const Event DEVICE_UNKNOWN_REPLY = MAKE_EVENT(6, SEVERITY::LOW); + static const Event DEVICE_UNREQUESTED_REPLY = MAKE_EVENT(7, SEVERITY::LOW); + static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, SEVERITY::LOW); //!< Indicates a SW bug in child class. + static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, SEVERITY::LOW); + static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, SEVERITY::HIGH); - //standard codes used in scan for reply - // static const ReturnValue_t TOO_SHORT = MAKE_RETURN_CODE(0xB1); - static const ReturnValue_t CHECKSUM_ERROR = MAKE_RETURN_CODE(0xB2); - static const ReturnValue_t LENGTH_MISSMATCH = MAKE_RETURN_CODE(0xB3); - static const ReturnValue_t INVALID_DATA = MAKE_RETURN_CODE(0xB4); - static const ReturnValue_t PROTOCOL_ERROR = MAKE_RETURN_CODE(0xB5); + static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_IF; - //standard codes used in interpret device reply - static const ReturnValue_t DEVICE_DID_NOT_EXECUTE = MAKE_RETURN_CODE(0xC1); //the device reported, that it did not execute the command - static const ReturnValue_t DEVICE_REPORTED_ERROR = MAKE_RETURN_CODE(0xC2); - static const ReturnValue_t UNKNOW_DEVICE_REPLY = MAKE_RETURN_CODE(0xC3); //the deviceCommandId reported by scanforReply is unknown - static const ReturnValue_t DEVICE_REPLY_INVALID = MAKE_RETURN_CODE(0xC4); //syntax etc is correct but still not ok, eg parameters where none are expected + // Standard codes used when building commands. + static const ReturnValue_t NO_COMMAND_DATA = MAKE_RETURN_CODE(0xA0); //!< If the command size is 0. Checked in DHB + static const ReturnValue_t COMMAND_NOT_SUPPORTED = MAKE_RETURN_CODE(0xA1); //!< Command ID not in commandMap. Checked in DHB + static const ReturnValue_t COMMAND_ALREADY_SENT = MAKE_RETURN_CODE(0xA2); //!< Command was already executed. Checked in DHB + static const ReturnValue_t COMMAND_WAS_NOT_SENT = MAKE_RETURN_CODE(0xA3); + static const ReturnValue_t CANT_SWITCH_ADDRESS = MAKE_RETURN_CODE(0xA4); + static const ReturnValue_t WRONG_MODE_FOR_COMMAND = MAKE_RETURN_CODE(0xA5); + static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(0xA6); + static const ReturnValue_t BUSY = MAKE_RETURN_CODE(0xA7); + static const ReturnValue_t NO_REPLY_EXPECTED = MAKE_RETURN_CODE(0xA8); //!< Used to indicate that this is a command-only command. + static const ReturnValue_t NON_OP_TEMPERATURE = MAKE_RETURN_CODE(0xA9); + static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xAA); - //Standard codes used in buildCommandFromCommand - static const ReturnValue_t INVALID_COMMAND_PARAMETER = MAKE_RETURN_CODE( - 0xD0); - static const ReturnValue_t INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS = - MAKE_RETURN_CODE(0xD1); + // Standard codes used in scanForReply + static const ReturnValue_t CHECKSUM_ERROR = MAKE_RETURN_CODE(0xB0); + static const ReturnValue_t LENGTH_MISSMATCH = MAKE_RETURN_CODE(0xB1); + static const ReturnValue_t INVALID_DATA = MAKE_RETURN_CODE(0xB2); + static const ReturnValue_t PROTOCOL_ERROR = MAKE_RETURN_CODE(0xB3); + + // Standard codes used in interpretDeviceReply + static const ReturnValue_t DEVICE_DID_NOT_EXECUTE = MAKE_RETURN_CODE(0xC0); //the device reported, that it did not execute the command + static const ReturnValue_t DEVICE_REPORTED_ERROR = MAKE_RETURN_CODE(0xC1); + static const ReturnValue_t UNKNOW_DEVICE_REPLY = MAKE_RETURN_CODE(0xC2); //the deviceCommandId reported by scanforReply is unknown + static const ReturnValue_t DEVICE_REPLY_INVALID = MAKE_RETURN_CODE(0xC3); //syntax etc is correct but still not ok, eg parameters where none are expected + + // Standard codes used in buildCommandFromCommand + static const ReturnValue_t INVALID_COMMAND_PARAMETER = MAKE_RETURN_CODE(0xD0); + static const ReturnValue_t INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS = MAKE_RETURN_CODE(0xD1); + + /** + * Communication action that will be executed. + * + * This is used by the child class to tell the base class what to do. + */ + enum CommunicationAction_t: uint8_t { + SEND_WRITE,//!< Send write + GET_WRITE, //!< Get write + SEND_READ, //!< Send read + GET_READ, //!< Get read + NOTHING //!< Do nothing. + }; - /** - * RMAP Action that will be executed. - * - * This is used by the child class to tell the base class what to do. - */ - enum RmapAction_t { - SEND_WRITE,//!< RMAP send write - GET_WRITE, //!< RMAP get write - SEND_READ, //!< RMAP send read - GET_READ, //!< RMAP get read - NOTHING //!< Do nothing. - }; /** * Default Destructor */ - virtual ~DeviceHandlerIF() { - - } + virtual ~DeviceHandlerIF() {} /** * This MessageQueue is used to command the device handler. - * - * To command a device handler, a DeviceHandlerCommandMessage can be sent to this Queue. - * The handler replies with a DeviceHandlerCommandMessage containing the DeviceHandlerCommand_t reply. - * * @return the id of the MessageQueue */ virtual MessageQueueId_t getCommandQueue() const = 0; diff --git a/devicehandlers/FixedSequenceSlot.cpp b/devicehandlers/FixedSequenceSlot.cpp index 29e7ee6a..bb97a8e5 100644 --- a/devicehandlers/FixedSequenceSlot.cpp +++ b/devicehandlers/FixedSequenceSlot.cpp @@ -16,6 +16,5 @@ FixedSequenceSlot::FixedSequenceSlot(object_id_t handlerId, uint32_t setTime, handler->setTaskIF(executingTask); } -FixedSequenceSlot::~FixedSequenceSlot() { -} +FixedSequenceSlot::~FixedSequenceSlot() {} diff --git a/devicehandlers/FixedSequenceSlot.h b/devicehandlers/FixedSequenceSlot.h index 5aff0f4f..7868cce3 100644 --- a/devicehandlers/FixedSequenceSlot.h +++ b/devicehandlers/FixedSequenceSlot.h @@ -13,35 +13,47 @@ class PeriodicTaskIF; /** - * \brief This class is the representation of a single polling sequence table entry. + * @brief This class is the representation of a single polling sequence table entry. * - * \details The PollingSlot class is the representation of a single polling sequence table entry. + * @details The PollingSlot class is the representation of a single polling + * sequence table entry. */ class FixedSequenceSlot { public: - FixedSequenceSlot( object_id_t handlerId, uint32_t setTimeMs, int8_t setSequenceId, PeriodicTaskIF* executingTask ); + FixedSequenceSlot( object_id_t handlerId, uint32_t setTimeMs, + int8_t setSequenceId, PeriodicTaskIF* executingTask ); virtual ~FixedSequenceSlot(); /** - * \brief \c handler identifies which device handler object is executed in this slot. + * @brief Handler identifies which device handler object is executed in this slot. */ ExecutableObjectIF* handler; /** - * \brief This attribute defines when a device handler object is executed. + * @brief This attribute defines when a device handler object is executed. * - * \details The pollingTime attribute identifies the time the handler is executed in ms. It must be - * smaller than the period length of the polling sequence, what is ensured by automated calculation - * from a database. + * @details The pollingTime attribute identifies the time the handler is executed in ms. + * It must be smaller than the period length of the polling sequence. */ uint32_t pollingTimeMs; /** - * \brief This value defines the type of device communication. + * @brief This value defines the type of device communication. * - * \details The state of this value decides what communication routine is called in the PST executable or the device handler object. + * @details The state of this value decides what communication routine is + * called in the PST executable or the device handler object. */ uint8_t opcode; + + /** + * @brief Operator overload for the comparison operator to + * allow sorting by polling time. + * @param fixedSequenceSlot + * @return + */ + bool operator <(const FixedSequenceSlot & fixedSequenceSlot) const { + return pollingTimeMs < fixedSequenceSlot.pollingTimeMs; + } }; diff --git a/devicehandlers/FixedSlotSequence.cpp b/devicehandlers/FixedSlotSequence.cpp index 2fa13fae..9a0dc372 100644 --- a/devicehandlers/FixedSlotSequence.cpp +++ b/devicehandlers/FixedSlotSequence.cpp @@ -7,17 +7,12 @@ FixedSlotSequence::FixedSlotSequence(uint32_t setLengthMs) : } FixedSlotSequence::~FixedSlotSequence() { - std::list::iterator slotIt; - //Iterate through slotList and delete all entries. - slotIt = this->slotList.begin(); - while (slotIt != this->slotList.end()) { - delete (*slotIt); - slotIt++; - } + // Call the destructor on each list entry. + slotList.clear(); } void FixedSlotSequence::executeAndAdvance() { - (*this->current)->handler->performOperation((*this->current)->opcode); + current->handler->performOperation(current->opcode); // if (returnValue != RETURN_OK) { // this->sendErrorMessage( returnValue ); // } @@ -31,53 +26,50 @@ void FixedSlotSequence::executeAndAdvance() { uint32_t FixedSlotSequence::getIntervalToNextSlotMs() { uint32_t oldTime; - std::list::iterator it; - it = current; + SlotListIter slotListIter = current; // Get the pollingTimeMs of the current slot object. - oldTime = (*it)->pollingTimeMs; + oldTime = slotListIter->pollingTimeMs; // Advance to the next object. - it++; + slotListIter++; // Find the next interval which is not 0. - while (it != slotList.end()) { - if (oldTime != (*it)->pollingTimeMs) { - return (*it)->pollingTimeMs - oldTime; + while (slotListIter != slotList.end()) { + if (oldTime != slotListIter->pollingTimeMs) { + return slotListIter->pollingTimeMs - oldTime; } else { - it++; + slotListIter++; } } // If the list end is reached (this is definitely an interval != 0), // the interval is calculated by subtracting the remaining time of the PST // and adding the start time of the first handler in the list. - it = slotList.begin(); - return lengthMs - oldTime + (*it)->pollingTimeMs; + slotListIter = slotList.begin(); + return lengthMs - oldTime + slotListIter->pollingTimeMs; } uint32_t FixedSlotSequence::getIntervalToPreviousSlotMs() { uint32_t currentTime; - std::list::iterator it; - it = current; + SlotListIter slotListIter = current; // Get the pollingTimeMs of the current slot object. - currentTime = (*it)->pollingTimeMs; + currentTime = slotListIter->pollingTimeMs; //if it is the first slot, calculate difference to last slot - if (it == slotList.begin()){ - return lengthMs - (*(--slotList.end()))->pollingTimeMs + currentTime; + if (slotListIter == slotList.begin()){ + return lengthMs - (--slotList.end())->pollingTimeMs + currentTime; } // get previous slot - it--; + slotListIter--; - return currentTime - (*it)->pollingTimeMs; + return currentTime - slotListIter->pollingTimeMs; } bool FixedSlotSequence::slotFollowsImmediately() { - uint32_t currentTime = (*current)->pollingTimeMs; - std::list::iterator it; - it = this->current; + uint32_t currentTime = current->pollingTimeMs; + SlotListIter fixedSequenceIter = this->current; // Get the pollingTimeMs of the current slot object. - if (it == slotList.begin()) + if (fixedSequenceIter == slotList.begin()) return false; - it--; - if ((*it)->pollingTimeMs == currentTime) { + fixedSequenceIter--; + if (fixedSequenceIter->pollingTimeMs == currentTime) { return true; } else { return false; @@ -93,26 +85,30 @@ ReturnValue_t FixedSlotSequence::checkSequence() const { sif::error << "Fixed Slot Sequence: Slot list is empty!" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } + auto slotIt = slotList.begin(); uint32_t count = 0; uint32_t time = 0; while (slotIt != slotList.end()) { - if ((*slotIt)->handler == NULL) { + if (slotIt->handler == nullptr) { sif::error << "FixedSlotSequene::initialize: ObjectId does not exist!" << std::endl; count++; - } else if ((*slotIt)->pollingTimeMs < time) { + } else if (slotIt->pollingTimeMs < time) { sif::error << "FixedSlotSequence::initialize: Time: " - << (*slotIt)->pollingTimeMs + << slotIt->pollingTimeMs << " is smaller than previous with " << time << std::endl; count++; } else { - //All ok, print slot. -// (*slotIt)->print(); + // All ok, print slot. + //info << "Current slot polling time: " << std::endl; + //info << std::dec << slotIt->pollingTimeMs << std::endl; } - time = (*slotIt)->pollingTimeMs; + time = slotIt->pollingTimeMs; slotIt++; } + //info << "Number of elements in slot list: " + // << slotList.size() << std::endl; if (count > 0) { return HasReturnvaluesIF::RETURN_FAILED; } @@ -121,8 +117,7 @@ ReturnValue_t FixedSlotSequence::checkSequence() const { void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep, PeriodicTaskIF* executingTask) { - this->slotList.push_back( - new FixedSequenceSlot(componentId, slotTimeMs, executionStep, - executingTask)); + this->slotList.insert(FixedSequenceSlot(componentId, slotTimeMs, executionStep, + executingTask)); this->current = slotList.begin(); } diff --git a/devicehandlers/FixedSlotSequence.h b/devicehandlers/FixedSlotSequence.h index 64c68aea..32b61f56 100644 --- a/devicehandlers/FixedSlotSequence.h +++ b/devicehandlers/FixedSlotSequence.h @@ -1,9 +1,9 @@ -#ifndef FIXEDSLOTSEQUENCE_H_ -#define FIXEDSLOTSEQUENCE_H_ +#ifndef FRAMEWORK_DEVICEHANDLERS_FIXEDSLOTSEQUENCE_H_ +#define FRAMEWORK_DEVICEHANDLERS_FIXEDSLOTSEQUENCE_H_ #include #include -#include +#include /** * @brief This class is the representation of a Polling Sequence Table in software. @@ -24,30 +24,39 @@ */ class FixedSlotSequence { public: + using SlotList = std::multiset; + using SlotListIter = std::multiset::iterator; /** - * \brief The constructor of the FixedSlotSequence object. + * @brief The constructor of the FixedSlotSequence object. * - * \details The constructor takes two arguments, the period length and the init function. + * @details The constructor takes two arguments, the period length and the init function. * - * \param setLength The period length, expressed in ms. + * @param setLength The period length, expressed in ms. */ FixedSlotSequence(uint32_t setLengthMs); /** - * \brief The destructor of the FixedSlotSequence object. + * @brief The destructor of the FixedSlotSequence object. * - * \details The destructor frees all allocated memory by iterating through the slotList + * @details The destructor frees all allocated memory by iterating through the slotList * and deleting all allocated resources. */ virtual ~FixedSlotSequence(); /** - * \brief This is a method to add an PollingSlot object to slotList. + * @brief This is a method to add an PollingSlot object to slotList. * - * \details Here, a polling slot object is added to the slot list. It is appended + * @details Here, a polling slot object is added to the slot list. It is appended * to the end of the list. The list is currently NOT reordered. * Afterwards, the iterator current is set to the beginning of the list. + * @param Object ID of the object to add + * @param setTime Value between (0 to 1) * slotLengthMs, when a FixedTimeslotTask + * will be called inside the slot period. + * @param setSequenceId ID which can be used to distinguish + * different task operations + * @param + * @param */ void addSlot(object_id_t handlerId, uint32_t setTime, int8_t setSequenceId, PeriodicTaskIF* executingTask); @@ -61,47 +70,59 @@ public: bool slotFollowsImmediately(); /** - * \brief This method returns the time until the next software component is invoked. + * @brief This method returns the time until the next software + * component is invoked. * - * \details This method is vitally important for the operation of the PST. By fetching the polling time - * of the current slot and that of the next one (or the first one, if the list end is reached) - * it calculates and returns the interval in milliseconds within which the handler execution - * shall take place. If the next slot has the same time as the current one, it is ignored until - * a slot with different time or the end of the PST is found. + * @details + * This method is vitally important for the operation of the PST. + * By fetching the polling time of the current slot and that of the + * next one (or the first one, if the list end is reached) + * it calculates and returns the interval in milliseconds within + * which the handler execution shall take place. + * If the next slot has the same time as the current one, it is ignored + * until a slot with different time or the end of the PST is found. */ uint32_t getIntervalToNextSlotMs(); /** - * \brief This method returns the time difference between the current slot and the previous slot + * @brief This method returns the time difference between the current + * slot and the previous slot * - * \details This method is vitally important for the operation of the PST. By fetching the polling time - * of the current slot and that of the prevous one (or the last one, if the slot is the first one) - * it calculates and returns the interval in milliseconds that the handler execution shall be delayed. + * @details + * This method is vitally important for the operation of the PST. + * By fetching the polling time of the current slot and that of the previous + * one (or the last one, if the slot is the first one) it calculates and + * returns the interval in milliseconds that the handler execution shall + * be delayed. */ uint32_t getIntervalToPreviousSlotMs(); /** - * \brief This method returns the length of this FixedSlotSequence instance. + * @brief This method returns the length of this FixedSlotSequence instance. */ uint32_t getLengthMs() const; /** - * \brief The method to execute the device handler entered in the current OPUSPollingSlot object. + * @brief The method to execute the device handler entered in the current + * PollingSlot object. * - * \details Within this method the device handler object to be executed is chosen by looking up the - * handler address of the current slot in the handlerMap. Either the device handler's - * talkToInterface or its listenToInterface method is invoked, depending on the isTalking flag - * of the polling slot. After execution the iterator current is increased or, by reaching the - * end of slotList, reset to the beginning. + * @details + * Within this method the device handler object to be executed is chosen by + * looking up the handler address of the current slot in the handlerMap. + * Either the device handler's talkToInterface or its listenToInterface + * method is invoked, depending on the isTalking flag of the polling slot. + * After execution the iterator current is increased or, by reaching the + * end of slotList, reset to the beginning. */ void executeAndAdvance(); /** - * \brief An iterator that indicates the current polling slot to execute. + * @brief An iterator that indicates the current polling slot to execute. * - * \details This is an iterator for slotList and always points to the polling slot which is executed next. + * @details This is an iterator for slotList and always points to the + * polling slot which is executed next. */ - std::list::iterator current; + SlotListIter current; /** * Iterate through slotList and check successful creation. @@ -109,18 +130,21 @@ public: * @return */ ReturnValue_t checkSequence() const; + protected: /** - * \brief This list contains all OPUSPollingSlot objects, defining order and execution time of the - * device handler objects. + * @brief This list contains all PollingSlot objects, defining order and + * execution time of the device handler objects. * - * \details The slot list is a std:list object that contains all created OPUSPollingSlot instances. - * They are NOT ordered automatically, so by adding entries, the correct order needs to be ensured. - * By iterating through this list the polling sequence is executed. Two entries with identical - * polling times are executed immediately one after another. + * @details + * The slot list is a std:list object that contains all created + * PollingSlot instances. They are NOT ordered automatically, so by + * adding entries, the correct order needs to be ensured. By iterating + * through this list the polling sequence is executed. Two entries with + * identical polling times are executed immediately one after another. */ - std::list slotList; + SlotList slotList; uint32_t lengthMs; }; diff --git a/osal/FreeRTOS/FixedTimeslotTask.cpp b/osal/FreeRTOS/FixedTimeslotTask.cpp index fb3c3b03..eea2f7d8 100644 --- a/osal/FreeRTOS/FixedTimeslotTask.cpp +++ b/osal/FreeRTOS/FixedTimeslotTask.cpp @@ -82,10 +82,10 @@ ReturnValue_t FixedTimeslotTask::checkSequence() const { void FixedTimeslotTask::taskFunctionality() { // A local iterator for the Polling Sequence Table is created to find the start time for the first entry. - std::list::iterator it = pst.current; + auto slotListIter = pst.current; //The start time for the first entry is read. - uint32_t intervalMs = (*it)->pollingTimeMs; + uint32_t intervalMs = slotListIter->pollingTimeMs; TickType_t interval = pdMS_TO_TICKS(intervalMs); TickType_t xLastWakeTime; @@ -120,4 +120,3 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) { vTaskDelay(pdMS_TO_TICKS(ms)); return HasReturnvaluesIF::RETURN_OK; } - diff --git a/osal/FreeRTOS/FixedTimeslotTask.h b/osal/FreeRTOS/FixedTimeslotTask.h index bed13051..d20b8268 100644 --- a/osal/FreeRTOS/FixedTimeslotTask.h +++ b/osal/FreeRTOS/FixedTimeslotTask.h @@ -5,8 +5,10 @@ #include #include -#include +extern "C" { +#include "FreeRTOS.h" #include "task.h" +} class FixedTimeslotTask: public FixedTimeslotTaskIF { public: diff --git a/returnvalues/FwClassIds.h b/returnvalues/FwClassIds.h index d21861c0..ddee539e 100644 --- a/returnvalues/FwClassIds.h +++ b/returnvalues/FwClassIds.h @@ -24,6 +24,7 @@ enum { MEMORY_HELPER, //MH SERIALIZE_IF, //SE FIXED_MAP, //FM + FIXED_MULTIMAP, //FMM HAS_HEALTH_IF, //HHI FIFO_CLASS, //FF MESSAGE_PROXY, //MQP @@ -54,11 +55,15 @@ enum { HAS_ACTIONS_IF, //HF DEVICE_COMMUNICATION_IF, //DC BSP, //BSP - TIME_STAMPER_IF, //TSI 52 + TIME_STAMPER_IF, //TSI 53 //TODO This will shift all IDs for FLP - SGP4PROPAGATOR_CLASS, //SGP4 53 - MUTEX_IF, //MUX 54 - MESSAGE_QUEUE_IF,//MQI 55 + SGP4PROPAGATOR_CLASS, //SGP4 54 + MUTEX_IF, //MUX 55 + MESSAGE_QUEUE_IF,//MQI 56 + SEMAPHORE_IF, //SPH 57 + LOCAL_POOL_OWNER_IF, //LPIF 58 + POOL_VARIABLE_IF, //PVA 59 + HOUSEKEEPING_MANAGER, //HKM 60 FW_CLASS_ID_COUNT //is actually count + 1 ! }; diff --git a/returnvalues/HasReturnvaluesIF.h b/returnvalues/HasReturnvaluesIF.h index 5adbca3f..d231f4ee 100644 --- a/returnvalues/HasReturnvaluesIF.h +++ b/returnvalues/HasReturnvaluesIF.h @@ -1,27 +1,23 @@ -#ifndef HASRETURNVALUESIF_H_ -#define HASRETURNVALUESIF_H_ +#ifndef FRAMEWORK_RETURNVALUES_HASRETURNVALUESIF_H_ +#define FRAMEWORK_RETURNVALUES_HASRETURNVALUESIF_H_ -#include #include #include +#include #define MAKE_RETURN_CODE( number ) ((INTERFACE_ID << 8) + (number)) typedef uint16_t ReturnValue_t; - - - - class HasReturnvaluesIF { public: static const ReturnValue_t RETURN_OK = 0; static const ReturnValue_t RETURN_FAILED = 1; - virtual ~HasReturnvaluesIF() { - } + virtual ~HasReturnvaluesIF() {} + static ReturnValue_t makeReturnCode(uint8_t interfaceId, uint8_t number) { + return (interfaceId << 8) + number; + } }; - - -#endif /* HASRETURNVALUESIF_H_ */ +#endif /* FRAMEWORK_RETURNVALUES_HASRETURNVALUESIF_H_ */ diff --git a/rmap/RMAPCookie.h b/rmap/RMAPCookie.h index c091ba18..4890c516 100644 --- a/rmap/RMAPCookie.h +++ b/rmap/RMAPCookie.h @@ -1,12 +1,12 @@ #ifndef RMAPCOOKIE_H_ #define RMAPCOOKIE_H_ -#include +#include #include class RMAPChannelIF; -class RMAPCookie : public Cookie{ +class RMAPCookie : public CookieIF { public: //To Uli: Sorry, I need an empty ctor to initialize an array of cookies. RMAPCookie(); diff --git a/rmap/RmapDeviceCommunicationIF.cpp b/rmap/RmapDeviceCommunicationIF.cpp index 4958b3ed..674d050d 100644 --- a/rmap/RmapDeviceCommunicationIF.cpp +++ b/rmap/RmapDeviceCommunicationIF.cpp @@ -5,43 +5,43 @@ RmapDeviceCommunicationIF::~RmapDeviceCommunicationIF() { } -ReturnValue_t RmapDeviceCommunicationIF::sendMessage(Cookie* cookie, +ReturnValue_t RmapDeviceCommunicationIF::sendMessage(CookieIF* cookie, uint8_t* data, uint32_t len) { return RMAP::sendWriteCommand((RMAPCookie *) cookie, data, len); } -ReturnValue_t RmapDeviceCommunicationIF::getSendSuccess(Cookie* cookie) { +ReturnValue_t RmapDeviceCommunicationIF::getSendSuccess(CookieIF* cookie) { return RMAP::getWriteReply((RMAPCookie *) cookie); } ReturnValue_t RmapDeviceCommunicationIF::requestReceiveMessage( - Cookie* cookie) { + CookieIF* cookie) { return RMAP::sendReadCommand((RMAPCookie *) cookie, ((RMAPCookie *) cookie)->getMaxReplyLen()); } -ReturnValue_t RmapDeviceCommunicationIF::readReceivedMessage(Cookie* cookie, +ReturnValue_t RmapDeviceCommunicationIF::readReceivedMessage(CookieIF* cookie, uint8_t** buffer, uint32_t* size) { return RMAP::getReadReply((RMAPCookie *) cookie, buffer, size); } -ReturnValue_t RmapDeviceCommunicationIF::setAddress(Cookie* cookie, +ReturnValue_t RmapDeviceCommunicationIF::setAddress(CookieIF* cookie, uint32_t address) { ((RMAPCookie *) cookie)->setAddress(address); return HasReturnvaluesIF::RETURN_OK; } -uint32_t RmapDeviceCommunicationIF::getAddress(Cookie* cookie) { +uint32_t RmapDeviceCommunicationIF::getAddress(CookieIF* cookie) { return ((RMAPCookie *) cookie)->getAddress(); } -ReturnValue_t RmapDeviceCommunicationIF::setParameter(Cookie* cookie, +ReturnValue_t RmapDeviceCommunicationIF::setParameter(CookieIF* cookie, uint32_t parameter) { //TODO Empty? return HasReturnvaluesIF::RETURN_FAILED; } -uint32_t RmapDeviceCommunicationIF::getParameter(Cookie* cookie) { +uint32_t RmapDeviceCommunicationIF::getParameter(CookieIF* cookie) { return 0; } diff --git a/rmap/RmapDeviceCommunicationIF.h b/rmap/RmapDeviceCommunicationIF.h index 12ae67e4..9d756ea2 100644 --- a/rmap/RmapDeviceCommunicationIF.h +++ b/rmap/RmapDeviceCommunicationIF.h @@ -25,7 +25,7 @@ public: * @param maxReplyLen Maximum length of expected reply * @return */ - virtual ReturnValue_t open(Cookie **cookie, uint32_t address, + virtual ReturnValue_t open(CookieIF **cookie, uint32_t address, uint32_t maxReplyLen) = 0; /** @@ -39,7 +39,7 @@ public: * @param maxReplyLen * @return */ - virtual ReturnValue_t reOpen(Cookie *cookie, uint32_t address, + virtual ReturnValue_t reOpen(CookieIF *cookie, uint32_t address, uint32_t maxReplyLen) = 0; @@ -47,7 +47,7 @@ public: * Closing call of connection and memory free of cookie. Mission dependent call * @param cookie */ - virtual void close(Cookie *cookie) = 0; + virtual void close(CookieIF *cookie) = 0; //SHOULDDO can data be const? /** @@ -58,23 +58,23 @@ public: * @param len Length of the data to be send * @return - Return codes of RMAP::sendWriteCommand() */ - virtual ReturnValue_t sendMessage(Cookie *cookie, uint8_t *data, + virtual ReturnValue_t sendMessage(CookieIF *cookie, uint8_t *data, uint32_t len); - virtual ReturnValue_t getSendSuccess(Cookie *cookie); + virtual ReturnValue_t getSendSuccess(CookieIF *cookie); - virtual ReturnValue_t requestReceiveMessage(Cookie *cookie); + virtual ReturnValue_t requestReceiveMessage(CookieIF *cookie); - virtual ReturnValue_t readReceivedMessage(Cookie *cookie, uint8_t **buffer, + virtual ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer, uint32_t *size); - virtual ReturnValue_t setAddress(Cookie *cookie, uint32_t address); + virtual ReturnValue_t setAddress(CookieIF *cookie, uint32_t address); - virtual uint32_t getAddress(Cookie *cookie); + virtual uint32_t getAddress(CookieIF *cookie); - virtual ReturnValue_t setParameter(Cookie *cookie, uint32_t parameter); + virtual ReturnValue_t setParameter(CookieIF *cookie, uint32_t parameter); - virtual uint32_t getParameter(Cookie *cookie); + virtual uint32_t getParameter(CookieIF *cookie); }; #endif /* MISSION_RMAP_RMAPDEVICECOMMUNICATIONINTERFACE_H_ */