diff --git a/devicehandlers/DeviceHandlerBase.cpp b/devicehandlers/DeviceHandlerBase.cpp index ad699508..8187ffde 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/devicehandlers/DeviceHandlerBase.cpp @@ -332,55 +332,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, uint8_t 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, uint8_t 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) { + std::pair result = deviceReplyMap.emplace(replyId, info); + if (result.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) { + std::pair result = deviceCommandMap.emplace(deviceCommand,info); + if (result.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, uint8_t periodic) { std::map::iterator iter = deviceReplyMap.find(deviceReply); if (iter == deviceReplyMap.end()) { @@ -492,7 +486,7 @@ void DeviceHandlerBase::replyToReply(DeviceReplyMap::iterator iter, return; } //Check if more replies are expected. If so, do nothing. - DeviceCommandInfo* info = &(iter->second.command->second); + DeviceCommandInfo * info = &(iter->second.command->second); if (--info->expectedReplies == 0) { //Check if it was transition or internal command. Don't send any replies in that case. if (info->sendReplyTo != NO_COMMANDER) { @@ -547,10 +541,23 @@ void DeviceHandlerBase::doGetWrite() { void DeviceHandlerBase::doSendRead() { ReturnValue_t result; + + DeviceReplyIter iter = deviceReplyMap.find(cookieInfo.pendingCommand->first); + if(iter != deviceReplyMap.end()) { + requestLen = iter->second.replyLen; + } + else { + requestLen = comCookie->getMaxReplyLen(); + } + result = communicationInterface->requestReceiveMessage(comCookie, requestLen); if (result == RETURN_OK) { cookieInfo.state = COOKIE_READ_SENT; - } else { + } + else if(result == DeviceCommunicationIF::NO_READ_REQUEST) { + return; + } + else { triggerEvent(DEVICE_REQUESTING_REPLY_FAILED, result); //We can't inform anyone, because we don't know which command was sent last. //So, we need to wait for a timeout. @@ -770,8 +777,8 @@ void DeviceHandlerBase::buildRawDeviceCommand(CommandMessage* commandMessage) { replyReturnvalueToCommand(result, RAW_COMMAND_ID); storedRawData.raw = StorageManagerIF::INVALID_ADDRESS; } else { - cookieInfo.pendingCommand = deviceCommandMap.find( - (DeviceCommandId_t) RAW_COMMAND_ID); + cookieInfo.pendingCommand = deviceCommandMap. + find((DeviceCommandId_t) RAW_COMMAND_ID); cookieInfo.pendingCommand->second.isExecuting = true; cookieInfo.state = COOKIE_WRITE_READY; } @@ -810,9 +817,9 @@ ReturnValue_t DeviceHandlerBase::enableReplyInReplyMap( iter = deviceReplyMap.find(command->first); } if (iter != deviceReplyMap.end()) { - DeviceReplyInfo & info = iter->second; - info.delayCycles = info.maxDelayCycles; - info.command = command; + DeviceReplyInfo * info = &(iter->second); + info->delayCycles = info->maxDelayCycles; + info->command = command; command->second.expectedReplies = expectedReplies; return RETURN_OK; } else { diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index dcca2cc4..129fb288 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -194,6 +194,9 @@ protected: * different commands can built returned 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 @@ -275,26 +278,33 @@ protected: * @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, eg checksums lengths and protocol data. + * 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. + * Errors should be reported directly, the base class does NOT report + * any errors based on the returnvalue of this function. * * @param start start of remaining buffer to be scanned * @param len length of remaining buffer to be scanned * @param[out] foundId the id of the data found in the buffer. - * @param[out] foundLen length of the data found. Is to be set in function, buffer is scanned at previous position + foundLen. + * @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, eg checksum error, implies @c foundLen is valid, can be used to skip some bytes + * - @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() ) + * - @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, + virtual ReturnValue_t scanForReply(const uint8_t *start, size_t remainingSize, DeviceCommandId_t *foundId, size_t *foundLen) = 0; /** @@ -513,6 +523,31 @@ protected: */ 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. + uint8_t expectedRepliesWhenEnablingReplyMap; //!< Constant value which specifies expected replies when enabling reply map. Inititated in insertInCommandAndReplyMap() + MessageQueueId_t sendReplyTo; //!< if this is != NO_COMMANDER, DHB was commanded externally and shall report everything to commander. + }; + typedef std::map DeviceCommandMap; + typedef DeviceCommandMap::iterator DeviceCommandIter; + + /** + * @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. + 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. + }; + + typedef std::map DeviceReplyMap; + typedef DeviceReplyMap::iterator DeviceReplyIter; + /** * The MessageQueue used to receive device handler commands and to send replies. */ @@ -643,6 +678,55 @@ protected: */ virtual void doTransition(Mode_t modeFrom, Submode_t subModeFrom); + /** + * This is a helper method to facilitate inserting entries in the command map. + * @param deviceCommand Identifier of the command to add. + * @param maxDelayCycles The maximum number of delay cycles the command waits until it times out. + * @param periodic Indicates if the reply is periodic (i.e. it is sent by the device repeatedly without request) or not. + * Default is aperiodic (0) + * @param hasDifferentReplyId + * @param replyId + * @return RETURN_OK when the command was successfully inserted, COMMAND_MAP_ERROR else. + */ + ReturnValue_t insertInCommandAndReplyMap(DeviceCommandId_t deviceCommand, + uint16_t maxDelayCycles, size_t replyLen = 0, uint8_t periodic = 0, + bool hasDifferentReplyId = false, DeviceCommandId_t replyId = 0); + /** + * This is a helper method to insert replies in the reply map. + * @param deviceCommand Identifier of the reply to add. + * @param maxDelayCycles The maximum number of delay cycles the reply waits until it times out. + * @param periodic Indicates if the command is periodic (i.e. it is sent by the device repeatedly without request) or not. + * Default is aperiodic (0) + * @return RETURN_OK when the command was successfully inserted, COMMAND_MAP_ERROR else. + */ + ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand, + uint16_t maxDelayCycles, size_t replyLen = 0, uint8_t periodic = 0); + /** + * A simple command to add a command to the commandList. + * @param deviceCommand The command to add + * @return RETURN_OK if the command was successfully inserted, RETURN_FAILED else. + */ + ReturnValue_t insertInCommandMap(DeviceCommandId_t deviceCommand); + /** + * This is a helper method to facilitate updating entries in the reply map. + * @param deviceCommand Identifier of the reply to update. + * @param delayCycles The current number of delay cycles to wait. As stated in #fillCommandAndCookieMap, to disable periodic commands, this is set to zero. + * @param maxDelayCycles The maximum number of delay cycles the reply waits until it times out. By passing 0 the entry remains untouched. + * @param periodic Indicates if the command is periodic (i.e. it is sent by the device repeatedly without request) or not. + * Default is aperiodic (0). Warning: The setting always overrides the value that was entered in the map. + * @return RETURN_OK when the reply was successfully updated, COMMAND_MAP_ERROR else. + */ + ReturnValue_t updateReplyMapEntry(DeviceCommandId_t deviceReply, + uint16_t delayCycles, uint16_t maxDelayCycles, + uint8_t periodic = 0); + /** + * Returns the delay cycle count of a reply. + * A count != 0 indicates that the command is already executed. + * @param deviceCommand The command to look for + * @return The current delay count. If the command does not exist (should never happen) it returns 0. + */ + uint8_t getReplyDelayCycles(DeviceCommandId_t deviceCommand); + /** * Is the combination of mode and submode valid? * @@ -684,56 +768,6 @@ protected: */ virtual ReturnValue_t buildChildRawCommand(); - - /** - * This is a helper method to facilitate inserting entries in the command map. - * @param deviceCommand Identifier of the command to add. - * @param maxDelayCycles The maximum number of delay cycles the command waits until it times out. - * @param periodic Indicates if the reply is periodic (i.e. it is sent by the device repeatedly without request) or not. - * Default is aperiodic (0) - * @param hasDifferentReplyId - * @param replyId - * @return RETURN_OK when the command was successfully inserted, COMMAND_MAP_ERROR else. - */ - ReturnValue_t insertInCommandAndReplyMap(DeviceCommandId_t deviceCommand, - uint16_t maxDelayCycles, 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. - * @param deviceCommand The command to look for - * @return The current delay count. If the command does not exist (should never happen) it returns 0. - */ - uint8_t getReplyDelayCycles(DeviceCommandId_t deviceCommand); - /** * Construct a command reply containing a raw reply. * @@ -762,14 +796,6 @@ protected: */ 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. Inititated with 0. - uint8_t expectedRepliesWhenEnablingReplyMap; //!< Constant value which specifies expected replies when enabling reply map. Inititated in insertInCommandAndReplyMap() - 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 * @@ -780,16 +806,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, @@ -884,22 +910,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. * diff --git a/devicehandlers/DeviceHandlerIF.h b/devicehandlers/DeviceHandlerIF.h index 5ea527e9..34aa4114 100644 --- a/devicehandlers/DeviceHandlerIF.h +++ b/devicehandlers/DeviceHandlerIF.h @@ -7,11 +7,6 @@ #include #include -/** - * @brief Physical address type - */ -typedef uint32_t address_t; - /** * @brief This is the Interface used to communicate with a device handler. * @details Includes all expected return values, events and modes.