From bfc7a768ce73b1db2a535d7919f24cc1b3244736 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 25 Feb 2020 12:54:28 +0100 Subject: [PATCH] message queue adaptions for calls from ISR functions moved to top binary sempahore file init mutex return values --- ipc/MessageQueueIF.h | 6 +- ipc/MessageQueueSenderIF.h | 4 +- osal/Endiness.h | 4 + osal/FreeRTOS/BinarySemaphore.cpp | 9 +++ osal/FreeRTOS/BinarySempahore.h | 14 ++++ osal/FreeRTOS/MessageQueue.cpp | 90 +++++++++++++++-------- osal/FreeRTOS/MessageQueue.h | 90 +++++++++++++++++------ osal/FreeRTOS/Mutex.cpp | 13 ++-- osal/FreeRTOS/Mutex.h | 6 +- serviceinterface/ServiceInterfaceBuffer.h | 2 +- 10 files changed, 171 insertions(+), 67 deletions(-) create mode 100644 osal/FreeRTOS/BinarySemaphore.cpp create mode 100644 osal/FreeRTOS/BinarySempahore.h diff --git a/ipc/MessageQueueIF.h b/ipc/MessageQueueIF.h index 18e2d99a..ee2479bf 100644 --- a/ipc/MessageQueueIF.h +++ b/ipc/MessageQueueIF.h @@ -3,12 +3,16 @@ // COULDDO: We could support blocking calls +/** + * @defgroup message_queue Message Queue + * @brief Message Queue related software components + */ + #include #include #include class MessageQueueIF { public: - static const MessageQueueId_t NO_QUEUE = MessageQueueSenderIF::NO_QUEUE; //!< Ugly hack. static const uint8_t INTERFACE_ID = CLASS_ID::MESSAGE_QUEUE_IF; diff --git a/ipc/MessageQueueSenderIF.h b/ipc/MessageQueueSenderIF.h index 9e7e11c0..6eb7733d 100644 --- a/ipc/MessageQueueSenderIF.h +++ b/ipc/MessageQueueSenderIF.h @@ -26,8 +26,8 @@ public: * Must be implemented by a subclass. */ static ReturnValue_t sendMessage(MessageQueueId_t sendTo, - MessageQueueMessage* message, MessageQueueId_t sentFrom = - MessageQueueSenderIF::NO_QUEUE, bool ignoreFault=false); + MessageQueueMessage* message, MessageQueueId_t sentFrom = MessageQueueSenderIF::NO_QUEUE, + bool ignoreFault=false); private: MessageQueueSenderIF() {} }; diff --git a/osal/Endiness.h b/osal/Endiness.h index 65cc0a10..55d0aeb3 100644 --- a/osal/Endiness.h +++ b/osal/Endiness.h @@ -1,6 +1,10 @@ #ifndef FRAMEWORK_OSAL_ENDINESS_H_ #define FRAMEWORK_OSAL_ENDINESS_H_ +/** + * @defgroup osal Operating System Abstraction Layer + * @brief Provides clean interfaces to use OS functionalities + */ /* * BSD-style endian declaration diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp new file mode 100644 index 00000000..0422f105 --- /dev/null +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -0,0 +1,9 @@ +/** + * @file BinarySemaphore.cpp + * + * @date 25.02.2020 + */ + + + + diff --git a/osal/FreeRTOS/BinarySempahore.h b/osal/FreeRTOS/BinarySempahore.h new file mode 100644 index 00000000..ab32d7b7 --- /dev/null +++ b/osal/FreeRTOS/BinarySempahore.h @@ -0,0 +1,14 @@ +/** + * @file BinarySempahore.h + * + * @date 25.02.2020 + */ + +#ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ +#define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ + + + + + +#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ diff --git a/osal/FreeRTOS/MessageQueue.cpp b/osal/FreeRTOS/MessageQueue.cpp index 887df392..883cf261 100644 --- a/osal/FreeRTOS/MessageQueue.cpp +++ b/osal/FreeRTOS/MessageQueue.cpp @@ -1,11 +1,13 @@ #include "MessageQueue.h" +#include "task.h" #include // TODO I guess we should have a way of checking if we are in an ISR and then use the "fromISR" versions of all calls - +// As a first step towards this, introduces system context variable which needs to be switched manually +// Haven't found function to find system context. MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) : -defaultDestination(0),lastPartner(0) { +defaultDestination(0),lastPartner(0), callContext(SystemContext::task_context) { handle = xQueueCreate(message_depth, max_message_size); if (handle == NULL) { error << "MessageQueue creation failed" << std::endl; @@ -18,6 +20,10 @@ MessageQueue::~MessageQueue() { } } +void MessageQueue::switchSystemContext(SystemContext callContext) { + this->callContext = callContext; +} + ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessage* message, bool ignoreFault) { return sendMessageFrom(sendTo, message, this->getId(), ignoreFault); @@ -27,6 +33,11 @@ ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message) { return sendToDefaultFrom(message, this->getId()); } +ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessage* message, + MessageQueueId_t sentFrom, bool ignoreFault) { + return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault); +} + ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) { if (this->lastPartner != 0) { return sendMessageFrom(this->lastPartner, message, this->getId()); @@ -35,6 +46,52 @@ ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) { } } +ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, + MessageQueueMessage* message, MessageQueueId_t sentFrom, + bool ignoreFault) { + return sendMessageFromMessageQueue(sendTo,message,sentFrom,ignoreFault, callContext); +} + +ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, + MessageQueueMessage *message, MessageQueueId_t sentFrom, + bool ignoreFault, SystemContext callContext) { + message->setSender(sentFrom); + BaseType_t result; + if(callContext == SystemContext::task_context) { + result = xQueueSendToBack(reinterpret_cast(sendTo), + reinterpret_cast(message->getBuffer()), 0); + } + else { + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + result = xQueueSendFromISR(reinterpret_cast(sendTo), + reinterpret_cast(message->getBuffer()), &xHigherPriorityTaskWoken); + if(xHigherPriorityTaskWoken == pdTRUE) { + requestContextSwitch(callContext); + } + } + return handleSendResult(result, ignoreFault); +} + +void MessageQueue::requestContextSwitch(SystemContext callContext) { + if(callContext == SystemContext::isr_context) { + portYIELD_FROM_ISR(); + } +} + +ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault) { + if (result != pdPASS) { + if (!ignoreFault) { + InternalErrorReporterIF* internalErrorReporter = objectManager->get( + objects::INTERNAL_ERROR_REPORTER); + if (internalErrorReporter != NULL) { + internalErrorReporter->queueMessageNotSent(); + } + } + return MessageQueueIF::FULL; + } + return HasReturnvaluesIF::RETURN_OK; +} + ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message, MessageQueueId_t* receivedFrom) { ReturnValue_t status = this->receiveMessage(message); @@ -73,17 +130,6 @@ void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { this->defaultDestination = defaultDestination; } -ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, - MessageQueueMessage* message, MessageQueueId_t sentFrom, - bool ignoreFault) { - return sendMessageFromMessageQueue(sendTo,message,sentFrom,ignoreFault); -} - -ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessage* message, - MessageQueueId_t sentFrom, bool ignoreFault) { - return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault); -} - MessageQueueId_t MessageQueue::getDefaultDestination() const { return defaultDestination; } @@ -92,23 +138,5 @@ bool MessageQueue::isDefaultDestinationSet() const { return 0; } -ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, - MessageQueueMessage *message, MessageQueueId_t sentFrom, - bool ignoreFault) { - message->setSender(sentFrom); - BaseType_t result = xQueueSendToBack(reinterpret_cast(sendTo),reinterpret_cast(message->getBuffer()), 0); - if (result != pdPASS) { - if (!ignoreFault) { - InternalErrorReporterIF* internalErrorReporter = objectManager->get( - objects::INTERNAL_ERROR_REPORTER); - if (internalErrorReporter != NULL) { - internalErrorReporter->queueMessageNotSent(); - } - } - return MessageQueueIF::FULL; - } - return HasReturnvaluesIF::RETURN_OK; - -} diff --git a/osal/FreeRTOS/MessageQueue.h b/osal/FreeRTOS/MessageQueue.h index 32f41b44..9e2d7790 100644 --- a/osal/FreeRTOS/MessageQueue.h +++ b/osal/FreeRTOS/MessageQueue.h @@ -6,7 +6,8 @@ #include #include -#include +#include "queue.h" +#include "portmacro.h" //TODO this class assumes that MessageQueueId_t is the same size as void* (the FreeRTOS handle type), compiler will catch this but it might be nice to have something checking or even an always working solution // https://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/ @@ -21,11 +22,17 @@ * methods to send a message to a user-defined or a default destination. In addition * it also provides a reply method to answer to the queue it received its last message * from. + * * The MessageQueue should be used as "post box" for a single owning object. So all * message queue communication is "n-to-one". * For creating the queue, as well as sending and receiving messages, the class makes * use of the operating system calls provided. - * \ingroup message_queue + * + * Please keep in mind that FreeRTOS offers + * different calls for message queue operations if called from an ISR. + * For now, the system context needs to be switched manually. + * @ingroup osal + * @ingroup message_queue */ class MessageQueue : public MessageQueueIF { friend class MessageQueueSenderIF; @@ -43,11 +50,30 @@ public: * This should be left default. */ MessageQueue( size_t message_depth = 3, size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE ); + /** * @brief The destructor deletes the formerly created message queue. * @details This is accomplished by using the delete call provided by the operating system. */ virtual ~MessageQueue(); + + /*! + * Used by calling function to tell the callbacks if they are being called from + * within an ISR or from a regular task. This is required because FreeRTOS + * has different functions for handling semaphores from within an ISR and task. + */ + typedef enum _SystemContext { + task_context = 0x00,//!< task_context + isr_context = 0xFF //!< isr_context + } SystemContext; + + /** + * This function is used to specify whether a message queue operation is called + * from within an ISR or a task. FreeRTOS offers different functions for this task. + * @param callContext + */ + void switchSystemContext(SystemContext callContext); + /** * @brief This operation sends a message to the given destination. * @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes its @@ -74,6 +100,29 @@ public: */ ReturnValue_t reply( MessageQueueMessage* message ); + /** + * \brief With the sendMessage call, a queue message is sent to a receiving queue. + * \details This method takes the message provided, adds the sentFrom information and passes + * it on to the destination provided with an operating system call. The OS's return + * value is returned. + * \param sendTo This parameter specifies the message queue id to send the message to. + * \param message This is a pointer to a previously created message, which is sent. + * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. + * This variable is set to zero by default. + * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. + */ + virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, + MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); + + /** + * \brief The sendToDefault method sends a queue message to the default destination. + * \details In all other aspects, it works identical to the sendMessage method. + * \param message This is a pointer to a previously created message, which is sent. + * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. + * This variable is set to zero by default. + */ + virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); + /** * @brief This function reads available messages from the message queue and returns the sender. * @details It works identically to the other receiveMessage call, but in addition returns the @@ -107,26 +156,7 @@ public: * @brief This method returns the message queue id of this class's message queue. */ MessageQueueId_t getId() const; - /** - * \brief With the sendMessage call, a queue message is sent to a receiving queue. - * \details This method takes the message provided, adds the sentFrom information and passes - * it on to the destination provided with an operating system call. The OS's return - * value is returned. - * \param sendTo This parameter specifies the message queue id to send the message to. - * \param message This is a pointer to a previously created message, which is sent. - * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. - * This variable is set to zero by default. - * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. - */ - virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); - /** - * \brief The sendToDefault method sends a queue message to the default destination. - * \details In all other aspects, it works identical to the sendMessage method. - * \param message This is a pointer to a previously created message, which is sent. - * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. - * This variable is set to zero by default. - */ - virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); + /** * \brief This method is a simple setter for the default destination. */ @@ -148,12 +178,26 @@ protected: * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. * This variable is set to zero by default. * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. + * \param context */ - static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo,MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE,bool ignoreFault=false); + static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo, + MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, + bool ignoreFault=false, SystemContext callContex = SystemContext::task_context); + + static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); + + /** + * In this function, a function dependant on the portmacro.h header function calls + * to request a context switch can be specified. + * This can be used if sending to the queue from an ISR caused a task to unblock + * and a context switch is required. + */ + static void requestContextSwitch(SystemContext callContext); private: QueueHandle_t handle; MessageQueueId_t defaultDestination; MessageQueueId_t lastPartner; + SystemContext callContext; //!< Stores the current system context }; #endif /* MESSAGEQUEUE_H_ */ diff --git a/osal/FreeRTOS/Mutex.cpp b/osal/FreeRTOS/Mutex.cpp index 7c511091..456506ea 100644 --- a/osal/FreeRTOS/Mutex.cpp +++ b/osal/FreeRTOS/Mutex.cpp @@ -6,7 +6,9 @@ const uint32_t MutexIF::NO_TIMEOUT = 0; Mutex::Mutex() { handle = xSemaphoreCreateMutex(); - //TODO print error + if(handle == NULL) { + error << "Mutex creation failure" << std::endl; + } } Mutex::~Mutex() { @@ -18,8 +20,7 @@ Mutex::~Mutex() { ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) { if (handle == 0) { - //TODO Does not exist - return HasReturnvaluesIF::RETURN_FAILED; + return MutexIF::MUTEX_NOT_FOUND; } TickType_t timeout = portMAX_DELAY; if (timeoutMs != NO_TIMEOUT) { @@ -30,8 +31,7 @@ ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) { if (returncode == pdPASS) { return HasReturnvaluesIF::RETURN_OK; } else { - //TODO could not be acquired/timeout - return HasReturnvaluesIF::RETURN_FAILED; + return MutexIF::MUTEX_TIMEOUT; } } @@ -44,7 +44,6 @@ ReturnValue_t Mutex::unlockMutex() { if (returncode == pdPASS) { return HasReturnvaluesIF::RETURN_OK; } else { - //TODO is not owner - return HasReturnvaluesIF::RETURN_FAILED; + return MutexIF::CURR_THREAD_DOES_NOT_OWN_MUTEX; } } diff --git a/osal/FreeRTOS/Mutex.h b/osal/FreeRTOS/Mutex.h index 91f29585..471b1113 100644 --- a/osal/FreeRTOS/Mutex.h +++ b/osal/FreeRTOS/Mutex.h @@ -7,8 +7,10 @@ #include #include "semphr.h" - - +/** + * + * @ingroup osal + */ class Mutex : public MutexIF { public: Mutex(); diff --git a/serviceinterface/ServiceInterfaceBuffer.h b/serviceinterface/ServiceInterfaceBuffer.h index 9a5f4ef8..b42c8a19 100644 --- a/serviceinterface/ServiceInterfaceBuffer.h +++ b/serviceinterface/ServiceInterfaceBuffer.h @@ -30,7 +30,7 @@ private: typedef std::char_traits Traits; // Work in buffer mode. It is also possible to work without buffer. - static size_t const BUF_SIZE = 255; + static size_t const BUF_SIZE = 128; char buf[BUF_SIZE]; // In this function, the characters are parsed.