From e26f0d54b2828e786c4d91ef38345a7e68d1fbcf Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 22 Apr 2020 19:44:03 +0200 Subject: [PATCH 01/94] binary semaphore init --- osal/FreeRTOS/BinarySemaphore.cpp | 152 ++++++++++++++++++++++++++++++ osal/FreeRTOS/BinarySemaphore.h | 130 +++++++++++++++++++++++++ 2 files changed, 282 insertions(+) create mode 100644 osal/FreeRTOS/BinarySemaphore.cpp create mode 100644 osal/FreeRTOS/BinarySemaphore.h diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp new file mode 100644 index 00000000..b5f8e6c6 --- /dev/null +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -0,0 +1,152 @@ +/** + * @file BinarySemaphore.cpp + * + * @date 25.02.2020 + */ +#include +#include + +#include + +extern "C" { +#include "portmacro.h" +#include "task.h" +} + +BinarySemaphore::BinarySemaphore() { + xSemaphoreCreateBinary(handle); + if(handle == nullptr) { + error << "Binary semaphore creation failure" << std::endl; + } +} + +BinarySemaphore::~BinarySemaphore() { + vSemaphoreDelete(handle); +} + +// This copy ctor is important as it prevents the assignment to a ressource +// (other.handle) variable which is later deleted! +BinarySemaphore::BinarySemaphore(const BinarySemaphore& other) { + xSemaphoreCreateBinary(handle); + if(handle == nullptr) { + error << "Binary semaphore creation failure" << std::endl; + } +} + +BinarySemaphore& BinarySemaphore::operator =(const BinarySemaphore& s) { + if(this != &s) { + xSemaphoreCreateBinary(handle); + if(handle == nullptr) { + error << "Binary semaphore creation failure" << std::endl; + } + } + return *this; +} + +BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { + xSemaphoreCreateBinary(handle); + if(handle == nullptr) { + error << "Binary semaphore creation failure" << std::endl; + } +} + +BinarySemaphore& BinarySemaphore::operator =( + BinarySemaphore&& s) { + if(&s != this) { + xSemaphoreCreateBinary(handle); + if(handle == nullptr) { + error << "Binary semaphore creation failure" << std::endl; + } + } + return *this; +} + +ReturnValue_t BinarySemaphore::takeBinarySemaphore(uint32_t timeoutMs) { + if(handle == nullptr) { + return SEMAPHORE_NULLPOINTER; + } + TickType_t timeout = BinarySemaphore::NO_BLOCK_TICKS; + if(timeoutMs == BinarySemaphore::BLOCK_TIMEOUT) { + timeout = BinarySemaphore::BLOCK_TIMEOUT_TICKS; + } + else if(timeoutMs > BinarySemaphore::NO_BLOCK_TIMEOUT){ + timeout = pdMS_TO_TICKS(timeoutMs); + } + + BaseType_t returncode = xSemaphoreTake(handle, timeout); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SEMAPHORE_TIMEOUT; + } +} + +ReturnValue_t BinarySemaphore::takeBinarySemaphoreTickTimeout( + TickType_t timeoutTicks) { + if(handle == nullptr) { + return SEMAPHORE_NULLPOINTER; + } + + BaseType_t returncode = xSemaphoreTake(handle, timeoutTicks); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } else { + return SEMAPHORE_TIMEOUT; + } +} + +ReturnValue_t BinarySemaphore::giveBinarySemaphore() { + if (handle == nullptr) { + return SEMAPHORE_NULLPOINTER; + } + BaseType_t returncode = xSemaphoreGive(handle); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } else { + return SEMAPHORE_NOT_OWNED; + } +} + +SemaphoreHandle_t BinarySemaphore::getSemaphore() { + return handle; +} + +ReturnValue_t BinarySemaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) { + if (semaphore == nullptr) { + return SEMAPHORE_NULLPOINTER; + } + BaseType_t returncode = xSemaphoreGive(semaphore); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +void BinarySemaphore::resetSemaphore() { + if(handle != nullptr) { + vSemaphoreDelete(handle); + xSemaphoreCreateBinary(handle); + } +} + + +// Be careful with the stack size here. This is called from an ISR! +ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, + BaseType_t * higherPriorityTaskWoken) { + if (semaphore == nullptr) { + return SEMAPHORE_NULLPOINTER; + } + BaseType_t returncode = xSemaphoreGiveFromISR(semaphore, higherPriorityTaskWoken); + if (returncode == pdPASS) { + if(*higherPriorityTaskWoken == pdPASS) { + // Request context switch because unblocking the semaphore + // caused a high priority task unblock. + TaskManagement::requestContextSwitch(CallContext::isr); + } + return HasReturnvaluesIF::RETURN_OK; + } else { + return SEMAPHORE_NOT_OWNED; + } +} diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h new file mode 100644 index 00000000..2203c923 --- /dev/null +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -0,0 +1,130 @@ +/** + * @file BinarySempahore.h + * + * @date 25.02.2020 + */ +#ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ +#define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ + +#include + +extern "C" { +#include "FreeRTOS.h" +#include "semphr.h" +} + + +/** + * @brief OS Tool to achieve synchronization of between tasks or between task and ISR + * @details + * Documentation: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html + * @ingroup osal + */ +class BinarySemaphore: public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; + + //! No block time, poll the semaphore. Can also be used as tick type. + //! Can be passed as tick type and ms value. + static constexpr uint32_t NO_BLOCK_TIMEOUT = 0; + static constexpr TickType_t NO_BLOCK_TICKS = 0; + //! No block time, poll the semaphore. + //! Can be passed as tick type and ms value. + static constexpr TickType_t BLOCK_TIMEOUT_TICKS = portMAX_DELAY; + static constexpr uint32_t BLOCK_TIMEOUT = portMAX_DELAY; + + //! Semaphore timeout + static constexpr ReturnValue_t SEMAPHORE_TIMEOUT = MAKE_RETURN_CODE(1); + /** The current semaphore can not be given, because it is not owned */ + static constexpr ReturnValue_t SEMAPHORE_NOT_OWNED = MAKE_RETURN_CODE(2); + static constexpr ReturnValue_t SEMAPHORE_NULLPOINTER = MAKE_RETURN_CODE(3); + + BinarySemaphore(); + + /** + * @brief Copy ctor + */ + BinarySemaphore(const BinarySemaphore&); + + /** + * @brief Copy assignment + */ + BinarySemaphore& operator=(const BinarySemaphore&); + + /** + * @brief Move constructor + */ + BinarySemaphore (BinarySemaphore &&); + + /** + * Move assignment + */ + BinarySemaphore & operator=(BinarySemaphore &&); + + /** + * Delete the binary semaphore to prevent a memory leak + */ + virtual ~BinarySemaphore(); + + /** + * Take the binary semaphore. + * If the semaphore has already been taken, the task will be blocked for a maximum + * of #timeoutMs or until the semaphore is given back, + * for example by an ISR or another task. + * @param timeoutMs + * @return -@c RETURN_OK on success + * -@c RETURN_FAILED on failure + */ + ReturnValue_t takeBinarySemaphore(uint32_t timeoutMs = + BinarySemaphore::NO_BLOCK_TIMEOUT); + + /** + * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. + * @param timeoutTicks + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + ReturnValue_t takeBinarySemaphoreTickTimeout(TickType_t timeoutTicks = + BinarySemaphore::NO_BLOCK_TICKS); + + /** + * Give back the binary semaphore + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + ReturnValue_t giveBinarySemaphore(); + + /** + * Get Handle to the semaphore. + * @return + */ + SemaphoreHandle_t getSemaphore(); + + /** + * Reset the semaphore. + */ + void resetSemaphore(); + + /** + * Wrapper function to give back semaphore from handle + * @param semaphore + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + static ReturnValue_t giveBinarySemaphore(SemaphoreHandle_t semaphore); + + /** + * Wrapper function to give back semaphore from handle when called from an ISR + * @param semaphore + * @param higherPriorityTaskWoken This will be set to pdPASS if a task with a higher priority + * was unblocked + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + static ReturnValue_t giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, + BaseType_t * higherPriorityTaskWoken); +private: + SemaphoreHandle_t handle; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ From 6eda5a08381891907d67e3b23a93e80808585b07 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 22 Apr 2020 19:46:49 +0200 Subject: [PATCH 02/94] task management header added --- osal/FreeRTOS/TaskManagement.h | 38 ++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 osal/FreeRTOS/TaskManagement.h diff --git a/osal/FreeRTOS/TaskManagement.h b/osal/FreeRTOS/TaskManagement.h new file mode 100644 index 00000000..fd2bfc0b --- /dev/null +++ b/osal/FreeRTOS/TaskManagement.h @@ -0,0 +1,38 @@ +/** + * @file TaskManagement.h + * + * @date 26.02.2020 + */ + +#ifndef FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ +#define FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ + +/*! + * Used by functions to tell 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 and messages from within an ISR and task. + */ + +enum CallContext { + task = 0x00,//!< task_context + isr = 0xFF //!< isr_context +}; + +class TaskManagement { +public: + /** + * 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(CallContext callContext); + + /** + * If task preemption in FreeRTOS is disabled, a context switch + * can be requested manually by calling this function. + */ + static void requestContextSwitchFromTask(void); +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ */ From 1b5127dc85f236d7e02cdb22c722bea4976d531b Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 22 Apr 2020 19:50:07 +0200 Subject: [PATCH 03/94] added task management implementation --- osal/FreeRTOS/TaskManagement.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 osal/FreeRTOS/TaskManagement.cpp diff --git a/osal/FreeRTOS/TaskManagement.cpp b/osal/FreeRTOS/TaskManagement.cpp new file mode 100644 index 00000000..9946833d --- /dev/null +++ b/osal/FreeRTOS/TaskManagement.cpp @@ -0,0 +1,32 @@ +/** + * @file TaskManagement.cpp + * + * @date 26.02.2020 + * + */ +#include +#include +#include "portmacro.h" +#include "task.h" + +/** + * TODO: This stuff is hardware and architecture and mission dependant... + * Some FreeRTOS implementations might be able to determine their own task context for example. + * If not ISRs are used, or task preemption is enabled, some of this stuff might + * not be necessary anyway. Maybe there is a better solution? + */ +void TaskManagement::requestContextSwitchFromTask() { + vTaskDelay(0); +} + +void TaskManagement::requestContextSwitch(CallContext callContext = CallContext::task) { + if(callContext == CallContext::isr) { + // This function depends on the partmacro.h definition for the specific device + portYIELD_FROM_ISR(); + } else { + requestContextSwitchFromTask(); + } +} + + + From 0e6f8d3f821d3fa6907de2310e9102a33d30afb2 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 22 Apr 2020 19:53:06 +0200 Subject: [PATCH 04/94] comment adapted --- osal/FreeRTOS/TaskManagement.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/osal/FreeRTOS/TaskManagement.cpp b/osal/FreeRTOS/TaskManagement.cpp index 9946833d..0c96c62f 100644 --- a/osal/FreeRTOS/TaskManagement.cpp +++ b/osal/FreeRTOS/TaskManagement.cpp @@ -5,15 +5,17 @@ * */ #include -#include + +extern "C" { +#include "FreeRTOS.h" #include "portmacro.h" #include "task.h" +} /** * TODO: This stuff is hardware and architecture and mission dependant... - * Some FreeRTOS implementations might be able to determine their own task context for example. - * If not ISRs are used, or task preemption is enabled, some of this stuff might - * not be necessary anyway. Maybe there is a better solution? + * Maybe there is a better solution? The request ContextSwitch function + * could be declared external for example. */ void TaskManagement::requestContextSwitchFromTask() { vTaskDelay(0); From 328737d0ad5d6efb098963fdf0e5088776f50f64 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Thu, 23 Apr 2020 18:12:02 +0200 Subject: [PATCH 05/94] newer non-deprecated semaphore call used --- osal/FreeRTOS/BinarySemaphore.cpp | 24 +++++++++++++----------- osal/FreeRTOS/BinarySemaphore.h | 8 ++++++-- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index b5f8e6c6..a6a923aa 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -8,16 +8,13 @@ #include -extern "C" { -#include "portmacro.h" -#include "task.h" -} - BinarySemaphore::BinarySemaphore() { - xSemaphoreCreateBinary(handle); + handle = xSemaphoreCreateBinary(); if(handle == nullptr) { + error << "Binary semaphore creation failure" << std::endl; } + xSemaphoreGive(handle); } BinarySemaphore::~BinarySemaphore() { @@ -27,36 +24,40 @@ BinarySemaphore::~BinarySemaphore() { // This copy ctor is important as it prevents the assignment to a ressource // (other.handle) variable which is later deleted! BinarySemaphore::BinarySemaphore(const BinarySemaphore& other) { - xSemaphoreCreateBinary(handle); + handle = xSemaphoreCreateBinary(); if(handle == nullptr) { error << "Binary semaphore creation failure" << std::endl; } + xSemaphoreGive(handle); } BinarySemaphore& BinarySemaphore::operator =(const BinarySemaphore& s) { if(this != &s) { - xSemaphoreCreateBinary(handle); + handle = xSemaphoreCreateBinary(); if(handle == nullptr) { error << "Binary semaphore creation failure" << std::endl; } + xSemaphoreGive(handle); } return *this; } BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { - xSemaphoreCreateBinary(handle); + handle = xSemaphoreCreateBinary(); if(handle == nullptr) { error << "Binary semaphore creation failure" << std::endl; } + xSemaphoreGive(handle); } BinarySemaphore& BinarySemaphore::operator =( BinarySemaphore&& s) { if(&s != this) { - xSemaphoreCreateBinary(handle); + handle = xSemaphoreCreateBinary(); if(handle == nullptr) { error << "Binary semaphore creation failure" << std::endl; } + xSemaphoreGive(handle); } return *this; } @@ -127,7 +128,8 @@ ReturnValue_t BinarySemaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) void BinarySemaphore::resetSemaphore() { if(handle != nullptr) { vSemaphoreDelete(handle); - xSemaphoreCreateBinary(handle); + handle = xSemaphoreCreateBinary(); + xSemaphoreGive(handle); } } diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 2203c923..0ab9cdea 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -18,6 +18,10 @@ extern "C" { * @brief OS Tool to achieve synchronization of between tasks or between task and ISR * @details * Documentation: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html + * + * SHOULDDO: check freeRTOS version and use new task notifications, + * if non-ancient freeRTOS version is used. + * * @ingroup osal */ class BinarySemaphore: public HasReturnvaluesIF { @@ -68,8 +72,8 @@ public: /** * Take the binary semaphore. - * If the semaphore has already been taken, the task will be blocked for a maximum - * of #timeoutMs or until the semaphore is given back, + * If the semaphore has already been taken, the task will be blocked + * for a maximum of #timeoutMs or until the semaphore is given back, * for example by an ISR or another task. * @param timeoutMs * @return -@c RETURN_OK on success From fc4199c3b12dfc6f7996d75c035fb0767c21a004 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Thu, 23 Apr 2020 18:13:14 +0200 Subject: [PATCH 06/94] architecture dependant call delcared external --- osal/FreeRTOS/TaskManagement.cpp | 8 +------- osal/FreeRTOS/TaskManagement.h | 7 +++++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/osal/FreeRTOS/TaskManagement.cpp b/osal/FreeRTOS/TaskManagement.cpp index 0c96c62f..d7ddaf38 100644 --- a/osal/FreeRTOS/TaskManagement.cpp +++ b/osal/FreeRTOS/TaskManagement.cpp @@ -8,15 +8,9 @@ extern "C" { #include "FreeRTOS.h" -#include "portmacro.h" #include "task.h" } -/** - * TODO: This stuff is hardware and architecture and mission dependant... - * Maybe there is a better solution? The request ContextSwitch function - * could be declared external for example. - */ void TaskManagement::requestContextSwitchFromTask() { vTaskDelay(0); } @@ -24,7 +18,7 @@ void TaskManagement::requestContextSwitchFromTask() { void TaskManagement::requestContextSwitch(CallContext callContext = CallContext::task) { if(callContext == CallContext::isr) { // This function depends on the partmacro.h definition for the specific device - portYIELD_FROM_ISR(); + requestContextSwitchFromISR(); } else { requestContextSwitchFromTask(); } diff --git a/osal/FreeRTOS/TaskManagement.h b/osal/FreeRTOS/TaskManagement.h index fd2bfc0b..c122e0fb 100644 --- a/osal/FreeRTOS/TaskManagement.h +++ b/osal/FreeRTOS/TaskManagement.h @@ -7,6 +7,12 @@ #ifndef FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ #define FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ +/** + * Architecture dependant portmacro.h function call. + * Should be implemented in bsp. + */ +extern "C" void requestContextSwitchFromISR(); + /*! * Used by functions to tell if they are being called from * within an ISR or from a regular task. This is required because FreeRTOS @@ -18,6 +24,7 @@ enum CallContext { isr = 0xFF //!< isr_context }; + class TaskManagement { public: /** From f2945f873fd1908f572650913f41a3175bf8c451 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 8 May 2020 14:17:27 +0200 Subject: [PATCH 07/94] additional access function for mode message --- modes/ModeMessage.cpp | 4 ++++ modes/ModeMessage.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/modes/ModeMessage.cpp b/modes/ModeMessage.cpp index 62fea7e4..1d3baad5 100644 --- a/modes/ModeMessage.cpp +++ b/modes/ModeMessage.cpp @@ -16,6 +16,10 @@ ReturnValue_t ModeMessage::setModeMessage(CommandMessage* message, Command_t com return HasReturnvaluesIF::RETURN_OK; } +ReturnValue_t ModeMessage::getCantReachModeReason(const CommandMessage* message) { + return message->getParameter(); +} + void ModeMessage::clear(CommandMessage* message) { message->setCommand(CommandMessage::CMD_NONE); } diff --git a/modes/ModeMessage.h b/modes/ModeMessage.h index fad34726..0a72aee0 100644 --- a/modes/ModeMessage.h +++ b/modes/ModeMessage.h @@ -24,6 +24,7 @@ public: static const Command_t REPLY_MODE_INFO = MAKE_COMMAND_ID(0x03); //!> Unrequested info about the current mode (used for composites to inform their container of a changed mode) static const Command_t REPLY_CANT_REACH_MODE = MAKE_COMMAND_ID(0x04); //!> Reply in case a mode command can't be executed. Par1: returnCode, Par2: 0 //SHOULDDO is there a way we can transmit a returnvalue when responding that the mode is wrong, so we can give a nice failure code when commanded by PUS? + // shouldn't that possible with parameter 2 when submode only takes 1 byte? static const Command_t REPLY_WRONG_MODE_REPLY = MAKE_COMMAND_ID(0x05);//!> Reply to a CMD_MODE_COMMAND, indicating that a mode was commanded and a transition started but was aborted; the parameters contain the mode that was reached static const Command_t CMD_MODE_READ = MAKE_COMMAND_ID(0x06);//!> Command to read the current mode and reply with a REPLY_MODE_REPLY static const Command_t CMD_MODE_ANNOUNCE = MAKE_COMMAND_ID(0x07);//!> Command to trigger an ModeInfo Event. This command does NOT have a reply. @@ -34,6 +35,7 @@ public: static ReturnValue_t setModeMessage(CommandMessage* message, Command_t command, Mode_t mode, Submode_t submode); static void cantReachMode(CommandMessage* message, ReturnValue_t reason); + static ReturnValue_t getCantReachModeReason(const CommandMessage* message); static void clear(CommandMessage* message); }; From 26763b7cee17b470a44de92301cfed17fd330b49 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 13 May 2020 11:24:17 +0200 Subject: [PATCH 08/94] added comparison operator --- storagemanager/StorageManagerIF.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/storagemanager/StorageManagerIF.h b/storagemanager/StorageManagerIF.h index 575e9caa..a0c2b23d 100644 --- a/storagemanager/StorageManagerIF.h +++ b/storagemanager/StorageManagerIF.h @@ -48,6 +48,10 @@ union store_address_t { * Alternative access to the raw value. */ uint32_t raw; + + bool operator==(const store_address_t& other) const { + return raw == other.raw; + } }; /** From cbfa21d45a51bbe97d6d35a6b54ab8f409a8f2d1 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sun, 17 May 2020 01:17:11 +0200 Subject: [PATCH 09/94] merging renaming into main branch --- datapool/ControllerSet.h | 4 +- datapool/DataPool.cpp | 132 ------ datapool/DataPool.h | 136 ------ datapool/DataSet.cpp | 150 ------ datapool/DataSet.h | 168 ------- datapool/DataSetIF.h | 39 +- datapool/HkSwitchHelper.cpp | 1 - datapool/PIDReader.h | 8 +- datapool/PoolEntry.cpp | 1 - datapool/PoolEntry.h | 46 +- datapool/PoolEntryIF.h | 61 ++- datapool/PoolRawAccess.cpp | 126 ++--- datapool/PoolRawAccess.h | 172 +++---- datapool/PoolRawAccessHelper.cpp | 6 +- datapool/PoolRawAccessHelper.h | 2 +- datapool/PoolVarList.h | 6 +- datapool/PoolVariableIF.h | 63 ++- {datapool => datapoolglob}/DataPoolAdmin.cpp | 18 +- {datapool => datapoolglob}/DataPoolAdmin.h | 15 +- .../DataPoolParameterWrapper.cpp | 14 +- .../DataPoolParameterWrapper.h | 0 datapoolglob/GlobalDataPool.cpp | 132 ++++++ datapoolglob/GlobalDataPool.h | 146 ++++++ datapoolglob/GlobalDataSet.cpp | 166 +++++++ datapoolglob/GlobalDataSet.h | 185 ++++++++ datapoolglob/GlobalPoolVariable.h | 189 ++++++++ datapoolglob/GlobalPoolVariable.tpp | 84 ++++ datapoolglob/GlobalPoolVector.h | 223 +++++++++ datapoollocal/LocalDataSet.cpp | 66 +++ datapoollocal/LocalDataSet.h | 187 ++++++++ datapoollocal/LocalPoolVariable.h | 103 ++++ datapoollocal/LocalPoolVariable.tpp | 109 +++++ devicehandlers/DeviceHandlerBase.cpp | 189 ++++---- devicehandlers/DeviceHandlerBase.h | 439 +++++++++--------- housekeeping/HasHkPoolParametersIF.h | 32 ++ housekeeping/HousekeepingManager.cpp | 50 ++ housekeeping/HousekeepingManager.h | 95 ++++ housekeeping/HousekeepingMessage.cpp | 10 + housekeeping/HousekeepingMessage.h | 87 ++++ internalError/InternalErrorReporter.cpp | 10 +- monitoring/MonitorBase.h | 4 +- power/Fuse.cpp | 2 +- power/Fuse.h | 6 +- power/PowerSensor.h | 6 +- thermal/CoreComponent.cpp | 12 +- thermal/CoreComponent.h | 12 +- thermal/ThermalModule.h | 6 +- 47 files changed, 2465 insertions(+), 1253 deletions(-) delete mode 100644 datapool/DataPool.cpp delete mode 100644 datapool/DataPool.h delete mode 100644 datapool/DataSet.cpp delete mode 100644 datapool/DataSet.h rename {datapool => datapoolglob}/DataPoolAdmin.cpp (96%) rename {datapool => datapoolglob}/DataPoolAdmin.h (90%) rename {datapool => datapoolglob}/DataPoolParameterWrapper.cpp (96%) rename {datapool => datapoolglob}/DataPoolParameterWrapper.h (100%) create mode 100644 datapoolglob/GlobalDataPool.cpp create mode 100644 datapoolglob/GlobalDataPool.h create mode 100644 datapoolglob/GlobalDataSet.cpp create mode 100644 datapoolglob/GlobalDataSet.h create mode 100644 datapoolglob/GlobalPoolVariable.h create mode 100644 datapoolglob/GlobalPoolVariable.tpp create mode 100644 datapoolglob/GlobalPoolVector.h create mode 100644 datapoollocal/LocalDataSet.cpp create mode 100644 datapoollocal/LocalDataSet.h create mode 100644 datapoollocal/LocalPoolVariable.h create mode 100644 datapoollocal/LocalPoolVariable.tpp create mode 100644 housekeeping/HasHkPoolParametersIF.h create mode 100644 housekeeping/HousekeepingManager.cpp create mode 100644 housekeeping/HousekeepingManager.h create mode 100644 housekeeping/HousekeepingMessage.cpp create mode 100644 housekeeping/HousekeepingMessage.h diff --git a/datapool/ControllerSet.h b/datapool/ControllerSet.h index de06bf91..7625c3d1 100644 --- a/datapool/ControllerSet.h +++ b/datapool/ControllerSet.h @@ -1,9 +1,9 @@ #ifndef CONTROLLERSET_H_ #define CONTROLLERSET_H_ -#include +#include -class ControllerSet :public DataSet { +class ControllerSet :public GlobDataSet { public: ControllerSet(); virtual ~ControllerSet(); diff --git a/datapool/DataPool.cpp b/datapool/DataPool.cpp deleted file mode 100644 index c6a1a74e..00000000 --- a/datapool/DataPool.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include -#include -#include - -DataPool::DataPool( void ( *initFunction )( std::map* pool_map ) ) { - mutex = MutexFactory::instance()->createMutex(); - if (initFunction != NULL ) { - initFunction( &this->data_pool ); - } -} - -DataPool::~DataPool() { - MutexFactory::instance()->deleteMutex(mutex); - for ( std::map::iterator it = this->data_pool.begin(); it != this->data_pool.end(); ++it ) { - delete it->second; - } -} - -//The function checks PID, type and array length before returning a copy of the PoolEntry. In failure case, it returns a temp-Entry with size 0 and NULL-ptr. -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t sizeOrPosition ) { - std::map::iterator it = this->data_pool.find( data_pool_id ); - if ( it != this->data_pool.end() ) { - PoolEntry* entry = dynamic_cast< PoolEntry* >( it->second ); - if (entry != NULL ) { - if ( sizeOrPosition <= entry->length ) { - return entry; - } - } - } - return NULL; -} - -PoolEntryIF* DataPool::getRawData( uint32_t data_pool_id ) { - std::map::iterator it = this->data_pool.find( data_pool_id ); - if ( it != this->data_pool.end() ) { - return it->second; - } else { - return NULL; - } -} - -//uint8_t DataPool::getRawData( uint32_t data_pool_id, uint8_t* address, uint16_t* size, uint32_t max_size ) { -// std::map::iterator it = this->data_pool.find( data_pool_id ); -// if ( it != this->data_pool.end() ) { -// if ( it->second->getByteSize() <= max_size ) { -// *size = it->second->getByteSize(); -// memcpy( address, it->second->getRawData(), *size ); -// return DP_SUCCESSFUL; -// } -// } -// *size = 0; -// return DP_FAILURE; -//} - -ReturnValue_t DataPool::freeDataPoolLock() { - ReturnValue_t status = mutex->unlockMutex(); - if ( status != RETURN_OK ) { - sif::error << "DataPool::DataPool: unlock of mutex failed with error code: " << status << std::endl; - } - return status; -} - -ReturnValue_t DataPool::lockDataPool() { - ReturnValue_t status = mutex->lockMutex(MutexIF::NO_TIMEOUT); - if ( status != RETURN_OK ) { - sif::error << "DataPool::DataPool: lock of mutex failed with error code: " << status << std::endl; - } - return status; -} - -void DataPool::print() { - sif::debug << "DataPool contains: " << std::endl; - std::map::iterator dataPoolIt; - dataPoolIt = this->data_pool.begin(); - while( dataPoolIt != this->data_pool.end() ) { - sif::debug << std::hex << dataPoolIt->first << std::dec << " |"; - dataPoolIt->second->print(); - dataPoolIt++; - } -} - -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData(uint32_t data_pool_id, - uint8_t size); -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData(uint32_t data_pool_id, - uint8_t size); - - -uint32_t DataPool::PIDToDataPoolId(uint32_t parameter_id) { - return (parameter_id >> 8) & 0x00FFFFFF; -} - -uint8_t DataPool::PIDToArrayIndex(uint32_t parameter_id) { - return (parameter_id & 0x000000FF); -} - -uint32_t DataPool::poolIdAndPositionToPid(uint32_t poolId, uint8_t index) { - return (poolId << 8) + index; -} - - -//SHOULDDO: Do we need a mutex lock here... I don't think so, as we only check static const values of elements in a list that do not change. -//there is no guarantee in the standard, but it seems to me that the implementation is safe -UM -ReturnValue_t DataPool::getType(uint32_t parameter_id, Type* type) { - std::map::iterator it = this->data_pool.find( PIDToDataPoolId(parameter_id)); - if ( it != this->data_pool.end() ) { - *type = it->second->getType(); - return RETURN_OK; - } else { - *type = Type::UNKNOWN_TYPE; - return RETURN_FAILED; - } -} - -bool DataPool::exists(uint32_t parameterId) { - uint32_t poolId = PIDToDataPoolId(parameterId); - uint32_t index = PIDToArrayIndex(parameterId); - std::map::iterator it = this->data_pool.find( poolId ); - if (it != data_pool.end()) { - if (it->second->getSize() >= index) { - return true; - } - } - return false; -} diff --git a/datapool/DataPool.h b/datapool/DataPool.h deleted file mode 100644 index 857bc3b2..00000000 --- a/datapool/DataPool.h +++ /dev/null @@ -1,136 +0,0 @@ -/** - * \file DataPool.h - * - * \date 10/17/2012 - * \author Bastian Baetz - * - * \brief This file contains the definition of the DataPool class and (temporarily) - * the "extern" definition of the global dataPool instance. - */ - -#ifndef DATAPOOL_H_ -#define DATAPOOL_H_ - -#include -#include -#include -#include - -/** - * \defgroup data_pool Data Pool - * This is the group, where all classes associated with Data Pool Handling belong to. - * This includes classes to access Data Pool variables. - */ - -#define DP_SUCCESSFUL 0 -#define DP_FAILURE 1 - -/** - * \brief This class represents the OBSW global data-pool. - * - * \details All variables are registered and space is allocated in an initialization - * function, which is passed to the constructor. - * Space for the variables is allocated on the heap (with a new call). - * The data is found by a data pool id, which uniquely represents a variable. - * Data pool variables should be used with a blackboard logic in mind, - * which means read data is valid (if flagged so), but not necessarily up-to-date. - * Variables are either single values or arrays. - * \ingroup data_pool - */ -class DataPool : public HasReturnvaluesIF { -private: - /** - * \brief This is the actual data pool itself. - * \details It is represented by a map - * with the data pool id as index and a pointer to a single - * PoolEntry as value. - */ - std::map data_pool; -public: - /** - * \brief The mutex is created in the constructor and makes access mutual exclusive. - * \details Locking and unlocking the pool is only done by the DataSet class. - */ - MutexIF* mutex; - /** - * \brief In the classes constructor, the passed initialization function is called. - * \details To enable filling the pool, - * a pointer to the map is passed, allowing direct access to the pool's content. - * On runtime, adding or removing variables is forbidden. - */ - DataPool( void ( *initFunction )( std::map* pool_map ) ); - /** - * \brief The destructor iterates through the data_pool map and calls all Entries destructors to clean up the heap. - */ - ~DataPool(); - /** - * \brief This is the default call to access the pool. - * \details A pointer to the PoolEntry object is returned. - * The call checks data pool id, type and array size. Returns NULL in case of failure. - * \param data_pool_id The data pool id to search. - * \param sizeOrPosition The array size (not byte size!) of the pool entry, or the position the user wants to read. - * If smaller than the entry size, everything's ok. - */ - template PoolEntry* getData( uint32_t data_pool_id, uint8_t sizeOrPosition ); - /** - * \brief An alternative call to get a data pool entry in case the type is not implicitly known - * (i.e. in Housekeeping Telemetry). - * \details It returns a basic interface and does NOT perform - * a size check. The caller has to assure he does not copy too much data. - * Returns NULL in case the entry is not found. - * \param data_pool_id The data pool id to search. - */ - PoolEntryIF* getRawData( uint32_t data_pool_id ); - /** - * \brief This is a small helper function to facilitate locking the global data pool. - * \details It fetches the pool's mutex id and tries to acquire the mutex. - */ - ReturnValue_t lockDataPool(); - /** - * \brief This is a small helper function to facilitate unlocking the global data pool. - * \details It fetches the pool's mutex id and tries to free the mutex. - */ - ReturnValue_t freeDataPoolLock(); - /** - * \brief The print call is a simple debug method. - * \details It prints the current content of the data pool. - * It iterates through the data_pool map and calls each entry's print() method. - */ - void print(); - /** - * Extracts the data pool id from a SCOS 2000 PID. - * @param parameter_id The passed Parameter ID. - * @return The data pool id as used within the OBSW. - */ - static uint32_t PIDToDataPoolId( uint32_t parameter_id ); - /** - * Extracts an array index out of a SCOS 2000 PID. - * @param parameter_id The passed Parameter ID. - * @return The index of the corresponding data pool entry. - */ - static uint8_t PIDToArrayIndex( uint32_t parameter_id ); - /** - * Retransforms a data pool id and an array index to a SCOS 2000 PID. - */ - static uint32_t poolIdAndPositionToPid( uint32_t poolId, uint8_t index ); - - /** - * Method to return the type of a pool variable. - * @param parameter_id A parameterID (not pool id) of a DP member. - * @param type Returns the type or TYPE::UNKNOWN_TYPE - * @return RETURN_OK if parameter exists, RETURN_FAILED else. - */ - ReturnValue_t getType( uint32_t parameter_id, Type* type ); - - /** - * Method to check if a PID exists. - * Does not lock, as there's no possibility to alter the list that is checked during run-time. - * @param parameterId The PID (not pool id!) of a parameter. - * @return true if exists, false else. - */ - bool exists(uint32_t parameterId); -}; - -//We assume someone globally instantiates a DataPool. -extern DataPool dataPool; -#endif /* DATAPOOL_H_ */ diff --git a/datapool/DataSet.cpp b/datapool/DataSet.cpp deleted file mode 100644 index 30362118..00000000 --- a/datapool/DataSet.cpp +++ /dev/null @@ -1,150 +0,0 @@ -#include -#include - -DataSet::DataSet() : - fill_count(0), state(DATA_SET_UNINITIALISED) { - for (unsigned count = 0; count < DATA_SET_MAX_SIZE; count++) { - registeredVariables[count] = NULL; - } -} - -DataSet::~DataSet() { - //Don't do anything with your variables, they are dead already! (Destructor is already called) -} - -ReturnValue_t DataSet::read() { - ReturnValue_t result = RETURN_OK; - if (state == DATA_SET_UNINITIALISED) { - lockDataPool(); - for (uint16_t count = 0; count < fill_count; count++) { - if (registeredVariables[count]->getReadWriteMode() - != PoolVariableIF::VAR_WRITE - && registeredVariables[count]->getDataPoolId() - != PoolVariableIF::NO_PARAMETER) { - ReturnValue_t status = registeredVariables[count]->read(); - if (status != RETURN_OK) { - result = INVALID_PARAMETER_DEFINITION; - break; - } - } - } - state = DATA_SET_WAS_READ; - freeDataPoolLock(); - } else { - sif::error << "DataSet::read(): Call made in wrong position." << std::endl; - result = SET_WAS_ALREADY_READ; - } - return result; -} - -ReturnValue_t DataSet::commit(uint8_t valid) { - setValid(valid); - return commit(); -} - -ReturnValue_t DataSet::commit() { - if (state == DATA_SET_WAS_READ) { - lockDataPool(); - for (uint16_t count = 0; count < fill_count; count++) { - if (registeredVariables[count]->getReadWriteMode() - != PoolVariableIF::VAR_READ - && registeredVariables[count]->getDataPoolId() - != PoolVariableIF::NO_PARAMETER) { - registeredVariables[count]->commit(); - } - } - state = DATA_SET_UNINITIALISED; - freeDataPoolLock(); - return RETURN_OK; - } else { - ReturnValue_t result = RETURN_OK; - lockDataPool(); - for (uint16_t count = 0; count < fill_count; count++) { - if (registeredVariables[count]->getReadWriteMode() - == PoolVariableIF::VAR_WRITE - && registeredVariables[count]->getDataPoolId() - != PoolVariableIF::NO_PARAMETER) { - registeredVariables[count]->commit(); - } else if (registeredVariables[count]->getDataPoolId() - != PoolVariableIF::NO_PARAMETER) { - if (result != COMMITING_WITHOUT_READING) { - sif::error << - "DataSet::commit(): commit-without-read " - "call made with non write-only variable." << std::endl; - result = COMMITING_WITHOUT_READING; - } - } - } - state = DATA_SET_UNINITIALISED; - freeDataPoolLock(); - return result; - } - -} - -void DataSet::registerVariable(PoolVariableIF* variable) { - if (state == DATA_SET_UNINITIALISED) { - if (variable != NULL) { - if (fill_count < DATA_SET_MAX_SIZE) { - registeredVariables[fill_count] = variable; - fill_count++; - return; - } - } - } - sif::error - << "DataSet::registerVariable: failed. Either NULL, or set is full, or call made in wrong position." - << std::endl; - return; -} - -uint8_t DataSet::freeDataPoolLock() { - return ::dataPool.freeDataPoolLock(); -} - -uint8_t DataSet::lockDataPool() { - return ::dataPool.lockDataPool(); -} - -ReturnValue_t DataSet::serialize(uint8_t** buffer, size_t* size, - const size_t max_size, bool bigEndian) const { - ReturnValue_t result = RETURN_FAILED; - for (uint16_t count = 0; count < fill_count; count++) { - result = registeredVariables[count]->serialize(buffer, size, max_size, - bigEndian); - if (result != RETURN_OK) { - return result; - } - } - return result; -} - -size_t DataSet::getSerializedSize() const { - size_t size = 0; - for (uint16_t count = 0; count < fill_count; count++) { - size += registeredVariables[count]->getSerializedSize(); - } - return size; -} - -void DataSet::setValid(uint8_t valid) { - for (uint16_t count = 0; count < fill_count; count++) { - if (registeredVariables[count]->getReadWriteMode() - != PoolVariableIF::VAR_READ) { - registeredVariables[count]->setValid(valid); - } - } -} - -ReturnValue_t DataSet::deSerialize(const uint8_t** buffer, size_t* size, - bool bigEndian) { - ReturnValue_t result = RETURN_FAILED; - for (uint16_t count = 0; count < fill_count; count++) { - result = registeredVariables[count]->deSerialize(buffer, size, - bigEndian); - if (result != RETURN_OK) { - return result; - } - } - return result; -} diff --git a/datapool/DataSet.h b/datapool/DataSet.h deleted file mode 100644 index 1e34e07c..00000000 --- a/datapool/DataSet.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * \file DataSet.h - * - * \brief This file contains the DataSet class and a small structure called DataSetContent. - * - * \date 10/17/2012 - * - * \author Bastian Baetz - * - */ - -#ifndef DATASET_H_ -#define DATASET_H_ - -#include -#include -#include -#include -#include -#include -#include -/** - * \brief The DataSet class manages a set of locally checked out variables. - * - * \details This class manages a list, where a set of local variables (or pool variables) are - * registered. They are checked-out (i.e. their values are looked up and copied) - * with the read call. After the user finishes working with the pool variables, - * he can write back all variable values to the pool with the commit call. - * The data set manages locking and freeing the data pool, to ensure that all values - * are read and written back at once. - * An internal state manages usage of this class. Variables may only be registered before - * the read call is made, and the commit call only after the read call. - * If pool variables are writable and not committed until destruction of the set, the - * DataSet class automatically sets the valid flag in the data pool to invalid (without) - * changing the variable's value. - * - * \ingroup data_pool - */ -class DataSet: public DataSetIF, public HasReturnvaluesIF, public SerializeIF { - -public: - //SHOULDDO we could use a linked list of datapool variables - static const uint8_t DATA_SET_MAX_SIZE = 63; //!< This definition sets the maximum number of variables to register in one DataSet. - - static const uint8_t INTERFACE_ID = CLASS_ID::DATA_SET_CLASS; - static const ReturnValue_t INVALID_PARAMETER_DEFINITION = - MAKE_RETURN_CODE( 0x01 ); - static const ReturnValue_t SET_WAS_ALREADY_READ = MAKE_RETURN_CODE( 0x02 ); - static const ReturnValue_t COMMITING_WITHOUT_READING = - MAKE_RETURN_CODE(0x03); - - /** - * \brief The constructor simply sets the fill_count to zero and sets the state to "uninitialized". - */ - DataSet(); - /** - * \brief The destructor automatically manages writing the valid information of variables. - * \details In case the data set was read out, but not committed (indicated by state), - * the destructor parses all variables that are still registered to the set. - * For each, the valid flag in the data pool is set to "invalid". - */ - ~DataSet(); - /** - * \brief The read call initializes reading out all registered variables. - * \details It iterates through the list of registered variables and calls all read() - * functions of the registered pool variables (which read out their values from the - * data pool) which are not write-only. In case of an error (e.g. a wrong data type, - * or an invalid data pool id), the operation is aborted and - * \c INVALID_PARAMETER_DEFINITION returned. - * The data pool is locked during the whole read operation and freed afterwards. - * The state changes to "was written" after this operation. - * \return - \c RETURN_OK if all variables were read successfully. - * - \c INVALID_PARAMETER_DEFINITION if PID, size or type of the - * requested variable is invalid. - * - \c SET_WAS_ALREADY_READ if read() is called twice without calling - * commit() in between - */ - ReturnValue_t read(); - /** - * \brief The commit call initializes writing back the registered variables. - * \details It iterates through the list of registered variables and calls - * the commit() method of the remaining registered variables (which write back - * their values to the pool). - * The data pool is locked during the whole commit operation and freed afterwards. - * The state changes to "was committed" after this operation. - * If the set does contain at least one variable which is not write-only commit() - * can only be called after read(). If the set only contains variables which are - * write only, commit() can be called without a preceding read() call. - * \return - \c RETURN_OK if all variables were read successfully. - * - \c COMMITING_WITHOUT_READING if set was not read yet and contains non write-only - * variables - */ - ReturnValue_t commit(void); - /** - * Variant of method above which sets validity of all elements of the set. - * @param valid Validity information from PoolVariableIF. - * \return - \c RETURN_OK if all variables were read successfully. - * - \c COMMITING_WITHOUT_READING if set was not read yet and contains non write-only - * variables - */ - ReturnValue_t commit(uint8_t valid); - /** - * \brief This operation is used to register the local variables in the set. - * \details It copies all required information to the currently - * free space in the registeredVariables list. - */ - void registerVariable(PoolVariableIF* variable); - - /** - * Set the valid information of all variables contained in the set which are not readonly - * - * @param valid Validity information from PoolVariableIF. - */ - void setValid(uint8_t valid); - - /** - * Serialize all registered pool variables into the provided buffer - * @param buffer - * @param size Is incremented by serialized size - * @param max_size - * @param bigEndian - * @return - */ - ReturnValue_t serialize(uint8_t** buffer, size_t* size, - const size_t max_size, bool bigEndian) const; - - virtual size_t getSerializedSize() const; - - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - bool bigEndian); - -private: - /** - * \brief This array represents all pool variables registered in this set. - * \details It has a maximum size of DATA_SET_MAX_SIZE. - */ - PoolVariableIF* registeredVariables[DATA_SET_MAX_SIZE]; - /** - * \brief The fill_count attribute ensures that the variables register in the correct array - * position and that the maximum number of variables is not exceeded. - */ - uint16_t fill_count; - /** - * States of the seet. - */ - enum States { - DATA_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED - DATA_SET_WAS_READ //!< DATA_SET_WAS_READ - }; - /** - * \brief state manages the internal state of the data set, which is important e.g. for the - * behavior on destruction. - */ - States state; - /** - * \brief This is a small helper function to facilitate locking the global data pool. - * \details It makes use of the lockDataPool method offered by the DataPool class. - */ - uint8_t lockDataPool(); - /** - * \brief This is a small helper function to facilitate unlocking the global data pool. - * \details It makes use of the freeDataPoolLock method offered by the DataPool class. - */ - uint8_t freeDataPoolLock(); - -}; - -#endif /* DATASET_H_ */ diff --git a/datapool/DataSetIF.h b/datapool/DataSetIF.h index 7741477d..4e351416 100644 --- a/datapool/DataSetIF.h +++ b/datapool/DataSetIF.h @@ -1,39 +1,36 @@ -/** - * \file DataSetIF.h - * - * \brief This file contains the small interface to access the DataSet class. - * - * \date 10/23/2012 - * - * \author Bastian Baetz - * - */ - #ifndef DATASETIF_H_ #define DATASETIF_H_ +#include class PoolVariableIF; /** - * \brief This class defines a small interface to register on a DataSet. + * @brief This class defines a small interface to register on a DataSet. * - * \details Currently, the only purpose of this interface is to provide a method for locally - * checked-out variables to register on a data set. Still, it may become useful for - * other purposes as well. - * - * \ingroup data_pool + * @details + * Currently, the only purpose of this interface is to provide a + * method for locally checked-out variables to register on a data set. + * Still, it may become useful for other purposes as well. + * @author Bastian Baetz + * @ingroup data_pool */ class DataSetIF { public: /** - * \brief This is an empty virtual destructor, as it is proposed for C++ interfaces. + * @brief This is an empty virtual destructor, + * as it is proposed for C++ interfaces. */ virtual ~DataSetIF() {} + /** - * \brief This operation provides a method to register local data pool variables - * to register in a data set by passing itself to this DataSet operation. + * @brief This operation provides a method to register local data pool + * variables to register in a data set by passing itself + * to this DataSet operation. */ - virtual void registerVariable( PoolVariableIF* variable ) = 0; + virtual ReturnValue_t registerVariable( PoolVariableIF* variable ) = 0; + + virtual ReturnValue_t lockDataPool() = 0; + virtual ReturnValue_t unlockDataPool() = 0; }; #endif /* DATASETIF_H_ */ diff --git a/datapool/HkSwitchHelper.cpp b/datapool/HkSwitchHelper.cpp index caae2146..844fcd90 100644 --- a/datapool/HkSwitchHelper.cpp +++ b/datapool/HkSwitchHelper.cpp @@ -1,5 +1,4 @@ #include -//#include #include HkSwitchHelper::HkSwitchHelper(EventReportingProxyIF* eventProxy) : diff --git a/datapool/PIDReader.h b/datapool/PIDReader.h index 5eb86026..3a815cee 100644 --- a/datapool/PIDReader.h +++ b/datapool/PIDReader.h @@ -1,9 +1,9 @@ #ifndef PIDREADER_H_ #define PIDREADER_H_ -#include #include #include #include +#include #include #include @@ -16,9 +16,9 @@ protected: uint32_t parameterId; uint8_t valid; ReturnValue_t read() { - uint8_t arrayIndex = DataPool::PIDToArrayIndex(parameterId); + uint8_t arrayIndex = GlobalDataPool::PIDToArrayIndex(parameterId); PoolEntry* read_out = ::dataPool.getData( - DataPool::PIDToDataPoolId(parameterId), arrayIndex); + GlobalDataPool::PIDToDataPoolId(parameterId), arrayIndex); if (read_out != NULL) { valid = read_out->valid; value = read_out->address[arrayIndex]; @@ -88,7 +88,7 @@ public: * \brief This operation returns the data pool id of the variable. */ uint32_t getDataPoolId() const { - return DataPool::PIDToDataPoolId(parameterId); + return GlobalDataPool::PIDToDataPoolId(parameterId); } uint32_t getParameterId() const { return parameterId; diff --git a/datapool/PoolEntry.cpp b/datapool/PoolEntry.cpp index e38af775..d07c516d 100644 --- a/datapool/PoolEntry.cpp +++ b/datapool/PoolEntry.cpp @@ -71,7 +71,6 @@ Type PoolEntry::getType() { return PodTypeConversion::type; } -template class PoolEntry; template class PoolEntry; template class PoolEntry; template class PoolEntry; diff --git a/datapool/PoolEntry.h b/datapool/PoolEntry.h index a02c6c60..4971ee45 100644 --- a/datapool/PoolEntry.h +++ b/datapool/PoolEntry.h @@ -6,34 +6,46 @@ #include #include #include +#include /** - * \brief This is a small helper class that defines a single data pool entry. - * - * \details The helper is used to store all information together with the data as a single data pool entry. - * The content's type is defined by the template argument. - * It is prepared for use with plain old data types, - * but may be extended to complex types if necessary. - * It can be initialized with a certain value, size and validity flag. - * It holds a pointer to the real data and offers methods to access this data and to acquire - * additional information (such as validity and array/byte size). - * It is NOT intended to be used outside the DataPool class. - * - * \ingroup data_pool + * @brief This is a small helper class that defines a single data pool entry. + * @details + * The helper is used to store all information together with the data as a + * single data pool entry.The content's type is defined by the template argument. + * It is prepared for use with plain old data types, but may be extended to + * complex types if necessary. It can be initialized with a certain value, + * size and validity flag. It holds a pointer to the real data and offers + * methods to access this data and to acquire additional information + * (such as validity and array/byte size). It is NOT intended to be used + * outside the DataPool class. + * @author Bastian Baetz + * @ingroup data_pool * */ template class PoolEntry : public PoolEntryIF { public: + static_assert(not std::is_same::value, + "Do not use boolean for the PoolEntry type, use uint8_t instead!" + "Warum? Darum :-)"); /** - * \brief In the classe's constructor, space is allocated on the heap and + * @brief In the classe's constructor, space is allocated on the heap and * potential init values are copied to that space. - * \param initValue A pointer to the single value or array that holds the init value. - * With the default value (NULL), the entry is initalized with all 0. - * \param set_length Defines the array length of this entry. - * \param set_valid Sets the initialization flag. It is invalid (0) by default. + * @param initValue Initializer list with values to initialize with + * @param set_length Defines the array length of this entry. + * @param set_valid Sets the initialization flag. It is invalid (0) by default. */ PoolEntry( std::initializer_list initValue = {}, uint8_t set_length = 1, uint8_t set_valid = 0 ); + /** + * @brief In the classe's constructor, space is allocated on the heap and + * potential init values are copied to that space. + * @param initValue A pointer to the single value or array that holds the init value. + * With the default value (NULL), the entry is initalized with all 0. + * @param set_length Defines the array length of this entry. + * @param set_valid Sets the initialization flag. It is invalid (0) by default. + */ PoolEntry( T* initValue = NULL, uint8_t set_length = 1, uint8_t set_valid = 0 ); + /** * \brief The allocated memory for the variable is freed in the destructor. * \details As the data pool is global, this dtor is only called on program exit. diff --git a/datapool/PoolEntryIF.h b/datapool/PoolEntryIF.h index 514e67ef..d24d553a 100644 --- a/datapool/PoolEntryIF.h +++ b/datapool/PoolEntryIF.h @@ -1,66 +1,63 @@ -/** - * \file PoolEntryIF.h - * - * \brief This file holds the class that defines the Interface for Pool Entry elements. - * - * \date 10/18/2012 - * - * \author Bastian Baetz - */ - #ifndef POOLENTRYIF_H_ #define POOLENTRYIF_H_ #include -#include - - +#include /** - * \brief This interface defines the access possibilities to a single data pool entry. - * - * \details The interface provides methods to determine the size and the validity information of a value. - * It also defines a method to receive a pointer to the raw data content. - * It is mainly used by DataPool itself, but also as a return pointer. - * - * \ingroup data_pool - * + * @brief This interface defines the access possibilities to a + * single data pool entry. + * @details + * The interface provides methods to determine the size and the validity + * information of a value. It also defines a method to receive a pointer to + * the raw data content. It is mainly used by DataPool itself, but also as a + * return pointer. + * @author Bastian Baetz + * @ingroup data_pool */ class PoolEntryIF { public: /** - * \brief This is an empty virtual destructor, as it is proposed for C++ interfaces. + * @brief This is an empty virtual destructor, + * as it is proposed for C++ interfaces. */ - virtual ~PoolEntryIF() { - } + virtual ~PoolEntryIF() {} + /** - * \brief getSize returns the array size of the entry. A single variable parameter has size 1. + * @brief getSize returns the array size of the entry. + * A single variable parameter has size 1. */ virtual uint8_t getSize() = 0; + /** - * \brief This operation returns the size in bytes, which is calculated by + * @brief This operation returns the size in bytes, which is calculated by * sizeof(type) * array_size. */ virtual uint16_t getByteSize() = 0; + /** - * \brief This operation returns a the address pointer casted to void*. + * @brief This operation returns a the address pointer casted to void*. */ virtual void* getRawData() = 0; + /** - * \brief This method allows to set the valid information of the pool entry. + * @brief This method allows to set the valid information of the pool entry. */ virtual void setValid(uint8_t isValid) = 0; + /** - * \brief This method allows to set the valid information of the pool entry. + * @brief This method allows to set the valid information of the pool entry. */ virtual uint8_t getValid() = 0; + /** - * \brief This is a debug method that prints all values and the valid information to the screen. - * It prints all array entries in a row. + * @brief This is a debug method that prints all values and the valid + * information to the screen. It prints all array entries in a row. */ virtual void print() = 0; + /** - * Returns the type of the entry. + * @brief Returns the type of the entry. */ virtual Type getType() = 0; }; diff --git a/datapool/PoolRawAccess.cpp b/datapool/PoolRawAccess.cpp index 592f663f..97bdc2b3 100644 --- a/datapool/PoolRawAccess.cpp +++ b/datapool/PoolRawAccess.cpp @@ -1,6 +1,6 @@ -#include #include #include +#include #include #include @@ -14,63 +14,41 @@ PoolRawAccess::PoolRawAccess(uint32_t set_id, uint8_t setArrayEntry, } } -PoolRawAccess::~PoolRawAccess() {} +PoolRawAccess::~PoolRawAccess() { + +} ReturnValue_t PoolRawAccess::read() { - ReturnValue_t result = RETURN_FAILED; PoolEntryIF* read_out = ::dataPool.getRawData(dataPoolId); if (read_out != NULL) { - result = handleReadOut(read_out); - if(result == RETURN_OK) { - return result; - } - } else { - result = READ_ENTRY_NON_EXISTENT; - } - handleReadError(result); - return result; -} - -ReturnValue_t PoolRawAccess::handleReadOut(PoolEntryIF* read_out) { - ReturnValue_t result = RETURN_FAILED; - valid = read_out->getValid(); - if (read_out->getSize() > arrayEntry) { - arraySize = read_out->getSize(); - typeSize = read_out->getByteSize() / read_out->getSize(); - type = read_out->getType(); - if (typeSize <= sizeof(value)) { - uint16_t arrayPosition = arrayEntry * typeSize; - sizeTillEnd = read_out->getByteSize() - arrayPosition; - uint8_t* ptr = &((uint8_t*) read_out->getRawData())[arrayPosition]; - memcpy(value, ptr, typeSize); - return RETURN_OK; + valid = read_out->getValid(); + if (read_out->getSize() > arrayEntry) { + arraySize = read_out->getSize(); + typeSize = read_out->getByteSize() / read_out->getSize(); + type = read_out->getType(); + if (typeSize <= sizeof(value)) { + uint16_t arrayPosition = arrayEntry * typeSize; + sizeTillEnd = read_out->getByteSize() - arrayPosition; + uint8_t* ptr = + &((uint8_t*) read_out->getRawData())[arrayPosition]; + memcpy(value, ptr, typeSize); + return HasReturnvaluesIF::RETURN_OK; + } else { + //Error value type too large. + } } else { - result = READ_TYPE_TOO_LARGE; + //Error index requested too large } } else { - //debug << "PoolRawAccess: Size: " << (int)read_out->getSize() << std::endl; - result = READ_INDEX_TOO_LARGE; + //Error entry does not exist. } - return result; -} - -void PoolRawAccess::handleReadError(ReturnValue_t result) { sif::error << "PoolRawAccess: read of DP Variable 0x" << std::hex << dataPoolId - << std::dec << " failed, "; - if(result == READ_TYPE_TOO_LARGE) { - sif::error << "type too large." << std::endl; - } - else if(result == READ_INDEX_TOO_LARGE) { - sif::error << "index too large." << std::endl; - } - else if(result == READ_ENTRY_NON_EXISTENT) { - sif::error << "entry does not exist." << std::endl; - } - + << std::dec << " failed." << std::endl; valid = INVALID; typeSize = 0; sizeTillEnd = 0; memset(value, 0, sizeof(value)); + return HasReturnvaluesIF::RETURN_FAILED; } ReturnValue_t PoolRawAccess::commit() { @@ -111,32 +89,6 @@ ReturnValue_t PoolRawAccess::getEntryEndianSafe(uint8_t* buffer, return HasReturnvaluesIF::RETURN_OK; } - -ReturnValue_t PoolRawAccess::serialize(uint8_t** buffer, size_t* size, - const size_t max_size, bool bigEndian) const { - if (typeSize + *size <= max_size) { - if (bigEndian) { -#ifndef BYTE_ORDER_SYSTEM -#error BYTE_ORDER_SYSTEM not defined -#elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN - for (uint8_t count = 0; count < typeSize; count++) { - (*buffer)[count] = value[typeSize - count - 1]; - } -#elif BYTE_ORDER_SYSTEM == BIG_ENDIAN - memcpy(*buffer, value, typeSize); -#endif - } else { - memcpy(*buffer, value, typeSize); - } - *size += typeSize; - (*buffer) += typeSize; - return HasReturnvaluesIF::RETURN_OK; - } else { - return SerializeIF::BUFFER_TOO_SHORT; - } -} - - Type PoolRawAccess::getType() { return type; } @@ -193,6 +145,29 @@ uint16_t PoolRawAccess::getSizeTillEnd() const { return sizeTillEnd; } +ReturnValue_t PoolRawAccess::serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { + if (typeSize + *size <= max_size) { + if (bigEndian) { +#ifndef BYTE_ORDER_SYSTEM +#error BYTE_ORDER_SYSTEM not defined +#elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN + for (uint8_t count = 0; count < typeSize; count++) { + (*buffer)[count] = value[typeSize - count - 1]; + } +#elif BYTE_ORDER_SYSTEM == BIG_ENDIAN + memcpy(*buffer, value, typeSize); +#endif + } else { + memcpy(*buffer, value, typeSize); + } + *size += typeSize; + (*buffer) += typeSize; + return HasReturnvaluesIF::RETURN_OK; + } else { + return SerializeIF::BUFFER_TOO_SHORT; + } +} size_t PoolRawAccess::getSerializedSize() const { return typeSize; @@ -200,9 +175,8 @@ size_t PoolRawAccess::getSerializedSize() const { ReturnValue_t PoolRawAccess::deSerialize(const uint8_t** buffer, size_t* size, bool bigEndian) { - // TODO: Needs to be tested!!! if (*size >= typeSize) { - *size -= typeSize; + if (bigEndian) { #ifndef BYTE_ORDER_SYSTEM #error BYTE_ORDER_SYSTEM not defined @@ -213,14 +187,12 @@ ReturnValue_t PoolRawAccess::deSerialize(const uint8_t** buffer, size_t* size, #elif BYTE_ORDER_SYSTEM == BIG_ENDIAN memcpy(value, *buffer, typeSize); #endif - } - else { + } else { memcpy(value, *buffer, typeSize); } *buffer += typeSize; return HasReturnvaluesIF::RETURN_OK; - } - else { + } else { return SerializeIF::STREAM_TOO_SHORT; } } diff --git a/datapool/PoolRawAccess.h b/datapool/PoolRawAccess.h index b491d949..f32aac51 100644 --- a/datapool/PoolRawAccess.h +++ b/datapool/PoolRawAccess.h @@ -6,54 +6,83 @@ #include /** - * @brief This class allows accessing Data Pool variables as raw bytes. - * @details + * This class allows accessing Data Pool variables as raw bytes. * This is necessary to have an access method for HK data, as the PID's alone do not - * provide a type information. Please note that the the raw pool access read() and commit() - * calls are not thread-safe. - * Please supply a data set and use the data set read(), commit() calls for thread-safe - * data pool access. - * @ingroup data_pool + * provide a type information. + * \ingroup data_pool */ -class PoolRawAccess: public PoolVariableIF, HasReturnvaluesIF { +class PoolRawAccess: public PoolVariableIF { +private: + /** + * \brief To access the correct data pool entry on read and commit calls, the data pool id + * is stored. + */ + uint32_t dataPoolId; + /** + * \brief The array entry that is fetched from the data pool. + */ + uint8_t arrayEntry; + /** + * \brief The valid information as it was stored in the data pool is copied to this attribute. + */ + uint8_t valid; + /** + * \brief This value contains the type of the data pool entry. + */ + Type type; + /** + * \brief This value contains the size of the data pool entry in bytes. + */ + uint8_t typeSize; + /** + * The size of the DP array (single values return 1) + */ + uint8_t arraySize; + /** + * The size (in bytes) from the selected entry till the end of this DataPool variable. + */ + uint16_t sizeTillEnd; + /** + * \brief The information whether the class is read-write or read-only is stored here. + */ + ReadWriteMode_t readWriteMode; + static const uint8_t RAW_MAX_SIZE = sizeof(double); +protected: + /** + * \brief This is a call to read the value from the global data pool. + * \details When executed, this operation tries to fetch the pool entry with matching + * data pool id from the global data pool and copies the value and the valid + * information to its local attributes. In case of a failure (wrong type or + * pool id not found), the variable is set to zero and invalid. + * The operation does NOT provide any mutual exclusive protection by itself. + */ + ReturnValue_t read(); + /** + * \brief The commit call writes back the variable's value to the data pool. + * \details It checks type and size, as well as if the variable is writable. If so, + * the value is copied and the valid flag is automatically set to "valid". + * The operation does NOT provide any mutual exclusive protection by itself. + * + */ + ReturnValue_t commit(); public: static const uint8_t INTERFACE_ID = CLASS_ID::POOL_RAW_ACCESS_CLASS; static const ReturnValue_t INCORRECT_SIZE = MAKE_RETURN_CODE(0x01); static const ReturnValue_t DATA_POOL_ACCESS_FAILED = MAKE_RETURN_CODE(0x02); - static const ReturnValue_t READ_TYPE_TOO_LARGE = MAKE_RETURN_CODE(0x03); - static const ReturnValue_t READ_INDEX_TOO_LARGE = MAKE_RETURN_CODE(0x04); - static const ReturnValue_t READ_ENTRY_NON_EXISTENT = MAKE_RETURN_CODE(0x05); - static const uint8_t RAW_MAX_SIZE = sizeof(double); uint8_t value[RAW_MAX_SIZE]; - - /** - * This constructor is used to access a data pool entry with a - * given ID if the target type is not known. A DataSet object is supplied - * and the data pool entry with the given ID is registered to that data set. - * Please note that a pool raw access buffer only has a buffer - * with a size of double. As such, for vector entries which have - * @param data_pool_id Target data pool entry ID - * @param arrayEntry - * @param data_set Dataset to register data pool entry to - * @param setReadWriteMode - * @param registerVectors If set to true, the constructor checks if - * there are multiple vector entries to registers - * and registers all of them recursively into the data_set - * - */ PoolRawAccess(uint32_t data_pool_id, uint8_t arrayEntry, DataSetIF* data_set, ReadWriteMode_t setReadWriteMode = - PoolVariableIF::VAR_READ); + PoolVariableIF::VAR_READ); /** * \brief The classes destructor is empty. If commit() was not called, the local value is * discarded and not written back to the data pool. */ ~PoolRawAccess(); - /** * \brief This operation returns a pointer to the entry fetched. - * \details Return pointer to the buffer containing the raw data - * Size and number of data can be retrieved by other means. + * \details This means, it does not return a pointer to byte "index", but to the start byte of + * array entry "index". Example: If the original data pool array consists of an double + * array of size four, getEntry(1) returns &(this->value[8]). */ uint8_t* getEntry(); /** @@ -71,19 +100,6 @@ public: */ ReturnValue_t getEntryEndianSafe(uint8_t* buffer, uint32_t* size, uint32_t max_size); - - /** - * @brief Serialize raw pool entry into provided buffer directly - * @param buffer Provided buffer. Raw pool data will be copied here - * @param size [out] Increment provided size value by serialized size - * @param max_size Maximum allowed serialization size - * @param bigEndian Specify endianess - * @return - @c RETURN_OK if serialization was successfull - * - @c SerializeIF::BUFFER_TOO_SHORT if range check failed - */ - ReturnValue_t serialize(uint8_t** buffer, size_t* size, - const size_t max_size, bool bigEndian) const; - /** * With this method, the content can be set from a big endian buffer safely. * @param buffer Pointer to the data to set @@ -125,73 +141,13 @@ public: */ uint16_t getSizeTillEnd() const; + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const; + size_t getSerializedSize() const; ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, bool bigEndian); - -protected: - /** - * \brief This is a call to read the value from the global data pool. - * \details When executed, this operation tries to fetch the pool entry with matching - * data pool id from the global data pool and copies the value and the valid - * information to its local attributes. In case of a failure (wrong type or - * pool id not found), the variable is set to zero and invalid. - * The operation does NOT provide any mutual exclusive protection by itself ! - * If reading from the data pool without information about the type is desired, - * initialize the raw pool access by supplying a data set and using the data set - * read function, which calls this read function. - * @return -@c RETURN_OK Read successfull - * -@c READ_TYPE_TOO_LARGE - * -@c READ_INDEX_TOO_LARGE - * -@c READ_ENTRY_NON_EXISTENT - */ - ReturnValue_t read(); - /** - * \brief The commit call writes back the variable's value to the data pool. - * \details It checks type and size, as well as if the variable is writable. If so, - * the value is copied and the valid flag is automatically set to "valid". - * The operation does NOT provide any mutual exclusive protection by itself. - * - */ - ReturnValue_t commit(); - - ReturnValue_t handleReadOut(PoolEntryIF* read_out); - void handleReadError(ReturnValue_t result); -private: - /** - * \brief To access the correct data pool entry on read and commit calls, the data pool id - * is stored. - */ - uint32_t dataPoolId; - /** - * \brief The array entry that is fetched from the data pool. - */ - uint8_t arrayEntry; - /** - * \brief The valid information as it was stored in the data pool is copied to this attribute. - */ - uint8_t valid; - /** - * \brief This value contains the type of the data pool entry. - */ - Type type; - /** - * \brief This value contains the size of the data pool entry type in bytes. - */ - uint8_t typeSize; - /** - * The size of the DP array (single values return 1) - */ - uint8_t arraySize; - /** - * The size (in bytes) from the selected entry till the end of this DataPool variable. - */ - uint16_t sizeTillEnd; - /** - * \brief The information whether the class is read-write or read-only is stored here. - */ - ReadWriteMode_t readWriteMode; }; #endif /* POOLRAWACCESS_H_ */ diff --git a/datapool/PoolRawAccessHelper.cpp b/datapool/PoolRawAccessHelper.cpp index 91d6309f..cf02b20a 100644 --- a/datapool/PoolRawAccessHelper.cpp +++ b/datapool/PoolRawAccessHelper.cpp @@ -9,7 +9,7 @@ #include -#include +#include PoolRawAccessHelper::PoolRawAccessHelper(uint32_t * poolIdBuffer_, uint8_t numberOfParameters_): @@ -97,7 +97,7 @@ ReturnValue_t PoolRawAccessHelper::handlePoolEntrySerialization( // << std::hex << currentPoolId << std::endl; while(not poolEntrySerialized) { - if(counter > DataSet::DATA_SET_MAX_SIZE) { + if(counter > GlobDataSet::DATA_SET_MAX_SIZE) { sif::error << "PoolRawAccessHelper: Config error, " "max. number of possible data set variables exceeded" << std::endl; @@ -105,7 +105,7 @@ ReturnValue_t PoolRawAccessHelper::handlePoolEntrySerialization( } counter ++; - DataSet currentDataSet = DataSet(); + GlobDataSet currentDataSet; //debug << "Current array position: " << (int)arrayPosition << std::endl; PoolRawAccess currentPoolRawAccess(currentPoolId,arrayPosition, ¤tDataSet,PoolVariableIF::VAR_READ); diff --git a/datapool/PoolRawAccessHelper.h b/datapool/PoolRawAccessHelper.h index 61d79731..ab881a5f 100644 --- a/datapool/PoolRawAccessHelper.h +++ b/datapool/PoolRawAccessHelper.h @@ -8,7 +8,7 @@ #define FRAMEWORK_DATAPOOL_POOLRAWACCESSHELPER_H_ #include -#include +#include /** * @brief This helper function simplifies accessing data pool entries diff --git a/datapool/PoolVarList.h b/datapool/PoolVarList.h index 90c9f178..9d6bc461 100644 --- a/datapool/PoolVarList.h +++ b/datapool/PoolVarList.h @@ -1,12 +1,12 @@ #ifndef POOLVARLIST_H_ #define POOLVARLIST_H_ -#include #include +#include template class PoolVarList { private: - PoolVariable variables[n_var]; + GlobPoolVar variables[n_var]; public: PoolVarList( const uint32_t set_id[n_var], DataSetIF* dataSet, PoolVariableIF::ReadWriteMode_t setReadWriteMode ) { //I really should have a look at the new init list c++ syntax. @@ -20,7 +20,7 @@ public: } } - PoolVariable &operator [](int i) { return variables[i]; } + GlobPoolVar &operator [](int i) { return variables[i]; } }; diff --git a/datapool/PoolVariableIF.h b/datapool/PoolVariableIF.h index 7626c9c1..9935ef75 100644 --- a/datapool/PoolVariableIF.h +++ b/datapool/PoolVariableIF.h @@ -1,71 +1,70 @@ -/* - * \file PoolVariableIF.h - * - * \brief This file contains the interface definition for pool variables. - * - * \date 10/17/2012 - * - * \author Bastian Baetz - */ - #ifndef POOLVARIABLEIF_H_ #define POOLVARIABLEIF_H_ #include #include + /** - * \brief This interface is used to control local data pool variable representations. - * - * \details To securely handle data pool variables, all pool entries are locally managed by - * data pool variable access classes, which are called pool variables. To ensure a - * common state of a set of variables needed in a function, these local pool variables - * again are managed by other classes, e.g. the DataSet. This interface provides unified - * access to local pool variables for such manager classes. - * \ingroup data_pool + * @brief This interface is used to control data pool variable representations. + * @details + * To securely handle data pool variables, all pool entries are locally + * managed by data pool variable access classes, which are called pool + * variables. To ensure a common state of a set of variables needed in a + * function, these local pool variables again are managed by other classes, + * like the DataSet classes. This interface provides unified access to + * local pool variables for such manager classes. + * @author Bastian Baetz + * @ingroup data_pool */ class PoolVariableIF : public SerializeIF { - friend class DataSet; + friend class GlobDataSet; + friend class LocalDataSet; protected: /** - * \brief The commit call shall write back a newly calculated local value to the data pool. + * @brief The commit call shall write back a newly calculated local + * value to the data pool. */ virtual ReturnValue_t commit() = 0; /** - * \brief The read call shall read the value of this parameter from the data pool and store - * the content locally. + * @brief The read call shall read the value of this parameter from + * the data pool and store the content locally. */ virtual ReturnValue_t read() = 0; public: - static const uint8_t VALID = 1; - static const uint8_t INVALID = 0; - static const uint32_t NO_PARAMETER = 0; + static constexpr bool VALID = 1; + static constexpr bool INVALID = 0; + static constexpr uint32_t NO_PARAMETER = 0; + enum ReadWriteMode_t { VAR_READ, VAR_WRITE, VAR_READ_WRITE }; /** - * \brief This is an empty virtual destructor, as it is proposed for C++ interfaces. + * @brief This is an empty virtual destructor, + * as it is proposed for C++ interfaces. */ - virtual ~PoolVariableIF() { - } + virtual ~PoolVariableIF() {} /** - * \brief This method returns if the variable is write-only, read-write or read-only. + * @brief This method returns if the variable is write-only, read-write or read-only. */ virtual ReadWriteMode_t getReadWriteMode() const = 0; /** - * \brief This operation shall return the data pool id of the variable. + * @brief This operation shall return the data pool id of the variable. */ virtual uint32_t getDataPoolId() const = 0; /** - * \brief With this call, the valid information of the variable is returned. + * @brief With this call, the valid information of the variable is returned. */ virtual bool isValid() const = 0; /** - * \brief With this call, the valid information of the variable is set. + * @brief With this call, the valid information of the variable is set. */ + // why not just use a boolean here? virtual void setValid(uint8_t validity) = 0; }; +using pool_rwm_t = PoolVariableIF::ReadWriteMode_t; + #endif /* POOLVARIABLEIF_H_ */ diff --git a/datapool/DataPoolAdmin.cpp b/datapoolglob/DataPoolAdmin.cpp similarity index 96% rename from datapool/DataPoolAdmin.cpp rename to datapoolglob/DataPoolAdmin.cpp index 25013726..59bd9f30 100644 --- a/datapool/DataPoolAdmin.cpp +++ b/datapoolglob/DataPoolAdmin.cpp @@ -1,7 +1,5 @@ -#include -#include -#include -#include +#include +#include #include #include #include @@ -26,7 +24,7 @@ MessageQueueId_t DataPoolAdmin::getCommandQueue() const { } ReturnValue_t DataPoolAdmin::executeAction(ActionId_t actionId, - MessageQueueId_t commandedBy, const uint8_t* data, size_t size) { + MessageQueueId_t commandedBy, const uint8_t* data, uint32_t size) { if (actionId != SET_VALIDITY) { return INVALID_ACTION_ID; } @@ -42,7 +40,7 @@ ReturnValue_t DataPoolAdmin::executeAction(ActionId_t actionId, uint32_t poolId = ::dataPool.PIDToDataPoolId(address); - DataSet mySet; + GlobDataSet mySet; PoolRawAccess variable(poolId, 0, &mySet, PoolVariableIF::VAR_READ_WRITE); ReturnValue_t status = mySet.read(); if (status != RETURN_OK) { @@ -94,7 +92,7 @@ ReturnValue_t DataPoolAdmin::handleMemoryLoad(uint32_t address, const uint8_t* data, uint32_t size, uint8_t** dataPointer) { uint32_t poolId = ::dataPool.PIDToDataPoolId(address); uint8_t arrayIndex = ::dataPool.PIDToArrayIndex(address); - DataSet testSet; + GlobDataSet testSet; PoolRawAccess varToGetSize(poolId, arrayIndex, &testSet, PoolVariableIF::VAR_READ); ReturnValue_t status = testSet.read(); @@ -113,7 +111,7 @@ ReturnValue_t DataPoolAdmin::handleMemoryLoad(uint32_t address, const uint8_t* readPosition = data; for (; size > 0; size -= typeSize) { - DataSet rawSet; + GlobDataSet rawSet; PoolRawAccess variable(poolId, arrayIndex, &rawSet, PoolVariableIF::VAR_READ_WRITE); status = rawSet.read(); @@ -133,7 +131,7 @@ ReturnValue_t DataPoolAdmin::handleMemoryDump(uint32_t address, uint32_t size, uint8_t** dataPointer, uint8_t* copyHere) { uint32_t poolId = ::dataPool.PIDToDataPoolId(address); uint8_t arrayIndex = ::dataPool.PIDToArrayIndex(address); - DataSet testSet; + GlobDataSet testSet; PoolRawAccess varToGetSize(poolId, arrayIndex, &testSet, PoolVariableIF::VAR_READ); ReturnValue_t status = testSet.read(); @@ -146,7 +144,7 @@ ReturnValue_t DataPoolAdmin::handleMemoryDump(uint32_t address, uint32_t size, } uint8_t* ptrToCopy = copyHere; for (; size > 0; size -= typeSize) { - DataSet rawSet; + GlobDataSet rawSet; PoolRawAccess variable(poolId, arrayIndex, &rawSet, PoolVariableIF::VAR_READ); status = rawSet.read(); diff --git a/datapool/DataPoolAdmin.h b/datapoolglob/DataPoolAdmin.h similarity index 90% rename from datapool/DataPoolAdmin.h rename to datapoolglob/DataPoolAdmin.h index dffcd462..5f995893 100644 --- a/datapool/DataPoolAdmin.h +++ b/datapoolglob/DataPoolAdmin.h @@ -1,15 +1,16 @@ #ifndef DATAPOOLADMIN_H_ #define DATAPOOLADMIN_H_ -#include -#include -#include #include #include #include -#include -#include +#include #include +#include + +#include +#include +#include class DataPoolAdmin: public HasActionsIF, public ExecutableObjectIF, @@ -33,8 +34,8 @@ public: ReturnValue_t handleMemoryDump(uint32_t address, uint32_t size, uint8_t** dataPointer, uint8_t* copyHere); - virtual ReturnValue_t executeAction(ActionId_t actionId, - MessageQueueId_t commandedBy, const uint8_t* data, size_t size); + ReturnValue_t executeAction(ActionId_t actionId, + MessageQueueId_t commandedBy, const uint8_t* data, uint32_t size); //not implemented as ParameterHelper is no used ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, diff --git a/datapool/DataPoolParameterWrapper.cpp b/datapoolglob/DataPoolParameterWrapper.cpp similarity index 96% rename from datapool/DataPoolParameterWrapper.cpp rename to datapoolglob/DataPoolParameterWrapper.cpp index 11399fb6..d93cd88e 100644 --- a/datapool/DataPoolParameterWrapper.cpp +++ b/datapoolglob/DataPoolParameterWrapper.cpp @@ -1,10 +1,8 @@ -#include "DataPoolParameterWrapper.h" - -//for returncodes +#include +#include +#include #include -#include -#include DataPoolParameterWrapper::DataPoolParameterWrapper() : type(Type::UNKNOWN_TYPE), rows(0), columns(0), poolId( @@ -20,7 +18,7 @@ ReturnValue_t DataPoolParameterWrapper::set(uint8_t domainId, uint16_t parameterId) { poolId = (domainId << 16) + parameterId; - DataSet mySet; + GlobDataSet mySet; PoolRawAccess raw(poolId, 0, &mySet, PoolVariableIF::VAR_READ); ReturnValue_t status = mySet.read(); if (status != HasReturnvaluesIF::RETURN_OK) { @@ -57,7 +55,7 @@ ReturnValue_t DataPoolParameterWrapper::serialize(uint8_t** buffer, } for (uint8_t index = 0; index < rows; index++){ - DataSet mySet; + GlobDataSet mySet; PoolRawAccess raw(poolId, index, &mySet,PoolVariableIF::VAR_READ); mySet.read(); result = raw.serialize(buffer,size,max_size,bigEndian); @@ -94,7 +92,7 @@ ReturnValue_t DataPoolParameterWrapper::deSerializeData(uint8_t startingRow, for (uint8_t fromRow = 0; fromRow < fromRows; fromRow++) { - DataSet mySet; + GlobDataSet mySet; PoolRawAccess raw(poolId, startingRow + fromRow, &mySet, PoolVariableIF::VAR_READ_WRITE); mySet.read(); diff --git a/datapool/DataPoolParameterWrapper.h b/datapoolglob/DataPoolParameterWrapper.h similarity index 100% rename from datapool/DataPoolParameterWrapper.h rename to datapoolglob/DataPoolParameterWrapper.h diff --git a/datapoolglob/GlobalDataPool.cpp b/datapoolglob/GlobalDataPool.cpp new file mode 100644 index 00000000..e13765ba --- /dev/null +++ b/datapoolglob/GlobalDataPool.cpp @@ -0,0 +1,132 @@ +#include +#include +#include + +GlobalDataPool::GlobalDataPool( + void(*initFunction)(GlobPoolMap* pool_map)) { + mutex = MutexFactory::instance()->createMutex(); + if (initFunction != NULL ) { + initFunction( &this->globDataPool ); + } +} + +GlobalDataPool::~GlobalDataPool() { + MutexFactory::instance()->deleteMutex(mutex); + for(GlobPoolMapIter it = this->globDataPool.begin(); + it != this->globDataPool.end(); ++it ) + { + delete it->second; + } +} + +// The function checks PID, type and array length before returning a copy of +// the PoolEntry. In failure case, it returns a temp-Entry with size 0 and NULL-ptr. +template PoolEntry* GlobalDataPool::getData( uint32_t data_pool_id, + uint8_t sizeOrPosition ) { + GlobPoolMapIter it = this->globDataPool.find( data_pool_id ); + if ( it != this->globDataPool.end() ) { + PoolEntry* entry = dynamic_cast< PoolEntry* >( it->second ); + if (entry != nullptr ) { + if ( sizeOrPosition <= entry->length ) { + return entry; + } + } + } + return nullptr; +} + +PoolEntryIF* GlobalDataPool::getRawData( uint32_t data_pool_id ) { + GlobPoolMapIter it = this->globDataPool.find( data_pool_id ); + if ( it != this->globDataPool.end() ) { + return it->second; + } else { + return nullptr; + } +} + +ReturnValue_t GlobalDataPool::freeDataPoolLock() { + ReturnValue_t status = mutex->unlockMutex(); + if ( status != RETURN_OK ) { + sif::error << "DataPool::DataPool: unlock of mutex failed with" + " error code: " << status << std::endl; + } + return status; +} + +ReturnValue_t GlobalDataPool::lockDataPool() { + ReturnValue_t status = mutex->lockMutex(MutexIF::NO_TIMEOUT); + if ( status != RETURN_OK ) { + sif::error << "DataPool::DataPool: lock of mutex failed " + "with error code: " << status << std::endl; + } + return status; +} + +void GlobalDataPool::print() { + sif::debug << "DataPool contains: " << std::endl; + std::map::iterator dataPoolIt; + dataPoolIt = this->globDataPool.begin(); + while( dataPoolIt != this->globDataPool.end() ) { + sif::debug << std::hex << dataPoolIt->first << std::dec << " |"; + dataPoolIt->second->print(); + dataPoolIt++; + } +} + +uint32_t GlobalDataPool::PIDToDataPoolId(uint32_t parameter_id) { + return (parameter_id >> 8) & 0x00FFFFFF; +} + +uint8_t GlobalDataPool::PIDToArrayIndex(uint32_t parameter_id) { + return (parameter_id & 0x000000FF); +} + +uint32_t GlobalDataPool::poolIdAndPositionToPid(uint32_t poolId, uint8_t index) { + return (poolId << 8) + index; +} + + +//SHOULDDO: Do we need a mutex lock here... I don't think so, +//as we only check static const values of elements in a list that do not change. +//there is no guarantee in the standard, but it seems to me that the implementation is safe -UM +ReturnValue_t GlobalDataPool::getType(uint32_t parameter_id, Type* type) { + GlobPoolMapIter it = this->globDataPool.find( PIDToDataPoolId(parameter_id)); + if ( it != this->globDataPool.end() ) { + *type = it->second->getType(); + return RETURN_OK; + } else { + *type = Type::UNKNOWN_TYPE; + return RETURN_FAILED; + } +} + +bool GlobalDataPool::exists(uint32_t parameterId) { + uint32_t poolId = PIDToDataPoolId(parameterId); + uint32_t index = PIDToArrayIndex(parameterId); + GlobPoolMapIter it = this->globDataPool.find( poolId ); + if (it != globDataPool.end()) { + if (it->second->getSize() >= index) { + return true; + } + } + return false; +} + +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size); diff --git a/datapoolglob/GlobalDataPool.h b/datapoolglob/GlobalDataPool.h new file mode 100644 index 00000000..e0c086ad --- /dev/null +++ b/datapoolglob/GlobalDataPool.h @@ -0,0 +1,146 @@ +#ifndef GLOBALDATAPOOL_H_ +#define GLOBALDATAPOOL_H_ + +#include +#include +#include +#include + +/** + * @defgroup data_pool Global data pool + * This is the group, where all classes associated with global + * data pool handling belong to. + * This includes classes to access Data Pool variables. + */ + +/** + * Typedefs for the global pool representations + */ +using GlobPoolMap = std::map; +using GlobPoolMapIter = GlobPoolMap::iterator; + +/** + * @brief This class represents the OBSW global data-pool. + * + * @details + * All variables are registered and space is allocated in an initialization + * function, which is passed do the constructor. Space for the variables is + * allocated on the heap (with a new call). + * + * The data is found by a data pool id, which uniquely represents a variable. + * Data pool variables should be used with a blackboard logic in mind, + * which means read data is valid (if flagged so), + * but not necessarily up-to-date. + * + * Variables are either single values or arrays. + * @author Bastian Baetz + * @ingroup data_pool + */ +class GlobalDataPool : public HasReturnvaluesIF { +private: + /** + * @brief This is the actual data pool itself. + * @details It is represented by a map with the data pool id as index + * and a pointer to a single PoolEntry as value. + */ + GlobPoolMap globDataPool; + + /** + * @brief The mutex is created in the constructor and makes + * access mutual exclusive. + * @details Locking and unlocking the pool is only done by the DataSet class. + */ + MutexIF* mutex; +public: + /** + * @brief In the classes constructor, + * the passed initialization function is called. + * @details + * To enable filling the pool, a pointer to the map is passed, + * allowing direct access to the pool's content. + * On runtime, adding or removing variables is forbidden. + */ + GlobalDataPool( void ( *initFunction )( GlobPoolMap* pool_map ) ); + + /** + * @brief The destructor iterates through the data_pool map and + * calls all entries destructors to clean up the heap. + */ + ~GlobalDataPool(); + + /** + * @brief This is the default call to access the pool. + * @details + * A pointer to the PoolEntry object is returned. + * The call checks data pool id, type and array size. + * Returns NULL in case of failure. + * @param data_pool_id The data pool id to search. + * @param sizeOrPosition The array size (not byte size!) of the pool entry, + * or the position the user wants to read. + * If smaller than the entry size, everything's ok. + */ + template PoolEntry* getData( uint32_t data_pool_id, + uint8_t sizeOrPosition ); + + /** + * @brief An alternative call to get a data pool entry in case the type is not implicitly known + * (i.e. in Housekeeping Telemetry). + * @details It returns a basic interface and does NOT perform + * a size check. The caller has to assure he does not copy too much data. + * Returns NULL in case the entry is not found. + * @param data_pool_id The data pool id to search. + */ + PoolEntryIF* getRawData( uint32_t data_pool_id ); + /** + * @brief This is a small helper function to facilitate locking the global data pool. + * @details It fetches the pool's mutex id and tries to acquire the mutex. + */ + ReturnValue_t lockDataPool(); + /** + * @brief This is a small helper function to facilitate unlocking the global data pool. + * @details It fetches the pool's mutex id and tries to free the mutex. + */ + ReturnValue_t freeDataPoolLock(); + /** + * @brief The print call is a simple debug method. + * @details It prints the current content of the data pool. + * It iterates through the data_pool map and calls each entry's print() method. + */ + void print(); + /** + * Extracts the data pool id from a SCOS 2000 PID. + * @param parameter_id The passed Parameter ID. + * @return The data pool id as used within the OBSW. + */ + static uint32_t PIDToDataPoolId( uint32_t parameter_id ); + /** + * Extracts an array index out of a SCOS 2000 PID. + * @param parameter_id The passed Parameter ID. + * @return The index of the corresponding data pool entry. + */ + static uint8_t PIDToArrayIndex( uint32_t parameter_id ); + /** + * Retransforms a data pool id and an array index to a SCOS 2000 PID. + */ + static uint32_t poolIdAndPositionToPid( uint32_t poolId, uint8_t index ); + + /** + * Method to return the type of a pool variable. + * @param parameter_id A parameterID (not pool id) of a DP member. + * @param type Returns the type or TYPE::UNKNOWN_TYPE + * @return RETURN_OK if parameter exists, RETURN_FAILED else. + */ + ReturnValue_t getType( uint32_t parameter_id, Type* type ); + + /** + * Method to check if a PID exists. Does not lock, as there's no + * possibility to alter the list that is checked during run-time. + * @param parameterId The PID (not pool id!) of a parameter. + * @return true if exists, false else. + */ + bool exists(uint32_t parameterId); +}; + +//We assume someone globally instantiates a DataPool. +extern GlobalDataPool dataPool; +#endif /* DATAPOOL_H_ */ diff --git a/datapoolglob/GlobalDataSet.cpp b/datapoolglob/GlobalDataSet.cpp new file mode 100644 index 00000000..7409dbbd --- /dev/null +++ b/datapoolglob/GlobalDataSet.cpp @@ -0,0 +1,166 @@ +#include +#include +#include + +GlobDataSet::GlobDataSet() : + fill_count(0), state(DATA_SET_UNINITIALISED) { + for (unsigned count = 0; count < DATA_SET_MAX_SIZE; count++) { + registeredVariables[count] = nullptr; + } +} + +GlobDataSet::~GlobDataSet() { + //Don't do anything with your variables, they are dead already! + // (Destructor is already called) +} + +ReturnValue_t GlobDataSet::registerVariable(PoolVariableIF* variable) { + if (state != DATA_SET_UNINITIALISED) { + sif::error << "DataSet::registerVariable: Call made in wrong position." << std::endl; + return DATA_SET_UNINITIALISED; + } + if (variable == nullptr) { + sif::error << "DataSet::registerVariable: Pool variable is nullptr." << std::endl; + return POOL_VAR_NULL; + } + if (fill_count >= DATA_SET_MAX_SIZE) { + sif::error << "DataSet::registerVariable: DataSet is full." << std::endl; + return DATA_SET_FULL; + } + registeredVariables[fill_count] = variable; + fill_count++; + return RETURN_OK; +} + +ReturnValue_t GlobDataSet::read() { + ReturnValue_t result = RETURN_OK; + if (state == DATA_SET_UNINITIALISED) { + lockDataPool(); + for (uint16_t count = 0; count < fill_count; count++) { + if (registeredVariables[count]->getReadWriteMode() + != PoolVariableIF::VAR_WRITE + && registeredVariables[count]->getDataPoolId() + != PoolVariableIF::NO_PARAMETER) { + ReturnValue_t status = registeredVariables[count]->read(); + if (status != RETURN_OK) { + result = INVALID_PARAMETER_DEFINITION; + break; + } + } + } + state = DATA_SET_WAS_READ; + unlockDataPool(); + } else { + sif::error << "DataSet::read(): Call made in wrong position." << std::endl; + result = SET_WAS_ALREADY_READ; + } + return result; +} + +ReturnValue_t GlobDataSet::commit(bool valid) { + setEntriesValid(valid); + setSetValid(valid); + return commit(); +} + +ReturnValue_t GlobDataSet::commit() { + if (state == DATA_SET_WAS_READ) { + handleAlreadyReadDatasetCommit(); + return RETURN_OK; + } + else { + return handleUnreadDatasetCommit(); + } +} + +void GlobDataSet::handleAlreadyReadDatasetCommit() { + lockDataPool(); + for (uint16_t count = 0; count < fill_count; count++) { + if (registeredVariables[count]->getReadWriteMode() + != PoolVariableIF::VAR_READ + && registeredVariables[count]->getDataPoolId() + != PoolVariableIF::NO_PARAMETER) { + registeredVariables[count]->commit(); + } + } + state = DATA_SET_UNINITIALISED; + unlockDataPool(); +} + +ReturnValue_t GlobDataSet::handleUnreadDatasetCommit() { + ReturnValue_t result = RETURN_OK; + lockDataPool(); + for (uint16_t count = 0; count < fill_count; count++) { + if (registeredVariables[count]->getReadWriteMode() + == PoolVariableIF::VAR_WRITE + && registeredVariables[count]->getDataPoolId() + != PoolVariableIF::NO_PARAMETER) { + registeredVariables[count]->commit(); + } else if (registeredVariables[count]->getDataPoolId() + != PoolVariableIF::NO_PARAMETER) { + if (result != COMMITING_WITHOUT_READING) { + sif::error << "DataSet::commit(): commit-without-read call made " + "with non write-only variable." << std::endl; + result = COMMITING_WITHOUT_READING; + } + } + } + state = DATA_SET_UNINITIALISED; + unlockDataPool(); + return result; +} + +ReturnValue_t GlobDataSet::unlockDataPool() { + return ::dataPool.freeDataPoolLock(); +} + +ReturnValue_t GlobDataSet::lockDataPool() { + return ::dataPool.lockDataPool(); +} + +ReturnValue_t GlobDataSet::serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { + ReturnValue_t result = RETURN_FAILED; + for (uint16_t count = 0; count < fill_count; count++) { + result = registeredVariables[count]->serialize(buffer, size, max_size, + bigEndian); + if (result != RETURN_OK) { + return result; + } + } + return result; +} + +size_t GlobDataSet::getSerializedSize() const { + uint32_t size = 0; + for (uint16_t count = 0; count < fill_count; count++) { + size += registeredVariables[count]->getSerializedSize(); + } + return size; +} + +void GlobDataSet::setEntriesValid(bool valid) { + for (uint16_t count = 0; count < fill_count; count++) { + if (registeredVariables[count]->getReadWriteMode() + != PoolVariableIF::VAR_READ) { + registeredVariables[count]->setValid(valid); + } + } +} + +void GlobDataSet::setSetValid(bool valid) { + this->valid = valid; +} + +ReturnValue_t GlobDataSet::deSerialize(const uint8_t** buffer, size_t* size, + bool bigEndian) { + ReturnValue_t result = RETURN_FAILED; + for (uint16_t count = 0; count < fill_count; count++) { + result = registeredVariables[count]->deSerialize(buffer, size, + bigEndian); + if (result != RETURN_OK) { + return result; + } + } + return result; +} diff --git a/datapoolglob/GlobalDataSet.h b/datapoolglob/GlobalDataSet.h new file mode 100644 index 00000000..365de380 --- /dev/null +++ b/datapoolglob/GlobalDataSet.h @@ -0,0 +1,185 @@ +#ifndef DATASET_H_ +#define DATASET_H_ + +#include +#include +#include + +#include +/** + * @brief The DataSet class manages a set of locally checked out variables + * for the global data pool. + * + * @details + * This class manages a list, where a set of local variables (or pool variables) + * are registered. They are checked-out (i.e. their values are looked + * up and copied) with the read call. After the user finishes working with the + * pool variables, he can write back all variable values to the pool with + * the commit call. The data set manages locking and freeing the data pool, + * to ensure that all values are read and written back at once. + * + * An internal state manages usage of this class. Variables may only be + * registered before the read call is made, and the commit call only + * after the read call. + * + * If pool variables are writable and not committed until destruction + * of the set, the DataSet class automatically sets the valid flag in the + * data pool to invalid (without) changing the variable's value. + * @author Bastian Baetz + * @ingroup data_pool + */ +class GlobDataSet: public DataSetIF, public HasReturnvaluesIF, public SerializeIF { +public: + //SHOULDDO we could use a linked list of datapool variables + //!< This definition sets the maximum number of variables to + //! register in one DataSet. + static const uint8_t DATA_SET_MAX_SIZE = 63; + + + static constexpr uint8_t INTERFACE_ID = CLASS_ID::DATA_SET_CLASS; + static constexpr ReturnValue_t INVALID_PARAMETER_DEFINITION = + MAKE_RETURN_CODE( 0x01 ); + static constexpr ReturnValue_t SET_WAS_ALREADY_READ = MAKE_RETURN_CODE( 0x02 ); + static constexpr ReturnValue_t COMMITING_WITHOUT_READING = + MAKE_RETURN_CODE(0x03); + + static constexpr ReturnValue_t DATA_SET_UNINITIALIZED = MAKE_RETURN_CODE( 0x04 ); + static constexpr ReturnValue_t DATA_SET_FULL = MAKE_RETURN_CODE( 0x05 ); + static constexpr ReturnValue_t POOL_VAR_NULL = MAKE_RETURN_CODE( 0x06 ); + /** + * @brief The constructor simply sets the fill_count to zero and sets + * the state to "uninitialized". + */ + GlobDataSet(); + + /** + * @brief This operation is used to register the local variables in the set. + * @details It stores the pool variable pointer in a variable list. + */ + ReturnValue_t registerVariable(PoolVariableIF* variable) override; + + /** + * @brief The destructor automatically manages writing the valid + * information of variables. + * @details + * In case the data set was read out, but not committed(indicated by state), + * the destructor parses all variables that are still registered to the set. + * For each, the valid flag in the data pool is set to "invalid". + */ + ~GlobDataSet(); + /** + * @brief The read call initializes reading out all registered variables. + * @details + * It iterates through the list of registered variables and calls all read() + * functions of the registered pool variables (which read out their values + * from the data pool) which are not write-only. + * In case of an error (e.g. a wrong data type, or an invalid data pool id), + * the operation is aborted and @c INVALID_PARAMETER_DEFINITION returned. + * + * The data pool is locked during the whole read operation and + * freed afterwards.The state changes to "was written" after this operation. + * @return - @c RETURN_OK if all variables were read successfully. + * - @c INVALID_PARAMETER_DEFINITION if PID, size or type of the + * requested variable is invalid. + * - @c SET_WAS_ALREADY_READ if read() is called twice without calling + * commit() in between + */ + ReturnValue_t read(); + /** + * @brief The commit call initializes writing back the registered variables. + * @details + * It iterates through the list of registered variables and calls the + * commit() method of the remaining registered variables (which write back + * their values to the pool). + * + * The data pool is locked during the whole commit operation and + * freed afterwards. The state changes to "was committed" after this operation. + * + * If the set does contain at least one variable which is not write-only commit() + * can only be called after read(). If the set only contains variables which are + * write only, commit() can be called without a preceding read() call. + * @return - @c RETURN_OK if all variables were read successfully. + * - @c COMMITING_WITHOUT_READING if set was not read yet and + * contains non write-only variables + */ + ReturnValue_t commit(void); + /** + * Variant of method above which sets validity of all elements of the set. + * @param valid Validity information from PoolVariableIF. + * @return - @c RETURN_OK if all variables were read successfully. + * - @c COMMITING_WITHOUT_READING if set was not read yet and + * contains non write-only variables + */ + ReturnValue_t commit(bool valid); + + /** + * Set all entries + * @param valid + */ + void setSetValid(bool valid); + + /** + * Set the valid information of all variables contained in the set which + * are not read-only + * + * @param valid Validity information from PoolVariableIF. + */ + void setEntriesValid(bool valid); + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const override; + + size_t getSerializedSize() const override; + + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + bool bigEndian) override; +private: + + /** + * @brief This array represents all pool variables registered in this set. + */ + PoolVariableIF* registeredVariables[DATA_SET_MAX_SIZE]; + /** + * \brief The fill_count attribute ensures that the variables register in the correct array + * position and that the maximum number of variables is not exceeded. + */ + uint16_t fill_count; + /** + * States of the seet. + */ + enum States { + DATA_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED + DATA_SET_WAS_READ //!< DATA_SET_WAS_READ + }; + /** + * @brief state manages the internal state of the data set, + * which is important e.g. for the behavior on destruction. + */ + States state; + + /** + * If the valid state of a dataset is always relevant to the whole + * data set we can use this flag. + */ + bool valid = false; + /** + * @brief This is a small helper function to facilitate locking + * the underlying data data pool structure + * @details + * It makes use of the lockDataPool method offered by the DataPool class. + */ + ReturnValue_t lockDataPool() override; + + /** + * @brief This is a small helper function to facilitate + * unlocking the underlying data data pool structure + * @details + * It makes use of the freeDataPoolLock method offered by the DataPool class. + */ + ReturnValue_t unlockDataPool() override; + + void handleAlreadyReadDatasetCommit(); + ReturnValue_t handleUnreadDatasetCommit(); +}; + +#endif /* DATASET_H_ */ diff --git a/datapoolglob/GlobalPoolVariable.h b/datapoolglob/GlobalPoolVariable.h new file mode 100644 index 00000000..9f80492b --- /dev/null +++ b/datapoolglob/GlobalPoolVariable.h @@ -0,0 +1,189 @@ +#ifndef POOLVARIABLE_H_ +#define POOLVARIABLE_H_ + +#include +#include +#include +#include +#include +#include + +template class PoolVarList; + + +/** + * @brief This is the access class for non-array data pool entries. + * + * @details + * To ensure safe usage of the data pool, operation is not done directly + * on the data pool entries, but on local copies. This class provides simple + * type-safe access to single data pool entries (i.e. entries with length = 1). + * The class can be instantiated as read-write and read only. + * It provides a commit-and-roll-back semantic, which means that the + * variable's value in the data pool is not changed until the + * commit call is executed. + * @tparam T The template parameter sets the type of the variable. + * Currently, all plain data types are supported, but in principle + * any type is possible. + * @ingroup data_pool + */ +template +class GlobPoolVar: public PoolVariableIF { + template friend class PoolVarList; + static_assert(not std::is_same::value, + "Do not use boolean for the PoolEntry type, use uint8_t instead!" + "Warum? Darum :-)"); +public: + /** + * @brief In the constructor, the variable can register itself in a + * DataSet (if nullptr is not passed). + * @details + * It DOES NOT fetch the current value from the data pool, but + * sets the value attribute to default (0). + * The value is fetched within the read() operation. + * @param set_id This is the id in the global data pool + * this instance of the access class corresponds to. + * @param dataSet The data set in which the variable shall register + * itself. If NULL, the variable is not registered. + * @param setWritable If this flag is set to true, changes in the value + * attribute can be written back to the data pool, otherwise not. + */ + GlobPoolVar(uint32_t set_id, DataSetIF* dataSet, + ReadWriteMode_t setReadWriteMode); + + /** + * @brief This is the local copy of the data pool entry. + * @details The user can work on this attribute + * just like he would on a simple local variable. + */ + T value = 0; + + /** + * @brief Copy ctor to copy classes containing Pool Variables. + * (Robin): This only copies member variables, which is done + * by the default copy ctor. maybe we can ommit this ctor? + */ + GlobPoolVar(const GlobPoolVar& rhs); + + /** + * @brief The classes destructor is empty. + * @details If commit() was not called, the local value is + * discarded and not written back to the data pool. + */ + ~GlobPoolVar() {} + +protected: + /** + * @brief To access the correct data pool entry on read and commit calls, + * the data pool is stored. + */ + uint32_t dataPoolId; + + /** + * @brief The valid information as it was stored in the data pool is + * copied to this attribute. + */ + uint8_t valid; + + /** + * @brief The information whether the class is read-write or read-only + * is stored here. + */ + pool_rwm_t readWriteMode; + + /** + * @brief This is a call to read the value from the global data pool. + * @details + * When executed, this operation tries to fetch the pool entry with matching + * data pool id from the global data pool and copies the value and the valid + * information to its local attributes. In case of a failure (wrong type or + * pool id not found), the variable is set to zero and invalid. + * The operation does NOT provide any mutual exclusive protection by itself. + */ + ReturnValue_t read() override; + + /** + * @brief The commit call writes back the variable's value to the data pool. + * @details It checks type and size, as well as if the variable is writable. If so, + * the value is copied and the valid flag is automatically set to "valid". + * The operation does NOT provide any mutual exclusive protection by itself. + * + */ + ReturnValue_t commit() override; + + /** + * Empty ctor for List initialization + */ + GlobPoolVar(); +public: + /** + * \brief This operation returns the data pool id of the variable. + */ + uint32_t getDataPoolId() const override; + + /** + * This method returns if the variable is write-only, read-write or read-only. + */ + ReadWriteMode_t getReadWriteMode() const override; + /** + * This operation sets the data pool id of the variable. + * The method is necessary to set id's of data pool member variables with bad initialization. + */ + void setDataPoolId(uint32_t poolId); + + /** + * \brief With this call, the valid information of the variable is returned. + */ + bool isValid() const override; + + uint8_t getValid(); + + void setValid(uint8_t valid); + + operator T() { + return value; + } + + operator T() const { + return value; + } + + GlobPoolVar &operator=(T newValue) { + value = newValue; + return *this; + } + + GlobPoolVar &operator=(GlobPoolVar newPoolVariable) { + value = newPoolVariable.value; + return *this; + } + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const override { + return SerializeAdapter::serialize(&value, buffer, size, max_size, + bigEndian); + } + + virtual size_t getSerializedSize() const { + return SerializeAdapter::getSerializedSize(&value); + } + + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + bool bigEndian) { + return SerializeAdapter::deSerialize(&value, buffer, size, bigEndian); + } +}; + +#include + +typedef GlobPoolVar gp_bool_t; +typedef GlobPoolVar gp_uint8_t; +typedef GlobPoolVar gp_uint16_t; +typedef GlobPoolVar gp_uint32_t; +typedef GlobPoolVar gp_int8_t; +typedef GlobPoolVar gp_int16_t; +typedef GlobPoolVar gp_int32_t; +typedef GlobPoolVar gp_float_t; +typedef GlobPoolVar gp_double_t; + +#endif /* POOLVARIABLE_H_ */ diff --git a/datapoolglob/GlobalPoolVariable.tpp b/datapoolglob/GlobalPoolVariable.tpp new file mode 100644 index 00000000..287f06dd --- /dev/null +++ b/datapoolglob/GlobalPoolVariable.tpp @@ -0,0 +1,84 @@ +#pragma once + +template +inline GlobPoolVar::GlobPoolVar(uint32_t set_id, + DataSetIF* dataSet, ReadWriteMode_t setReadWriteMode): + dataPoolId(set_id), valid(PoolVariableIF::INVALID), + readWriteMode(setReadWriteMode) +{ + if (dataSet != nullptr) { + dataSet->registerVariable(this); + } +} + +template +inline ReturnValue_t GlobPoolVar::read() { + PoolEntry* read_out = ::dataPool.getData(dataPoolId, 1); + if (read_out != NULL) { + valid = read_out->valid; + value = *(read_out->address); + return HasReturnvaluesIF::RETURN_OK; + } else { + value = 0; + valid = false; + sif::error << "PoolVariable: read of DP Variable 0x" << std::hex + << dataPoolId << std::dec << " failed." << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +template +inline ReturnValue_t GlobPoolVar::commit() { + PoolEntry* write_back = ::dataPool.getData(dataPoolId, 1); + if ((write_back != NULL) && (readWriteMode != VAR_READ)) { + write_back->valid = valid; + *(write_back->address) = value; + return HasReturnvaluesIF::RETURN_OK; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +template +inline GlobPoolVar::GlobPoolVar(): + dataPoolId(PoolVariableIF::NO_PARAMETER), + valid(PoolVariableIF::INVALID), + readWriteMode(VAR_READ), value(0) {} + +template +inline GlobPoolVar::GlobPoolVar(const GlobPoolVar& rhs) : + dataPoolId(rhs.dataPoolId), valid(rhs.valid), readWriteMode( + rhs.readWriteMode), value(rhs.value) {} + +template +inline pool_rwm_t GlobPoolVar::getReadWriteMode() const { + return readWriteMode; +} + +template +inline uint32_t GlobPoolVar::getDataPoolId() const { + return dataPoolId; +} + +template +inline void GlobPoolVar::setDataPoolId(uint32_t poolId) { + dataPoolId = poolId; +} + +template +inline bool GlobPoolVar::isValid() const { + if (valid) + return true; + else + return false; +} + +template +inline uint8_t GlobPoolVar::getValid() { + return valid; +} + +template +inline void GlobPoolVar::setValid(uint8_t valid) { + this->valid = valid; +} diff --git a/datapoolglob/GlobalPoolVector.h b/datapoolglob/GlobalPoolVector.h new file mode 100644 index 00000000..47381aec --- /dev/null +++ b/datapoolglob/GlobalPoolVector.h @@ -0,0 +1,223 @@ +#ifndef POOLVECTOR_H_ +#define POOLVECTOR_H_ + +#include +#include +#include +#include +#include + +/** + * \brief This is the access class for array-type data pool entries. + * + * \details To ensure safe usage of the data pool, operation is not done directly on the data pool + * entries, but on local copies. This class provides simple type- and length-safe access + * to vector-style data pool entries (i.e. entries with length > 1). + * The class can be instantiated as read-write and read only. + * It provides a commit-and-roll-back semantic, which means that no array entry in + * the data pool is changed until the commit call is executed. + * There are two template parameters: + * \tparam T This template parameter specifies the data type of an array entry. Currently, all + * plain data types are supported, but in principle any type is possible. + * \tparam vector_size This template parameter specifies the vector size of this entry. + * Using a template parameter for this is not perfect, but avoids dynamic memory allocation. + * \ingroup data_pool + */ +template +class GlobPoolVector: public PoolVariableIF { +private: + /** + * \brief To access the correct data pool entry on read and commit calls, the data pool id + * is stored. + */ + uint32_t dataPoolId; + /** + * \brief The valid information as it was stored in the data pool is copied to this attribute. + */ + uint8_t valid; + /** + * \brief The information whether the class is read-write or read-only is stored here. + */ + ReadWriteMode_t readWriteMode; + +protected: + /** + * \brief This is a call to read the array's values from the global data pool. + * \details When executed, this operation tries to fetch the pool entry with matching + * data pool id from the global data pool and copies all array values and the valid + * information to its local attributes. In case of a failure (wrong type, size or + * pool id not found), the variable is set to zero and invalid. + * The operation does NOT provide any mutual exclusive protection by itself. + */ + ReturnValue_t read() { + PoolEntry* read_out = ::dataPool.getData(this->dataPoolId, + vector_size); + if (read_out != NULL) { + this->valid = read_out->valid; + memcpy(this->value, read_out->address, read_out->getByteSize()); + + return HasReturnvaluesIF::RETURN_OK; + + } else { + memset(this->value, 0, vector_size * sizeof(T)); + sif::error << "PoolVector: read of DP Variable 0x" << std::hex + << dataPoolId << std::dec << " failed." << std::endl; + this->valid = INVALID; + return HasReturnvaluesIF::RETURN_FAILED; + } + } + /** + * \brief The commit call copies the array values back to the data pool. + * \details It checks type and size, as well as if the variable is writable. If so, + * the value is copied and the valid flag is automatically set to "valid". + * The operation does NOT provide any mutual exclusive protection by itself. + * + */ + ReturnValue_t commit() { + PoolEntry* write_back = ::dataPool.getData(this->dataPoolId, + vector_size); + if ((write_back != NULL) && (this->readWriteMode != VAR_READ)) { + write_back->valid = valid; + memcpy(write_back->address, this->value, write_back->getByteSize()); + return HasReturnvaluesIF::RETURN_OK; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } + } +public: + /** + * \brief This is the local copy of the data pool entry. + * \detials The user can work on this attribute + * just like he would on a local array of this type. + */ + T value[vector_size]; + /** + * \brief In the constructor, the variable can register itself in a DataSet (if not NULL is + * passed). + * \details It DOES NOT fetch the current value from the data pool, but sets the value + * attribute to default (0). The value is fetched within the read() operation. + * \param set_id This is the id in the global data pool this instance of the access class + * corresponds to. + * \param dataSet The data set in which the variable shall register itself. If NULL, + * the variable is not registered. + * \param setWritable If this flag is set to true, changes in the value attribute can be + * written back to the data pool, otherwise not. + */ + GlobPoolVector(uint32_t set_id, DataSetIF* set, + ReadWriteMode_t setReadWriteMode) : + dataPoolId(set_id), valid(false), readWriteMode(setReadWriteMode) { + memset(this->value, 0, vector_size * sizeof(T)); + if (set != NULL) { + set->registerVariable(this); + } + } + /** + * Copy ctor to copy classes containing Pool Variables. + */ +// PoolVector(const PoolVector& rhs) { +// PoolVector temp(rhs.dataPoolId, rhs.) +// memcpy(value, rhs.value, sizeof(T)*vector_size); +// } + /** + * \brief The classes destructor is empty. + * \details If commit() was not called, the local value is + * discarded and not written back to the data pool. + */ + ~GlobPoolVector() { + } + ; + /** + * \brief The operation returns the number of array entries in this variable. + */ + uint8_t getSize() { + return vector_size; + } + /** + * \brief This operation returns the data pool id of the variable. + */ + uint32_t getDataPoolId() const { + return dataPoolId; + } + /** + * This operation sets the data pool id of the variable. + * The method is necessary to set id's of data pool member variables with bad initialization. + */ + void setDataPoolId(uint32_t poolId) { + dataPoolId = poolId; + } + /** + * This method returns if the variable is write-only, read-write or read-only. + */ + ReadWriteMode_t getReadWriteMode() const { + return readWriteMode; + } + ; + /** + * \brief With this call, the valid information of the variable is returned. + */ + bool isValid() const { + if (valid != INVALID) + return true; + else + return false; + } + + void setValid(uint8_t valid) { + this->valid = valid; + } + + uint8_t getValid() { + return valid; + } + + T &operator [](int i) { + return value[i]; + } + + const T &operator [](int i) const { + return value[i]; + } + + GlobPoolVector &operator=( + GlobPoolVector newPoolVector) { + + for (uint16_t i = 0; i < vector_size; i++) { + this->value[i] = newPoolVector.value[i]; + } + return *this; + } + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const override { + uint16_t i; + ReturnValue_t result; + for (i = 0; i < vector_size; i++) { + result = SerializeAdapter::serialize(&(value[i]), buffer, size, + max_size, bigEndian); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return result; + } + + virtual size_t getSerializedSize() const override { + return vector_size * SerializeAdapter::getSerializedSize(value); + } + + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + bool bigEndian) override { + uint16_t i; + ReturnValue_t result; + for (i = 0; i < vector_size; i++) { + result = SerializeAdapter::deSerialize(&(value[i]), buffer, size, + bigEndian); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return result; + } +}; + +#endif /* POOLVECTOR_H_ */ diff --git a/datapoollocal/LocalDataSet.cpp b/datapoollocal/LocalDataSet.cpp new file mode 100644 index 00000000..07f86e18 --- /dev/null +++ b/datapoollocal/LocalDataSet.cpp @@ -0,0 +1,66 @@ +#include + +LocalDataSet::LocalDataSet(): + fill_count(0), state(DATA_SET_UNINITIALISED) +{ + for (unsigned count = 0; count < DATA_SET_MAX_SIZE; count++) { + registeredVariables[count] = nullptr; + } +} + +// who has the responsibility to lock the mutex? the local pool variable +// has access to the HK manager and could call its mutex lock function. +ReturnValue_t LocalDataSet::registerVariable( + PoolVariableIF *variable) { + return RETURN_OK; +} + +LocalDataSet::~LocalDataSet() { +} + +ReturnValue_t LocalDataSet::read() { + return RETURN_OK; +} + +ReturnValue_t LocalDataSet::commit(void) { + return RETURN_OK; +} + +ReturnValue_t LocalDataSet::commit(bool valid) { + return RETURN_OK; +} + +void LocalDataSet::setSetValid(bool valid) { +} + +void LocalDataSet::setEntriesValid(bool valid) { +} + +ReturnValue_t LocalDataSet::serialize(uint8_t **buffer, + size_t *size, const size_t max_size, bool bigEndian) const { + return RETURN_OK; +} + +size_t LocalDataSet::getSerializedSize() const { + return 0; +} + +ReturnValue_t LocalDataSet::deSerialize(const uint8_t **buffer, + size_t *size, bool bigEndian) { + return RETURN_OK; +} + +ReturnValue_t LocalDataSet::lockDataPool() { + return RETURN_OK; +} + +ReturnValue_t LocalDataSet::unlockDataPool() { + return RETURN_OK; +} + +void LocalDataSet::handleAlreadyReadDatasetCommit() { +} + +ReturnValue_t LocalDataSet::handleUnreadDatasetCommit() { + return RETURN_OK; +} diff --git a/datapoollocal/LocalDataSet.h b/datapoollocal/LocalDataSet.h new file mode 100644 index 00000000..6110175c --- /dev/null +++ b/datapoollocal/LocalDataSet.h @@ -0,0 +1,187 @@ +#ifndef FRAMEWORK_DATAPOOLLOCAL_LOCALDATASET_H_ +#define FRAMEWORK_DATAPOOLLOCAL_LOCALDATASET_H_ +#include +#include + +/** + * @brief The LocalDataSet class manages a set of locally checked out variables + * for local data pools + * @details + * This class manages a list, where a set of local variables (or pool variables) + * are registered. They are checked-out (i.e. their values are looked + * up and copied) with the read call. After the user finishes working with the + * pool variables, he can write back all variable values to the pool with + * the commit call. The data set manages locking and freeing the local data pools, + * to ensure thread-safety. + * + * An internal state manages usage of this class. Variables may only be + * registered before the read call is made, and the commit call only + * after the read call. + * + * If pool variables are writable and not committed until destruction + * of the set, the DataSet class automatically sets the valid flag in the + * data pool to invalid (without) changing the variable's value. + * + * @ingroup data_pool + */ +class LocalDataSet: + public DataSetIF, + public HasReturnvaluesIF, + public SerializeIF { +public: + static constexpr uint8_t INTERFACE_ID = CLASS_ID::DATA_SET_CLASS; + static constexpr ReturnValue_t INVALID_PARAMETER_DEFINITION = + MAKE_RETURN_CODE( 0x01 ); + static constexpr ReturnValue_t SET_WAS_ALREADY_READ = MAKE_RETURN_CODE( 0x02 ); + static constexpr ReturnValue_t COMMITING_WITHOUT_READING = + MAKE_RETURN_CODE(0x03); + + static constexpr ReturnValue_t DATA_SET_UNINITIALIZED = MAKE_RETURN_CODE( 0x04 ); + static constexpr ReturnValue_t DATA_SET_FULL = MAKE_RETURN_CODE( 0x05 ); + static constexpr ReturnValue_t POOL_VAR_NULL = MAKE_RETURN_CODE( 0x06 ); + /** + * @brief The constructor simply sets the fill_count to zero and sets + * the state to "uninitialized". + */ + LocalDataSet(); + + /** + * @brief This operation is used to register the local variables in the set. + * @details It stores the pool variable pointer in a variable list. + */ + ReturnValue_t registerVariable(PoolVariableIF* variable) override; + + /** + * @brief The destructor automatically manages writing the valid + * information of variables. + * @details + * In case the data set was read out, but not committed(indicated by state), + * the destructor parses all variables that are still registered to the set. + * For each, the valid flag in the data pool is set to "invalid". + */ + ~LocalDataSet(); + + /** + * @brief The read call initializes reading out all registered variables. + * @details + * It iterates through the list of registered variables and calls all read() + * functions of the registered pool variables (which read out their values + * from the data pool) which are not write-only. + * In case of an error (e.g. a wrong data type, or an invalid data pool id), + * the operation is aborted and @c INVALID_PARAMETER_DEFINITION returned. + * + * The data pool is locked during the whole read operation and + * freed afterwards.The state changes to "was written" after this operation. + * @return - @c RETURN_OK if all variables were read successfully. + * - @c INVALID_PARAMETER_DEFINITION if PID, size or type of the + * requested variable is invalid. + * - @c SET_WAS_ALREADY_READ if read() is called twice without + * calling commit() in between + */ + ReturnValue_t read(); + + /** + * @brief The commit call initializes writing back the registered variables. + * @details + * It iterates through the list of registered variables and calls the + * commit() method of the remaining registered variables (which write back + * their values to the pool). + * + * The data pool is locked during the whole commit operation and + * freed afterwards. The state changes to "was committed" after this operation. + * + * If the set does contain at least one variable which is not write-only commit() + * can only be called after read(). If the set only contains variables which are + * write only, commit() can be called without a preceding read() call. + * @return - @c RETURN_OK if all variables were read successfully. + * - @c COMMITING_WITHOUT_READING if set was not read yet and + * contains non write-only variables + */ + ReturnValue_t commit(void); + + /** + * Variant of method above which sets validity of all elements of the set. + * @param valid Validity information from PoolVariableIF. + * @return - @c RETURN_OK if all variables were read successfully. + * - @c COMMITING_WITHOUT_READING if set was not read yet and + * contains non write-only variables + */ + ReturnValue_t commit(bool valid); + + /** + * Set all entries + * @param valid + */ + void setSetValid(bool valid); + + /** + * Set the valid information of all variables contained in the set which + * are not read-only + * + * @param valid Validity information from PoolVariableIF. + */ + void setEntriesValid(bool valid); + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const override; + + size_t getSerializedSize() const override; + + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + bool bigEndian) override; +private: + // SHOULDDO we could use a linked list of datapool variables + //! This definition sets the maximum number of variables + //! to register in one DataSet. + static const uint8_t DATA_SET_MAX_SIZE = 63; + /** + * @brief This array represents all pool variables registered in this set. + */ + PoolVariableIF* registeredVariables[DATA_SET_MAX_SIZE]; + /** + * @brief The fill_count attribute ensures that the variables register in + * the correct array position and that the maximum number of + * variables is not exceeded. + */ + uint16_t fill_count; + + /** + * States of the seet. + */ + enum States { + DATA_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED + DATA_SET_WAS_READ //!< DATA_SET_WAS_READ + }; + + /** + * @brief state manages the internal state of the data set, + * which is important e.g. for the behavior on destruction. + */ + States state; + + /** + * If the valid state of a dataset is always relevant to the whole + * data set we can use this flag. + */ + bool valid = false; + /** + * @brief This is a small helper function to facilitate locking + * the underlying data data pool structure + * @details + * It makes use of the lockDataPool method offered by the DataPool class. + */ + ReturnValue_t lockDataPool() override; + + /** + * @brief This is a small helper function to facilitate + * unlocking the underlying data data pool structure + * @details + * It makes use of the freeDataPoolLock method offered by the DataPool class. + */ + ReturnValue_t unlockDataPool() override; + + void handleAlreadyReadDatasetCommit(); + ReturnValue_t handleUnreadDatasetCommit(); +}; + +#endif /* FRAMEWORK_DATAPOOLLOCAL_LOCALDATASET_H_ */ diff --git a/datapoollocal/LocalPoolVariable.h b/datapoollocal/LocalPoolVariable.h new file mode 100644 index 00000000..44c16a7c --- /dev/null +++ b/datapoollocal/LocalPoolVariable.h @@ -0,0 +1,103 @@ +#pragma once + +#include +#include + +#include + +#include +/** + * @brief This is the access class for non-array local data pool entries. + * + * @details + * + * @tparam T The template parameter sets the type of the variable. + * Currently, all plain data types are supported, but in principle + * any type is possible. + * @ingroup data_pool + */ + +/** + * @brief Local Pool Variable class which is used to access the local pools. + * @details This class is not stored in the map. Instead, it is used to access + * the pool entries by using a pointer to the map storing the pool + * entries. It can also be used to organize these pool entries + * into data sets. + * @tparam T + */ +template +class LocalPoolVar: public PoolVariableIF, HasReturnvaluesIF { +public: + static constexpr lp_id_t INVALID_POOL_ID = 0xFFFFFFFF; + + /** + * This constructor is used by the data creators to have pool variable + * instances which can also be stored in datasets. + * @param set_id + * @param setReadWriteMode + * @param localPoolMap + * @param dataSet + */ + LocalPoolVar(lp_id_t poolId, HasHkPoolParametersIF* hkOwner, + pool_rwm_t setReadWriteMode, DataSetIF* dataSet = nullptr); + + /** + * This constructor is used by data users like controllers to have + * access to the local pool variables of data creators by supplying + * the respective creator object ID. + * @param poolId + * @param poolOwner + * @param setReadWriteMode + * @param dataSet + */ + LocalPoolVar(lp_id_t poolId, object_id_t poolOwner, + pool_rwm_t setReadWriteMode, DataSetIF* dataSet = nullptr); + + virtual~ LocalPoolVar() {}; + + /** + * @brief This is the local copy of the data pool entry. + * @details The user can work on this attribute + * just like he would on a simple local variable. + */ + T value = 0; + + ReturnValue_t commit() override; + ReturnValue_t read() override; + pool_rwm_t getReadWriteMode() const override; + uint32_t getDataPoolId() const override; + bool isValid() const override; + void setValid(uint8_t validity) override; + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const override; + virtual size_t getSerializedSize() const override; + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + bool bigEndian) override; +private: + lp_id_t localPoolId = INVALID_POOL_ID; + pool_rwm_t readWriteMode = pool_rwm_t::VAR_READ_WRITE; + bool valid = false; + + bool objectValid = true; + //! Pointer to the class which manages the HK pool. + HousekeepingManager* hkManager; +}; + +#include +template +using lp_variable = LocalPoolVar; + +using lp_bool_t = LocalPoolVar; +using lp_uint8_t = LocalPoolVar; +using lp_uint16_t = LocalPoolVar; +using lp_uint32_t = LocalPoolVar; +using lp_uint64_t = LocalPoolVar; +using lp_int8_t = LocalPoolVar; +using lp_int16_t = LocalPoolVar; +using lp_int32_t = LocalPoolVar; +using lp_int64_t = LocalPoolVar; +using lp_float_t = LocalPoolVar; +using lp_double_t = LocalPoolVar; + + diff --git a/datapoollocal/LocalPoolVariable.tpp b/datapoollocal/LocalPoolVariable.tpp new file mode 100644 index 00000000..fdd18bcd --- /dev/null +++ b/datapoollocal/LocalPoolVariable.tpp @@ -0,0 +1,109 @@ +#pragma once + +#include +#include + +#include + +template +inline LocalPoolVar::LocalPoolVar(lp_id_t poolId, + HasHkPoolParametersIF* hkOwner, pool_rwm_t setReadWriteMode, + DataSetIF* dataSet): + localPoolId(poolId),readWriteMode(setReadWriteMode) { + hkManager = hkOwner->getHkManagerHandle(); + if(dataSet != nullptr) { + dataSet->registerVariable(this); + } +} + +template +inline LocalPoolVar::LocalPoolVar(lp_id_t poolId, object_id_t poolOwner, + pool_rwm_t setReadWriteMode, DataSetIF *dataSet): + readWriteMode(readWriteMode) { + HasHkPoolParametersIF* hkOwner = + objectManager->get(poolOwner); + if(hkOwner == nullptr) { + sif::error << "LocalPoolVariable: The supplied pool owner did not implement" + "the correct interface HasHkPoolParametersIF!" << std::endl; + objectValid = false; + return; + } + hkManager = hkOwner->getHkManagerHandle(); + if(dataSet != nullptr) { + dataSet->registerVariable(this); + } +} + +template +inline ReturnValue_t LocalPoolVar::read() { + if(readWriteMode == pool_rwm_t::VAR_WRITE) { + sif::debug << "LocalPoolVar: Invalid read write " + "mode for read() call." << std::endl; + // TODO: special return value + return HasReturnvaluesIF::RETURN_FAILED; + } + MutexHelper(hkManager->getMutexHandle(), MutexIF::NO_TIMEOUT); + PoolEntry* poolEntry = nullptr; + ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, poolEntry); + if(result != RETURN_OK) { + return result; + } + this->value = *(poolEntry->address); + return RETURN_OK; +} + +template +inline ReturnValue_t LocalPoolVar::commit() { + if(readWriteMode == pool_rwm_t::VAR_READ) { + sif::debug << "LocalPoolVar: Invalid read write " + "mode for commit() call." << std::endl; + // TODO: special return value + return HasReturnvaluesIF::RETURN_FAILED; + } + MutexHelper(hkManager->getMutexHandle(), MutexIF::NO_TIMEOUT); + PoolEntry* poolEntry = nullptr; + ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, poolEntry); + if(result != RETURN_OK) { + return result; + } + *(poolEntry->address) = this->value; + return RETURN_OK; +} + +template +inline pool_rwm_t LocalPoolVar::getReadWriteMode() const { + return readWriteMode; +} + +template +inline lp_id_t LocalPoolVar::getDataPoolId() const { + return localPoolId; +} + +template +inline bool LocalPoolVar::isValid() const { + return valid; +} + +template +inline void LocalPoolVar::setValid(uint8_t validity) { + this->valid = validity; +} + +template +inline ReturnValue_t LocalPoolVar::serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { + return AutoSerializeAdapter::serialize(&value, + buffer, size ,max_size, bigEndian); +} + +template +inline size_t LocalPoolVar::getSerializedSize() const { + return AutoSerializeAdapter::getSerializedSize(&value); +} + +template +inline ReturnValue_t LocalPoolVar::deSerialize(const uint8_t** buffer, + size_t* size, bool bigEndian) { + return AutoSerializeAdapter::deSerialize(&value, buffer, size, bigEndian); +} diff --git a/devicehandlers/DeviceHandlerBase.cpp b/devicehandlers/DeviceHandlerBase.cpp index 710e97d7..0549bd45 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/devicehandlers/DeviceHandlerBase.cpp @@ -1,14 +1,14 @@ -#include -#include -#include -#include #include -#include -#include #include #include -#include #include +#include + +#include +#include +#include +#include +#include #include #include @@ -17,34 +17,33 @@ object_id_t DeviceHandlerBase::rawDataReceiverId = 0; object_id_t DeviceHandlerBase::defaultFDIRParentId = 0; DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, - object_id_t deviceCommunication, CookieIF * comCookie_, + 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), - fdirInstance(fdirInstance), hkSwitcher(this), - defaultFDIRUsed(fdirInstance == nullptr), switchOffWasReported(false), - executingTask(nullptr), actionHelper(this, nullptr), cookieInfo(), - childTransitionDelay(5000), transitionSourceMode(_MODE_POWER_DOWN), - transitionSourceSubMode(SUBMODE_NONE), deviceSwitch(setDeviceSwitch) -{ - commandQueue = QueueFactory::instance()-> - createMessageQueue(cmdQueueSize, CommandMessage::MAX_MESSAGE_SIZE); + deviceCommunicationId(deviceCommunication), 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), cookieInfo(), + 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 == nullptr) { - this->fdirInstance = - new DeviceHandlerFailureIsolation(setObjectId, - defaultFDIRParentId); + this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, + defaultFDIRParentId); } } DeviceHandlerBase::~DeviceHandlerBase() { - delete comCookie; + //communicationInterface->close(cookie); if (defaultFDIRUsed) { delete fdirInstance; } @@ -53,7 +52,8 @@ 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(); @@ -66,7 +66,6 @@ ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) { if (mode == MODE_OFF) { return RETURN_OK; } - switch (getComAction()) { case SEND_WRITE: if ((cookieInfo.state == COOKIE_UNUSED)) { @@ -87,7 +86,6 @@ ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) { default: break; } - return RETURN_OK; } @@ -116,7 +114,7 @@ ReturnValue_t DeviceHandlerBase::initialize() { AcceptsDeviceResponsesIF *rawReceiver = objectManager->get< AcceptsDeviceResponsesIF>(rawDataReceiverId); - if (rawReceiver == nullptr) { + if (rawReceiver == NULL) { return RETURN_FAILED; } @@ -158,14 +156,15 @@ ReturnValue_t DeviceHandlerBase::initialize() { fillCommandAndReplyMap(); //Set temperature target state to NON_OP. - DataSet mySet; - PoolVariable thermalRequest(deviceThermalRequestPoolId, &mySet, + GlobDataSet mySet; + gp_uint8_t thermalRequest(deviceThermalRequestPoolId, &mySet, PoolVariableIF::VAR_WRITE); mySet.read(); thermalRequest = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; mySet.commit(PoolVariableIF::VALID); return RETURN_OK; + } void DeviceHandlerBase::decrementDeviceReplyMap() { @@ -366,8 +365,11 @@ ReturnValue_t DeviceHandlerBase::insertInCommandMap(DeviceCommandId_t deviceComm info.expectedReplies = 0; info.isExecuting = false; info.sendReplyTo = NO_COMMANDER; - std::pair result = deviceCommandMap.emplace(deviceCommand,info); - if (result.second) { + std::pair::iterator, bool> returnValue; + returnValue = deviceCommandMap.insert( + std::pair(deviceCommand, + info)); + if (returnValue.second) { return RETURN_OK; } else { return RETURN_FAILED; @@ -426,8 +428,8 @@ void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) { Clock::getUptime(&timeoutStart); if (mode == MODE_OFF) { - DataSet mySet; - PoolVariable thermalRequest(deviceThermalRequestPoolId, &mySet, + GlobDataSet mySet; + gp_uint8_t thermalRequest(deviceThermalRequestPoolId, &mySet, PoolVariableIF::VAR_READ_WRITE); mySet.read(); if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) { @@ -487,7 +489,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) { @@ -526,6 +528,7 @@ void DeviceHandlerBase::doGetWrite() { 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. result = enableReplyInReplyMap(cookieInfo.pendingCommand); @@ -541,25 +544,22 @@ void DeviceHandlerBase::doGetWrite() { } void DeviceHandlerBase::doSendRead() { - ReturnValue_t result = RETURN_FAILED; + ReturnValue_t result; + size_t requestLen = 0; - // If the device handler can only request replies after a command - // has been sent, there should be only one reply enabled and the - // correct reply length will be mapped. - for(DeviceReplyIter iter = deviceReplyMap.begin(); - iter != deviceReplyMap.end();iter++) - { - if(iter->second.delayCycles != 0) { - requestLen = iter->second.replyLen; - break; - } + DeviceReplyIter iter = deviceReplyMap.find(cookieInfo.pendingCommand->first); + if(iter != deviceReplyMap.end()) { + requestLen = iter->second.replyLen; + } + else { + requestLen = 0; } result = communicationInterface->requestReceiveMessage(comCookie, requestLen); + if (result == RETURN_OK) { cookieInfo.state = COOKIE_READ_SENT; - } - else { + } 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. @@ -583,8 +583,8 @@ void DeviceHandlerBase::doGetRead() { cookieInfo.state = COOKIE_UNUSED; - result = communicationInterface->readReceivedMessage(comCookie, &receivedData, - &receivedDataLen); + result = communicationInterface->readReceivedMessage(comCookie, + &receivedData, &receivedDataLen); if (result != RETURN_OK) { triggerEvent(DEVICE_REQUESTING_REPLY_FAILED, result); @@ -644,7 +644,7 @@ void DeviceHandlerBase::doGetRead() { } ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress, - uint8_t ** data, size_t * len) { + uint8_t * *data, uint32_t * len) { size_t lenTmp; if (IPCStore == NULL) { @@ -663,10 +663,8 @@ ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress, *len = 0; return result; } - } - void DeviceHandlerBase::replyRawData(const uint8_t *data, size_t len, MessageQueueId_t sendTo, bool isCommand) { if (IPCStore == NULL || len == 0) { @@ -681,6 +679,7 @@ void DeviceHandlerBase::replyRawData(const uint8_t *data, size_t len, } CommandMessage message; + DeviceHandlerMessage::setDeviceHandlerRawReplyMessage(&message, getObjectId(), address, isCommand); @@ -690,14 +689,12 @@ void DeviceHandlerBase::replyRawData(const uint8_t *data, size_t len, if (result != RETURN_OK) { IPCStore->deleteData(address); - // Silently discard data, this indicates heavy TM traffic which should - // not be increased by additional events. + //Silently discard data, this indicates heavy TM traffic which should not be increased by additional events. } } //Default child implementations - -DeviceHandlerBase::CommunicationAction_t DeviceHandlerBase::getComAction() { +DeviceHandlerIF::CommunicationAction_t DeviceHandlerBase::getComAction() { switch (pstStep) { case 0: return SEND_WRITE; @@ -762,8 +759,8 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, // DeviceCommunicationIF>(newChannelId); // // if (newCommunication != NULL) { -// ReturnValue_t result = newCommunication->reOpen(cookie, logicalAddress, -// maxDeviceReplyLen, comParameter1, comParameter2); +// ReturnValue_t result = newCommunication->reOpen(cookie, ioBoardAddress, +// maxDeviceReplyLen); // if (result != RETURN_OK) { // return result; // } @@ -780,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; } @@ -820,7 +817,7 @@ ReturnValue_t DeviceHandlerBase::enableReplyInReplyMap( iter = deviceReplyMap.find(command->first); } if (iter != deviceReplyMap.end()) { - DeviceReplyInfo * info = &(iter->second); + DeviceReplyInfo *info = &(iter->second); info->delayCycles = info->maxDelayCycles; info->command = command; command->second.expectedReplies = expectedReplies; @@ -846,9 +843,8 @@ ReturnValue_t DeviceHandlerBase::getStateOfSwitches(void) { ReturnValue_t result = getSwitches(&switches, &numberOfSwitches); if ((result == RETURN_OK) && (numberOfSwitches != 0)) { while (numberOfSwitches > 0) { - if (powerSwitcher-> getSwitchState(switches[numberOfSwitches - 1]) - == PowerSwitchIF::SWITCH_OFF) - { + if (powerSwitcher->getSwitchState(switches[numberOfSwitches - 1]) + == PowerSwitchIF::SWITCH_OFF) { return PowerSwitchIF::SWITCH_OFF; } numberOfSwitches--; @@ -890,10 +886,10 @@ ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode, if ((commandedMode == MODE_ON) && (mode == MODE_OFF) && (deviceThermalStatePoolId != PoolVariableIF::NO_PARAMETER)) { - DataSet mySet; - PoolVariable thermalState(deviceThermalStatePoolId, &mySet, + GlobDataSet mySet; + gp_uint8_t thermalState(deviceThermalStatePoolId, &mySet, PoolVariableIF::VAR_READ); - PoolVariable thermalRequest(deviceThermalRequestPoolId, &mySet, + gp_uint8_t thermalRequest(deviceThermalRequestPoolId, &mySet, PoolVariableIF::VAR_READ); mySet.read(); if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) { @@ -920,8 +916,8 @@ void DeviceHandlerBase::startTransition(Mode_t commandedMode, childTransitionDelay = getTransitionDelayMs(_MODE_START_UP, MODE_ON); triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); - DataSet mySet; - PoolVariable thermalRequest(deviceThermalRequestPoolId, + GlobDataSet mySet; + gp_int8_t thermalRequest(deviceThermalRequestPoolId, &mySet, PoolVariableIF::VAR_READ_WRITE); mySet.read(); if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) { @@ -1032,7 +1028,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)) { @@ -1054,21 +1049,19 @@ ReturnValue_t DeviceHandlerBase::handleDeviceHandlerMessage( } replyReturnvalueToCommand(RETURN_OK); return RETURN_OK; - case DeviceHandlerMessage::CMD_SWITCH_ADDRESS: - if (mode != MODE_OFF) { - replyReturnvalueToCommand(WRONG_MODE_FOR_COMMAND); - } else { - // rework in progress - result = RETURN_OK; - //result = switchCookieChannel( - // DeviceHandlerMessage::getIoBoardObjectId(message)); - if (result == RETURN_OK) { - replyReturnvalueToCommand(RETURN_OK); - } else { - replyReturnvalueToCommand(CANT_SWITCH_ADDRESS); - } - } - 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); @@ -1124,7 +1117,8 @@ void DeviceHandlerBase::handleDeviceTM(SerializeIF* data, // hiding of sender needed so the service will handle it as unexpected Data, no matter what state //(progress or completed) it is in - actionHelper.reportData(defaultRawReceiver, replyId, &wrapper, true); + actionHelper.reportData(defaultRawReceiver, replyId, &wrapper, + true); } } else { //unrequested/aperiodic replies @@ -1137,9 +1131,9 @@ void DeviceHandlerBase::handleDeviceTM(SerializeIF* data, true); } } -//Try to cast to DataSet and commit data. +//Try to cast to GlobDataSet and commit data. if (!neverInDataPool) { - DataSet* dataSet = dynamic_cast(data); + GlobDataSet* dataSet = dynamic_cast(data); if (dataSet != NULL) { dataSet->commit(PoolVariableIF::VALID); } @@ -1147,12 +1141,11 @@ void DeviceHandlerBase::handleDeviceTM(SerializeIF* data, } ReturnValue_t DeviceHandlerBase::executeAction(ActionId_t actionId, - MessageQueueId_t commandedBy, const uint8_t* data, size_t size) { + MessageQueueId_t commandedBy, const uint8_t* data, uint32_t size) { ReturnValue_t result = acceptExternalDeviceCommands(); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } - DeviceCommandMap::iterator iter = deviceCommandMap.find(actionId); if (iter == deviceCommandMap.end()) { result = COMMAND_NOT_SUPPORTED; @@ -1171,7 +1164,7 @@ ReturnValue_t DeviceHandlerBase::executeAction(ActionId_t actionId, } void DeviceHandlerBase::buildInternalCommand(void) { - // Neither Raw nor Direct could build a command +//Neither Raw nor Direct could build a command ReturnValue_t result = NOTHING_TO_SEND; DeviceCommandId_t deviceCommandId = NO_COMMAND_ID; if (mode == MODE_NORMAL) { @@ -1189,13 +1182,12 @@ void DeviceHandlerBase::buildInternalCommand(void) { } else { return; } - if (result == NOTHING_TO_SEND) { return; } if (result == RETURN_OK) { - DeviceCommandMap::iterator iter = - deviceCommandMap.find(deviceCommandId); + DeviceCommandMap::iterator iter = deviceCommandMap.find( + deviceCommandId); if (iter == deviceCommandMap.end()) { result = COMMAND_NOT_SUPPORTED; } else if (iter->second.isExecuting) { @@ -1210,7 +1202,6 @@ void DeviceHandlerBase::buildInternalCommand(void) { cookieInfo.state = COOKIE_WRITE_READY; } } - if (result != RETURN_OK) { triggerEvent(DEVICE_BUILDING_COMMAND_FAILED, result, deviceCommandId); } @@ -1285,8 +1276,8 @@ void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task_){ executingTask = task_; } -void DeviceHandlerBase::debugInterface(uint8_t positionTracker, object_id_t objectId, uint32_t parameter) { -} +// Default implementations empty. +void DeviceHandlerBase::debugInterface(uint8_t positionTracker, + object_id_t objectId, uint32_t parameter) {} -void DeviceHandlerBase::performOperationHook() { -} +void DeviceHandlerBase::performOperationHook() {} diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index 25ec75b9..379992b1 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -1,26 +1,23 @@ #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{ @@ -92,21 +89,22 @@ public: * The constructor passes the objectId to the SystemObject(). * * @param setObjectId the ObjectId to pass to the SystemObject() Constructor - * @param maxDeviceReplyLen the largest allowed reply size + * @param maxDeviceReplyLen the length the RMAP getRead call will be sent with * @param setDeviceSwitch the switch the device is connected to, - * for devices using two switches, overwrite getSwitches() - * @param deviceCommuncation Communcation Interface object which is - * used to implement communication functions + * 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(object_id_t setObjectId, object_id_t deviceCommunication, - CookieIF * comCookie_, uint8_t setDeviceSwitch, + CookieIF * comCookie, uint8_t setDeviceSwitch, uint32_t thermalStatePoolId = PoolVariableIF::NO_PARAMETER, uint32_t thermalRequestPoolId = PoolVariableIF::NO_PARAMETER, - FailureIsolationBase* fdirInstance = nullptr, size_t cmdQueueSize = 20); + FailureIsolationBase* fdirInstance = nullptr, + size_t cmdQueueSize = 20); /** * @brief This function is the device handler base core component and is @@ -213,12 +211,13 @@ protected: /** * 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. + * 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 + * #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 @@ -233,10 +232,13 @@ protected: * 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() + * @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. + * 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. * @@ -266,6 +268,63 @@ protected: 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 @@ -312,85 +371,83 @@ protected: virtual void fillCommandAndReplyMap() = 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 returnvalue of this function. - * - * @param start start of remaining buffer to be scanned - * @param len length of remaining buffer to be scanned - * @param[out] foundId the id of the data found in the buffer. - * @param[out] foundLen length of the data found. Is to be set in function, - * buffer is scanned at previous position + foundLen. - * @return - * - @c RETURN_OK a valid packet was found at @c start, @c foundLen is valid - * - @c RETURN_FAILED no reply could be found starting at @c start, - * implies @c foundLen is not valid, - * base class will call scanForReply() again with ++start - * - @c DeviceHandlerIF::INVALID_DATA a packet was found but it is invalid, - * e.g. checksum error, implies @c foundLen is valid, can be used to skip some bytes - * - @c DeviceHandlerIF::LENGTH_MISSMATCH @c len is invalid - * - @c DeviceHandlerIF::IGNORE_REPLY_DATA Ignore this specific part of the packet - * - @c DeviceHandlerIF::IGNORE_FULL_PACKET Ignore the packet - * - @c APERIODIC_REPLY if a valid reply is received that has not been - * requested by a command, but should be handled anyway - * (@see also fillCommandAndCookieMap() ) + * 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. */ - virtual ReturnValue_t scanForReply(const uint8_t *start, size_t remainingSize, - DeviceCommandId_t *foundId, size_t *foundLen) = 0; + ReturnValue_t insertInCommandAndReplyMap(DeviceCommandId_t deviceCommand, + uint16_t maxDelayCycles, size_t replyLen = 0, uint8_t periodic = 0, + bool hasDifferentReplyId = false, DeviceCommandId_t replyId = 0); /** - * @brief Interpret a reply from the device. - * @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 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 - * @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 + * @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. */ - virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, - const uint8_t *packet) = 0; + ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand, + uint16_t maxDelayCycles, size_t replyLen = 0, uint8_t periodic = 0); /** - * set all datapool variables that are update periodically in normal mode invalid - * - * Child classes should provide an implementation which sets all those variables invalid - * which are set periodically during any normal mode. + * @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. */ - virtual void setNormalDatapoolEntriesInvalid() = 0; + ReturnValue_t insertInCommandMap(DeviceCommandId_t deviceCommand); + /** + * @brief This is a helper method to facilitate updating entries + * in the reply map. + * @param deviceCommand Identifier of the reply to update. + * @param delayCycles The current number of delay cycles to wait. + * As stated in #fillCommandAndCookieMap, to disable periodic commands, + * this is set to zero. + * @param maxDelayCycles The maximum number of delay cycles the reply waits + * until it times out. By passing 0 the entry remains untouched. + * @param periodic Indicates if the command is periodic (i.e. it is sent + * by the device repeatedly without request) or not.Default is aperiodic (0). + * Warning: The setting always overrides the value that was entered in the map. + * @return - @c RETURN_OK when the command was successfully inserted, + * - @c RETURN_FAILED else. + */ + ReturnValue_t updateReplyMapEntry(DeviceCommandId_t deviceReply, + uint16_t delayCycles, uint16_t maxDelayCycles, + uint8_t periodic = 0); /** * @brief Can be implemented by child handler to * 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 + * @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); + 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) + * 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 @@ -408,40 +465,24 @@ protected: * @param[out] numberOfSwitches length of returned array * @return * - @c RETURN_OK if the parameters were set - * - @c NO_SWITCH or any other returnvalue if no switches exist + * - @c RETURN_FAILED if no switches exist */ virtual ReturnValue_t getSwitches(const uint8_t **switches, uint8_t *numberOfSwitches); /** - * Can be used to perform device specific periodic operations. - * This is called on the SEND_READ step of the performOperation() call + * @brief Hook function for child handlers which is called once per + * performOperation(). Default implementation is empty. */ virtual void performOperationHook(); - - /** - * The Returnvalues id of this class, required by HasReturnvaluesIF - */ - static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE; - public: /** * @param parentQueueId */ virtual void setParentQueue(MessageQueueId_t parentQueueId); - /** - * This function call handles the execution of external commands as required - * by the HasActionIF. - * @param actionId - * @param commandedBy - * @param data - * @param size - * @return - */ ReturnValue_t executeAction(ActionId_t actionId, - MessageQueueId_t commandedBy, const uint8_t* data, size_t size); - + MessageQueueId_t commandedBy, const uint8_t* data, uint32_t size); Mode_t getTransitionSourceMode() const; Submode_t getTransitionSourceSubMode() const; virtual void getMode(Mode_t *mode, Submode_t *submode); @@ -460,6 +501,28 @@ public: virtual MessageQueueId_t getCommandQueue(void) const; protected: + /** + * The Returnvalues id of this class, required by HasReturnvaluesIF + */ + static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE; + + /** + * These returnvalues can be returned from abstract functions + * to alter the behaviour of DHB.For error values, refer to + * DeviceHandlerIF.h returnvalues. + */ + static const ReturnValue_t INVALID_CHANNEL = MAKE_RETURN_CODE(4); + // Returnvalues for scanForReply() + static const ReturnValue_t APERIODIC_REPLY = MAKE_RETURN_CODE(5); //!< This is used to specify for replies from a device which are not replies to requests + static const ReturnValue_t IGNORE_REPLY_DATA = MAKE_RETURN_CODE(6); //!< Ignore parts of the received packet + static const ReturnValue_t IGNORE_FULL_PACKET = MAKE_RETURN_CODE(7); //!< Ignore full received packet + +// static const ReturnValue_t ONE_SWITCH = MAKE_RETURN_CODE(8); +// static const ReturnValue_t TWO_SWITCHES = MAKE_RETURN_CODE(9); + static const ReturnValue_t NO_SWITCH = MAKE_RETURN_CODE(10); + static const ReturnValue_t COMMAND_MAP_ERROR = MAKE_RETURN_CODE(11); + static const ReturnValue_t NOTHING_TO_SEND = MAKE_RETURN_CODE(12); + //Mode handling error Codes static const ReturnValue_t CHILD_TIMEOUT = MAKE_RETURN_CODE(0xE1); static const ReturnValue_t SWITCH_FAILED = MAKE_RETURN_CODE(0xE2); @@ -475,7 +538,7 @@ protected: /** * Size of the #rawPacket. */ - size_t rawPacketLen = 0; + uint32_t rawPacketLen = 0; /** * The mode the device handler is currently in. @@ -502,7 +565,7 @@ protected: * indicates either that all raw messages to and from the device should be sent to #theOneWhoWantsToReadRawTraffic * or that all device TM should be downlinked to #theOneWhoWantsToReadRawTraffic */ - enum WiretappingMode: uint8_t { + enum WiretappingMode { OFF = 0, RAW = 1, TM = 2 } wiretappingMode; @@ -546,18 +609,16 @@ protected: DeviceCommunicationIF *communicationInterface = nullptr; /** - * Cookie used for communication. This is passed to the communication - * interface. + * Cookie used for communication */ - CookieIF *comCookie; + CookieIF * comCookie = nullptr; 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. }; - typedef std::map DeviceCommandMap; - typedef DeviceCommandMap::iterator DeviceCommandIter; + using DeviceCommandMap = std::map ; /** * @brief Information about expected replies @@ -568,15 +629,12 @@ protected: 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. - //(Robin): This is a flag, isnt it? could we declare it bool? uint8_t always - // gives away the impression that this variable is more than a simple flag - // and true/false are also more explicit. uint8_t periodic; //!< if this is !=0, the delayCycles will not be reset to 0 but to maxDelayCycles DeviceCommandMap::iterator command; //!< The command that expects this reply. }; - typedef std::map DeviceReplyMap; - typedef DeviceReplyMap::iterator DeviceReplyIter; + using DeviceReplyMap = std::map ; + using DeviceReplyIter = DeviceReplyMap::iterator; /** * The MessageQueue used to receive device handler commands and to send replies. @@ -610,7 +668,7 @@ protected: * Optional Error code * Can be set in doStartUp(), doShutDown() and doTransition() to signal cause for Transition failure. */ - ReturnValue_t childTransitionFailure = RETURN_OK; + ReturnValue_t childTransitionFailure; uint32_t ignoreMissedRepliesCount = 0; //!< Counts if communication channel lost a reply, so some missed replys can be ignored. @@ -622,35 +680,13 @@ 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. static object_id_t rawDataReceiverId; //!< Object which receives RAW data by default. static object_id_t defaultFDIRParentId; //!< Object which may be the root cause of an identified fault. - - /** - * Set the device handler mode - * - * Sets #timeoutStart with every call. - * - * Sets #transitionTargetMode if necessary so transitional states can be entered from everywhere without breaking the state machine - * (which relies on a correct #transitionTargetMode). - * - * The submode is left unchanged. - * - * - * @param newMode - */ - void setMode(Mode_t newMode); - - /** - * @overload - * @param submode - */ - void setMode(Mode_t newMode, Submode_t submode); - /** * Helper function to report a missed reply * @@ -671,14 +707,30 @@ protected: void replyReturnvalueToCommand(ReturnValue_t status, uint32_t parameter = 0); - /** - * Send reply to a command, differentiate between raw command - * and normal command. - * @param status - * @param parameter - */ void replyToCommand(ReturnValue_t status, uint32_t parameter = 0); + /** + * Set the device handler mode + * + * Sets #timeoutStart with every call. + * + * Sets #transitionTargetMode if necessary so transitional states can be + * entered from everywhere without breaking the state machine + * (which relies on a correct #transitionTargetMode). + * + * The submode is left unchanged. + * + * + * @param newMode + */ + void setMode(Mode_t newMode); + + /** + * @overload + * @param submode + */ + void setMode(Mode_t newMode, Submode_t submode); + /** * Do the transition to the main modes (MODE_ON, MODE_NORMAL and MODE_RAW). * @@ -708,55 +760,6 @@ 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? * @@ -776,6 +779,7 @@ protected: * * @return The Rmap action to execute in this step */ + virtual CommunicationAction_t getComAction(); /** @@ -798,6 +802,14 @@ protected: */ virtual ReturnValue_t buildChildRawCommand(); + /** + * Returns the delay cycle count of a reply. + * A count != 0 indicates that the command is already executed. + * @param deviceCommand The command to look for + * @return The current delay count. If the command does not exist (should never happen) it returns 0. + */ + uint8_t getReplyDelayCycles(DeviceCommandId_t deviceCommand); + /** * Construct a command reply containing a raw reply. * @@ -861,6 +873,14 @@ protected: */ ReturnValue_t getStateOfSwitches(void); + /** + * set all datapool variables that are update periodically in normal mode invalid + * + * Child classes should provide an implementation which sets all those variables invalid + * which are set periodically during any normal mode. + */ + virtual void setNormalDatapoolEntriesInvalid() = 0; + /** * build a list of sids and pass it to the #hkSwitcher */ @@ -889,6 +909,7 @@ protected: virtual void startTransition(Mode_t mode, Submode_t submode); virtual void setToExternalControl(); virtual void announceMode(bool recursive); + virtual ReturnValue_t letChildHandleMessage(CommandMessage *message); /** @@ -954,13 +975,12 @@ protected: DeviceCommandMap deviceCommandMap; ActionHelper actionHelper; - private: /** * State a cookie is in. * - * Used to keep track of the state of the communication. + * Used to keep track of the state of the RMAP communication. */ enum CookieState_t { COOKIE_UNUSED, //!< The Cookie is unused @@ -1034,20 +1054,22 @@ private: * - checks whether commanded mode transitions are required and calls handleCommandedModeTransition() * - does the necessary action for the current mode or calls doChildStateMachine in modes @c MODE_TO_ON and @c MODE_TO_OFF * - actions that happen in transitions (eg setting a timeout) are handled in setMode() - * - Maybe export this into own class to increase modularity of software - * and reduce the massive class size ? */ void doStateMachine(void); void buildRawDeviceCommand(CommandMessage* message); void buildInternalCommand(void); +// /** +// * Send a reply with the current mode and submode. +// */ +// void announceMode(void); + /** * Decrement the counter for the timout of replies. * * This is called at the beginning of each cycle. It checks whether a reply has timed out (that means a reply was expected * but not received). - * In case the reply is periodic, the counter is simply set back to a specified value. */ void decrementDeviceReplyMap(void); @@ -1114,8 +1136,8 @@ private: * - @c RETURN_FAILED IPCStore is NULL * - the return value from the IPCStore if it was not @c RETURN_OK */ - ReturnValue_t getStorageData(store_address_t storageAddress, - uint8_t ** data, size_t * len); + ReturnValue_t getStorageData(store_address_t storageAddress, uint8_t **data, + uint32_t *len); /** * set all switches returned by getSwitches() @@ -1144,16 +1166,9 @@ private: * - @c RETURN_FAILED when cookies could not be changed, eg because the newChannel is not enabled * - @c returnvalues of RMAPChannelIF::isActive() */ - //ReturnValue_t switchCookieChannel(object_id_t newChannelId); + ReturnValue_t switchCookieChannel(object_id_t newChannelId); - /** - * Handle device handler messages (e.g. commands sent by PUS Service 2) - * @param message - * @return - */ ReturnValue_t handleDeviceHandlerMessage(CommandMessage *message); - - }; #endif /* DEVICEHANDLERBASE_H_ */ diff --git a/housekeeping/HasHkPoolParametersIF.h b/housekeeping/HasHkPoolParametersIF.h new file mode 100644 index 00000000..5ec9beef --- /dev/null +++ b/housekeeping/HasHkPoolParametersIF.h @@ -0,0 +1,32 @@ +#ifndef FRAMEWORK_DATAPOOL_HASHKPOOLPARAMETERSIF_H_ +#define FRAMEWORK_DATAPOOL_HASHKPOOLPARAMETERSIF_H_ +#include +#include +#include + +class HousekeepingManager; +/** + * @brief Type definition for local pool entries. + */ +using lp_id_t = uint32_t; +using LocalDataPoolMap = std::map; +using LocalDataPoolMapIter = LocalDataPoolMap::iterator; + +/** + * @brief Interface for the local housekeeping managers used by the device + * handler. + */ +class HasHkPoolParametersIF { +public: + virtual~ HasHkPoolParametersIF() {}; + + virtual MessageQueueId_t getCommandQueue() const = 0; + virtual ReturnValue_t initializeHousekeepingPoolEntries( + LocalDataPoolMap& localDataPoolMap) = 0; + virtual float setMinimalHkSamplingFrequency() = 0; + virtual HousekeepingManager* getHkManagerHandle() = 0; +}; + + + +#endif /* FRAMEWORK_DATAPOOL_HASHKPOOLPARAMETERSIF_H_ */ diff --git a/housekeeping/HousekeepingManager.cpp b/housekeeping/HousekeepingManager.cpp new file mode 100644 index 00000000..05df0ffc --- /dev/null +++ b/housekeeping/HousekeepingManager.cpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include + +HousekeepingManager::HousekeepingManager(HasHkPoolParametersIF* owner) { + //todo :: nullptr check owner. + if(owner == nullptr) { + sif::error << "HkManager: Invalid supplied owner!" << std::endl; + std::exit(0); + } + this->owner = owner; + mutex = MutexFactory::instance()->createMutex(); + owner->setMinimalHkSamplingFrequency(); +} + +HousekeepingManager::~HousekeepingManager() {} + +ReturnValue_t HousekeepingManager::initializeHousekeepingPoolEntriesOnce() { + if(not mapInitialized) { + ReturnValue_t result = owner->initializeHousekeepingPoolEntries(localDpMap); + if(result == HasReturnvaluesIF::RETURN_OK) { + mapInitialized = true; + } + return result; + } + sif::warning << "hk manager says no" << std::endl; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t HousekeepingManager::handleHousekeepingMessage( + CommandMessage *message) { + return HasReturnvaluesIF::RETURN_OK; +} + +MutexIF* HousekeepingManager::getMutexHandle() { + return mutex; +} + +void HousekeepingManager::setMinimalSamplingFrequency(float frequencySeconds) { + this->samplingFrequency = frequencySeconds; + +} + +void HousekeepingManager::generateHousekeepingPacket(DataSetIF *dataSet) { +} + +void HousekeepingManager::setHkPacketQueue(MessageQueueIF *msgQueue) { + this->hkPacketQueue = msgQueue; +} diff --git a/housekeeping/HousekeepingManager.h b/housekeeping/HousekeepingManager.h new file mode 100644 index 00000000..feec69fc --- /dev/null +++ b/housekeeping/HousekeepingManager.h @@ -0,0 +1,95 @@ +#ifndef FRAMEWORK_HK_HOUSEKEEPINGHELPER_H_ +#define FRAMEWORK_HK_HOUSEKEEPINGHELPER_H_ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + + +class HousekeepingManager { +public: + static constexpr float MINIMAL_SAMPLING_FREQUENCY = 0.2; + + HousekeepingManager(HasHkPoolParametersIF* owner); + virtual~ HousekeepingManager(); + + MutexIF* getMutexHandle(); + + // propably will just call respective local data set functions. + void generateHousekeepingPacket(DataSetIF* dataSet); + ReturnValue_t handleHousekeepingMessage(CommandMessage* message); + + /** + * Read a variable by supplying its local pool ID and assign the pool + * entry to the supplied PoolEntry pointer. The type of the pool entry + * is deduced automatically. This call is not thread-safe! + * @tparam T Type of the pool entry + * @param localPoolId Pool ID of the variable to read + * @param poolVar [out] Corresponding pool entry will be assigned to the + * supplied pointer. + * @return + */ + template + ReturnValue_t fetchPoolEntry(lp_id_t localPoolId, PoolEntry *poolEntry); + void setMinimalSamplingFrequency(float frequencySeconds); + + /** + * This function is used to fill the local data pool map with pool + * entries. The default implementation is empty. + * @param localDataPoolMap + * @return + */ + ReturnValue_t initializeHousekeepingPoolEntriesOnce(); + + void setHkPacketQueue(MessageQueueIF* msgQueue); +private: + //! this depends on the PST frequency.. maybe it would be better to just + //! set this manually with a global configuration value which is also + //! passed to the PST. Or force setting this in device handler. + float samplingFrequency = MINIMAL_SAMPLING_FREQUENCY; + + //! This is the map holding the actual data. Should only be initialized + //! once ! + bool mapInitialized = false; + LocalDataPoolMap localDpMap; + + //! Every housekeeping data manager has a mutex to protect access + //! to it's data pool. + MutexIF * mutex = nullptr; + + //! The class which actually owns the manager (and its datapool). + HasHkPoolParametersIF* owner = nullptr; + + //! Used for replies. + //! (maybe we dont need this, the sender can be retrieved from command + //! message..) + MessageQueueIF* hkReplyQueue = nullptr; + //! Used for HK packets, which are generated without requests. + MessageQueueIF* hkPacketQueue = nullptr; +}; + +template inline +ReturnValue_t HousekeepingManager::fetchPoolEntry(lp_id_t localPoolId, + PoolEntry *poolEntry) { + auto poolIter = localDpMap.find(localPoolId); + if (poolIter == localDpMap.end()) { + // todo: special returnvalue. + return HasReturnvaluesIF::RETURN_FAILED; + } + + poolEntry = dynamic_cast< PoolEntry* >(poolIter->second); + if(poolEntry == nullptr) { + // todo: special returnvalue. + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +#endif /* FRAMEWORK_HK_HOUSEKEEPINGHELPER_H_ */ diff --git a/housekeeping/HousekeepingMessage.cpp b/housekeeping/HousekeepingMessage.cpp new file mode 100644 index 00000000..65d87e9e --- /dev/null +++ b/housekeeping/HousekeepingMessage.cpp @@ -0,0 +1,10 @@ +#include + +void HousekeepingMessage::setAddHkReportStructMessage(CommandMessage *message, + set_t setId, store_address_t packet) { + message->setCommand(ADD_HK_REPORT_STRUCT); + message->setParameter(setId); + message->setParameter2(packet.raw); +} + +//void Housekeeping diff --git a/housekeeping/HousekeepingMessage.h b/housekeeping/HousekeepingMessage.h new file mode 100644 index 00000000..80dc83a6 --- /dev/null +++ b/housekeeping/HousekeepingMessage.h @@ -0,0 +1,87 @@ +#ifndef FRAMEWORK_HK_HOUSEKEEPINGMESSAGE_H_ +#define FRAMEWORK_HK_HOUSEKEEPINGMESSAGE_H_ +#include +#include +#include + +/** + * the sid consists of the target object ID and... something else I forgot. + * Propably a special HK id to distinguish multiple hk pool packages + * inside a handler or controller + */ +typedef uint32_t set_t; + +union sid_t { + static constexpr uint64_t INVALID_ADDRESS = std::numeric_limits::max(); + sid_t(): raw(INVALID_ADDRESS) {} + + struct { + object_id_t objectId ; + set_t hkId; + }; + /** + * Alternative access to the raw value. + */ + uint64_t raw; +}; +class HousekeepingMessage { +public: + /** + * No instances of a message shall be created, instead + * a CommandMessage instance is manipulated. + */ + HousekeepingMessage() = delete; + HousekeepingMessage(const HousekeepingMessage&) = delete; + HousekeepingMessage operator=(const HousekeepingMessage &) = delete; + + static constexpr uint8_t MESSAGE_ID = MESSAGE_TYPE::HOUSEKEEPING; + static constexpr Command_t ADD_HK_REPORT_STRUCT = + MAKE_COMMAND_ID(1); + static constexpr Command_t ADD_DIAGNOSTICS_REPORT_STRUCT = + MAKE_COMMAND_ID(2); + + static constexpr Command_t DELETE_HK_REPORT_STRUCT = MAKE_COMMAND_ID(3); + static constexpr Command_t DELETE_DIAGNOSTICS_REPORT_STRUCT = + MAKE_COMMAND_ID(4); + + static constexpr Command_t ENABLE_PERIODIC_HK_GENERATION = + MAKE_COMMAND_ID(5); + static constexpr Command_t DISABLE_PERIODIC_HK_REPORT_GENERATION = + MAKE_COMMAND_ID(6); + + static constexpr Command_t ENABLE_PERIODIC_DIAGNOSTICS_GENERATION = + MAKE_COMMAND_ID(7); + static constexpr Command_t DISABLE_PERIODIC_DIAGNOSTICS_GENERATION = + MAKE_COMMAND_ID(8); + + static constexpr Command_t REPORT_HK_REPORT_STRUCTURES = MAKE_COMMAND_ID(9); + static constexpr Command_t REPORT_DIAGNOSTICS_REPORT_STRUCTURES = + MAKE_COMMAND_ID(11); + + static constexpr Command_t HK_DEFINITIONS_REPORT = MAKE_COMMAND_ID(10); + static constexpr Command_t DIAGNOSTICS_DEFINITION_REPORT = MAKE_COMMAND_ID(12); + + static constexpr Command_t HK_REPORT = MAKE_COMMAND_ID(25); + static constexpr Command_t DIAGNOSTICS_REPORT = MAKE_COMMAND_ID(26); + + static constexpr Command_t GENERATE_ONE_PARAMETER_REPORT = + MAKE_COMMAND_ID(27); + static constexpr Command_t GENERATE_ONE_DIAGNOSTICS_REPORT = + MAKE_COMMAND_ID(28); + + static constexpr Command_t APPEND_PARAMETERS_TO_PARAMETER_REPORT_STRUCTURE = + MAKE_COMMAND_ID(29); + static constexpr Command_t APPEND_PARAMETERS_TO_DIAGNOSTICS_REPORT_STRUCTURE = + MAKE_COMMAND_ID(30); + + static constexpr Command_t MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL = + MAKE_COMMAND_ID(31); + static constexpr Command_t MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL = + MAKE_COMMAND_ID(32); + + static void setAddHkReportStructMessage(CommandMessage* message, + set_t setId, store_address_t packet); +}; + + +#endif /* FRAMEWORK_HK_HOUSEKEEPINGMESSAGE_H_ */ diff --git a/internalError/InternalErrorReporter.cpp b/internalError/InternalErrorReporter.cpp index 81c4a0e5..72ba434a 100644 --- a/internalError/InternalErrorReporter.cpp +++ b/internalError/InternalErrorReporter.cpp @@ -1,6 +1,6 @@ #include "InternalErrorReporter.h" -#include +#include #include #include @@ -20,13 +20,13 @@ InternalErrorReporter::~InternalErrorReporter() { ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) { - DataSet mySet; - PoolVariable queueHitsInPool(queuePoolId, &mySet, + GlobDataSet mySet; + gp_uint32_t queueHitsInPool(queuePoolId, &mySet, PoolVariableIF::VAR_READ_WRITE); - PoolVariable tmHitsInPool(tmPoolId, &mySet, + gp_uint32_t tmHitsInPool(tmPoolId, &mySet, PoolVariableIF::VAR_READ_WRITE); - PoolVariable storeHitsInPool(storePoolId, &mySet, + gp_uint32_t storeHitsInPool(storePoolId, &mySet, PoolVariableIF::VAR_READ_WRITE); mySet.read(); diff --git a/monitoring/MonitorBase.h b/monitoring/MonitorBase.h index 79622645..d66e956d 100644 --- a/monitoring/MonitorBase.h +++ b/monitoring/MonitorBase.h @@ -1,7 +1,7 @@ #ifndef MONITORBASE_H_ #define MONITORBASE_H_ -#include +#include #include #include #include @@ -48,7 +48,7 @@ public: protected: virtual ReturnValue_t fetchSample(T* sample) { - DataSet mySet; + GlobDataSet mySet; PIDReader parameter(this->parameterId, &mySet); mySet.read(); if (!parameter.isValid()) { diff --git a/power/Fuse.cpp b/power/Fuse.cpp index 04079bb0..eee91984 100644 --- a/power/Fuse.cpp +++ b/power/Fuse.cpp @@ -12,7 +12,7 @@ Fuse::Fuse(object_id_t fuseObjectId, uint8_t fuseId, VariableIds ids, SystemObject(fuseObjectId), oldFuseState(0), fuseId(fuseId), powerIF( NULL), currentLimit(fuseObjectId, 1, ids.pidCurrent, confirmationCount, maxCurrent, FUSE_CURRENT_HIGH), powerMonitor(fuseObjectId, 2, - DataPool::poolIdAndPositionToPid(ids.poolIdPower, 0), + GlobalDataPool::poolIdAndPositionToPid(ids.poolIdPower, 0), confirmationCount), set(), voltage(ids.pidVoltage, &set), current( ids.pidCurrent, &set), state(ids.pidState, &set), power( ids.poolIdPower, &set, PoolVariableIF::VAR_READ_WRITE), commandQueue( diff --git a/power/Fuse.h b/power/Fuse.h index aee03778..a826a125 100644 --- a/power/Fuse.h +++ b/power/Fuse.h @@ -1,7 +1,7 @@ #ifndef FUSE_H_ #define FUSE_H_ -#include +#include #include #include #include @@ -83,11 +83,11 @@ private: }; PowerMonitor powerMonitor; - DataSet set; + GlobDataSet set; PIDReader voltage; PIDReader current; PIDReader state; - db_float_t power; + gp_float_t power; MessageQueueIF* commandQueue; ParameterHelper parameterHelper; HealthHelper healthHelper; diff --git a/power/PowerSensor.h b/power/PowerSensor.h index 922560d0..566f93ca 100644 --- a/power/PowerSensor.h +++ b/power/PowerSensor.h @@ -1,7 +1,7 @@ #ifndef POWERSENSOR_H_ #define POWERSENSOR_H_ -#include +#include #include #include #include @@ -53,12 +53,12 @@ private: MessageQueueIF* commandQueue; ParameterHelper parameterHelper; HealthHelper healthHelper; - DataSet set; + GlobDataSet set; //Variables in PIDReader current; PIDReader voltage; //Variables out - db_float_t power; + gp_float_t power; static const uint8_t MODULE_ID_CURRENT = 1; static const uint8_t MODULE_ID_VOLTAGE = 2; diff --git a/thermal/CoreComponent.cpp b/thermal/CoreComponent.cpp index 304712ef..657e79cb 100644 --- a/thermal/CoreComponent.cpp +++ b/thermal/CoreComponent.cpp @@ -2,7 +2,7 @@ CoreComponent::CoreComponent(object_id_t reportingObjectId, uint8_t domainId, uint32_t temperaturePoolId, uint32_t targetStatePoolId, - uint32_t currentStatePoolId, uint32_t requestPoolId, DataSet* dataSet, + uint32_t currentStatePoolId, uint32_t requestPoolId, GlobDataSet* dataSet, AbstractTemperatureSensor* sensor, AbstractTemperatureSensor* firstRedundantSensor, AbstractTemperatureSensor* secondRedundantSensor, @@ -18,14 +18,14 @@ CoreComponent::CoreComponent(object_id_t reportingObjectId, uint8_t domainId, AbstractTemperatureSensor::ZERO_KELVIN_C), parameters( parameters), temperatureMonitor(reportingObjectId, domainId + 1, - DataPool::poolIdAndPositionToPid(temperaturePoolId, 0), + GlobalDataPool::poolIdAndPositionToPid(temperaturePoolId, 0), COMPONENT_TEMP_CONFIRMATION), domainId(domainId) { if (thermalModule != NULL) { thermalModule->registerComponent(this, priority); } //Set thermal state once, then leave to operator. - DataSet mySet; - PoolVariable writableTargetState(targetStatePoolId, &mySet, + GlobDataSet mySet; + gp_uint8_t writableTargetState(targetStatePoolId, &mySet, PoolVariableIF::VAR_WRITE); writableTargetState = initialTargetState; mySet.commit(PoolVariableIF::VALID); @@ -70,8 +70,8 @@ float CoreComponent::getLowerOpLimit() { } ReturnValue_t CoreComponent::setTargetState(int8_t newState) { - DataSet mySet; - PoolVariable writableTargetState(targetState.getDataPoolId(), + GlobDataSet mySet; + gp_uint8_t writableTargetState(targetState.getDataPoolId(), &mySet, PoolVariableIF::VAR_READ_WRITE); mySet.read(); if ((writableTargetState == STATE_REQUEST_OPERATIONAL) diff --git a/thermal/CoreComponent.h b/thermal/CoreComponent.h index da77c65b..0b87d889 100644 --- a/thermal/CoreComponent.h +++ b/thermal/CoreComponent.h @@ -1,7 +1,7 @@ #ifndef MISSION_CONTROLLERS_TCS_CORECOMPONENT_H_ #define MISSION_CONTROLLERS_TCS_CORECOMPONENT_H_ -#include +#include #include #include #include @@ -23,7 +23,7 @@ public: CoreComponent(object_id_t reportingObjectId, uint8_t domainId, uint32_t temperaturePoolId, uint32_t targetStatePoolId, uint32_t currentStatePoolId, - uint32_t requestPoolId, DataSet *dataSet, + uint32_t requestPoolId, GlobDataSet *dataSet, AbstractTemperatureSensor *sensor, AbstractTemperatureSensor *firstRedundantSensor, AbstractTemperatureSensor *secondRedundantSensor, @@ -58,10 +58,10 @@ protected: AbstractTemperatureSensor *secondRedundantSensor; ThermalModuleIF *thermalModule; - db_float_t temperature; - db_int8_t targetState; - db_int8_t currentState; - db_uint8_t heaterRequest; + gp_float_t temperature; + gp_int8_t targetState; + gp_int8_t currentState; + gp_uint8_t heaterRequest; bool isHeating; diff --git a/thermal/ThermalModule.h b/thermal/ThermalModule.h index e65560cd..65fa13a6 100644 --- a/thermal/ThermalModule.h +++ b/thermal/ThermalModule.h @@ -1,7 +1,7 @@ #ifndef THERMALMODULE_H_ #define THERMALMODULE_H_ -#include +#include #include #include #include @@ -23,10 +23,10 @@ public: }; ThermalModule(uint32_t moduleTemperaturePoolId, uint32_t currentStatePoolId, - uint32_t targetStatePoolId, DataSet *dataSet, Parameters parameters, + uint32_t targetStatePoolId, GlobDataSet *dataSet, Parameters parameters, RedundantHeater::Parameters heaterParameters); - ThermalModule(uint32_t moduleTemperaturePoolId, DataSet *dataSet); + ThermalModule(uint32_t moduleTemperaturePoolId, GlobDataSet *dataSet); virtual ~ThermalModule(); From 5b8a6e35dcc3e36715e2eaa39345744e3b2ebaef Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sun, 17 May 2020 13:37:50 +0200 Subject: [PATCH 10/94] renaming complete, pool in namespace --- datapool/PIDReader.h | 2 +- datapool/PoolRawAccess.cpp | 4 ++-- datapoolglob/DataPoolAdmin.cpp | 10 +++++----- datapoolglob/GlobalDataPool.h | 3 +++ datapoolglob/GlobalDataSet.cpp | 4 ++-- datapoolglob/GlobalPoolVariable.tpp | 4 ++-- datapoolglob/GlobalPoolVector.h | 4 ++-- devicehandlers/DeviceHandlerBase.cpp | 2 +- devicehandlers/DeviceHandlerBase.h | 3 ++- framework.mk | 2 ++ thermal/TemperatureSensor.h | 8 ++++---- thermal/ThermalComponent.cpp | 6 +++--- thermal/ThermalComponent.h | 2 +- thermal/ThermalModule.cpp | 8 ++++---- thermal/ThermalModule.h | 6 +++--- 15 files changed, 37 insertions(+), 31 deletions(-) diff --git a/datapool/PIDReader.h b/datapool/PIDReader.h index 3a815cee..f83fa3b9 100644 --- a/datapool/PIDReader.h +++ b/datapool/PIDReader.h @@ -17,7 +17,7 @@ protected: uint8_t valid; ReturnValue_t read() { uint8_t arrayIndex = GlobalDataPool::PIDToArrayIndex(parameterId); - PoolEntry* read_out = ::dataPool.getData( + PoolEntry* read_out = glob::dataPool.getData( GlobalDataPool::PIDToDataPoolId(parameterId), arrayIndex); if (read_out != NULL) { valid = read_out->valid; diff --git a/datapool/PoolRawAccess.cpp b/datapool/PoolRawAccess.cpp index 97bdc2b3..aea84612 100644 --- a/datapool/PoolRawAccess.cpp +++ b/datapool/PoolRawAccess.cpp @@ -19,7 +19,7 @@ PoolRawAccess::~PoolRawAccess() { } ReturnValue_t PoolRawAccess::read() { - PoolEntryIF* read_out = ::dataPool.getRawData(dataPoolId); + PoolEntryIF* read_out = glob::dataPool.getRawData(dataPoolId); if (read_out != NULL) { valid = read_out->getValid(); if (read_out->getSize() > arrayEntry) { @@ -52,7 +52,7 @@ ReturnValue_t PoolRawAccess::read() { } ReturnValue_t PoolRawAccess::commit() { - PoolEntryIF* write_back = ::dataPool.getRawData(dataPoolId); + PoolEntryIF* write_back = glob::dataPool.getRawData(dataPoolId); if ((write_back != NULL) && (readWriteMode != VAR_READ)) { write_back->setValid(valid); uint8_t array_position = arrayEntry * typeSize; diff --git a/datapoolglob/DataPoolAdmin.cpp b/datapoolglob/DataPoolAdmin.cpp index 59bd9f30..2779ce5c 100644 --- a/datapoolglob/DataPoolAdmin.cpp +++ b/datapoolglob/DataPoolAdmin.cpp @@ -38,7 +38,7 @@ ReturnValue_t DataPoolAdmin::executeAction(ActionId_t actionId, uint8_t valid = data[4]; - uint32_t poolId = ::dataPool.PIDToDataPoolId(address); + uint32_t poolId = glob::dataPool.PIDToDataPoolId(address); GlobDataSet mySet; PoolRawAccess variable(poolId, 0, &mySet, PoolVariableIF::VAR_READ_WRITE); @@ -90,8 +90,8 @@ void DataPoolAdmin::handleCommand() { ReturnValue_t DataPoolAdmin::handleMemoryLoad(uint32_t address, const uint8_t* data, uint32_t size, uint8_t** dataPointer) { - uint32_t poolId = ::dataPool.PIDToDataPoolId(address); - uint8_t arrayIndex = ::dataPool.PIDToArrayIndex(address); + uint32_t poolId = glob::dataPool.PIDToDataPoolId(address); + uint8_t arrayIndex = glob::dataPool.PIDToArrayIndex(address); GlobDataSet testSet; PoolRawAccess varToGetSize(poolId, arrayIndex, &testSet, PoolVariableIF::VAR_READ); @@ -129,8 +129,8 @@ ReturnValue_t DataPoolAdmin::handleMemoryLoad(uint32_t address, ReturnValue_t DataPoolAdmin::handleMemoryDump(uint32_t address, uint32_t size, uint8_t** dataPointer, uint8_t* copyHere) { - uint32_t poolId = ::dataPool.PIDToDataPoolId(address); - uint8_t arrayIndex = ::dataPool.PIDToArrayIndex(address); + uint32_t poolId = glob::dataPool.PIDToDataPoolId(address); + uint8_t arrayIndex = glob::dataPool.PIDToArrayIndex(address); GlobDataSet testSet; PoolRawAccess varToGetSize(poolId, arrayIndex, &testSet, PoolVariableIF::VAR_READ); diff --git a/datapoolglob/GlobalDataPool.h b/datapoolglob/GlobalDataPool.h index e0c086ad..42921a77 100644 --- a/datapoolglob/GlobalDataPool.h +++ b/datapoolglob/GlobalDataPool.h @@ -142,5 +142,8 @@ public: }; //We assume someone globally instantiates a DataPool. +namespace glob { extern GlobalDataPool dataPool; +} + #endif /* DATAPOOL_H_ */ diff --git a/datapoolglob/GlobalDataSet.cpp b/datapoolglob/GlobalDataSet.cpp index 7409dbbd..6e09a398 100644 --- a/datapoolglob/GlobalDataSet.cpp +++ b/datapoolglob/GlobalDataSet.cpp @@ -111,11 +111,11 @@ ReturnValue_t GlobDataSet::handleUnreadDatasetCommit() { } ReturnValue_t GlobDataSet::unlockDataPool() { - return ::dataPool.freeDataPoolLock(); + return glob::dataPool.freeDataPoolLock(); } ReturnValue_t GlobDataSet::lockDataPool() { - return ::dataPool.lockDataPool(); + return glob::dataPool.lockDataPool(); } ReturnValue_t GlobDataSet::serialize(uint8_t** buffer, size_t* size, diff --git a/datapoolglob/GlobalPoolVariable.tpp b/datapoolglob/GlobalPoolVariable.tpp index 287f06dd..21b648e6 100644 --- a/datapoolglob/GlobalPoolVariable.tpp +++ b/datapoolglob/GlobalPoolVariable.tpp @@ -13,7 +13,7 @@ inline GlobPoolVar::GlobPoolVar(uint32_t set_id, template inline ReturnValue_t GlobPoolVar::read() { - PoolEntry* read_out = ::dataPool.getData(dataPoolId, 1); + PoolEntry* read_out = glob::dataPool.getData(dataPoolId, 1); if (read_out != NULL) { valid = read_out->valid; value = *(read_out->address); @@ -29,7 +29,7 @@ inline ReturnValue_t GlobPoolVar::read() { template inline ReturnValue_t GlobPoolVar::commit() { - PoolEntry* write_back = ::dataPool.getData(dataPoolId, 1); + PoolEntry* write_back = glob::dataPool.getData(dataPoolId, 1); if ((write_back != NULL) && (readWriteMode != VAR_READ)) { write_back->valid = valid; *(write_back->address) = value; diff --git a/datapoolglob/GlobalPoolVector.h b/datapoolglob/GlobalPoolVector.h index 47381aec..8d2488ea 100644 --- a/datapoolglob/GlobalPoolVector.h +++ b/datapoolglob/GlobalPoolVector.h @@ -50,7 +50,7 @@ protected: * The operation does NOT provide any mutual exclusive protection by itself. */ ReturnValue_t read() { - PoolEntry* read_out = ::dataPool.getData(this->dataPoolId, + PoolEntry* read_out = glob::dataPool.getData(this->dataPoolId, vector_size); if (read_out != NULL) { this->valid = read_out->valid; @@ -74,7 +74,7 @@ protected: * */ ReturnValue_t commit() { - PoolEntry* write_back = ::dataPool.getData(this->dataPoolId, + PoolEntry* write_back = glob::dataPool.getData(this->dataPoolId, vector_size); if ((write_back != NULL) && (this->readWriteMode != VAR_READ)) { write_back->valid = valid; diff --git a/devicehandlers/DeviceHandlerBase.cpp b/devicehandlers/DeviceHandlerBase.cpp index 0549bd45..740bb383 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/devicehandlers/DeviceHandlerBase.cpp @@ -1141,7 +1141,7 @@ void DeviceHandlerBase::handleDeviceTM(SerializeIF* data, } ReturnValue_t DeviceHandlerBase::executeAction(ActionId_t actionId, - MessageQueueId_t commandedBy, const uint8_t* data, uint32_t size) { + MessageQueueId_t commandedBy, const uint8_t* data, size_t size) { ReturnValue_t result = acceptExternalDeviceCommands(); if (result != HasReturnvaluesIF::RETURN_OK) { return result; diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index 379992b1..82cf6cab 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -482,7 +482,8 @@ public: virtual void setParentQueue(MessageQueueId_t parentQueueId); ReturnValue_t executeAction(ActionId_t actionId, - MessageQueueId_t commandedBy, const uint8_t* data, uint32_t size); + MessageQueueId_t commandedBy, const uint8_t* data, + size_t size) override; Mode_t getTransitionSourceMode() const; Submode_t getTransitionSourceSubMode() const; virtual void getMode(Mode_t *mode, Submode_t *submode); diff --git a/framework.mk b/framework.mk index 6f64b720..cb3e4f22 100644 --- a/framework.mk +++ b/framework.mk @@ -8,6 +8,8 @@ CXXSRC += $(wildcard $(FRAMEWORK_PATH)/controller/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/coordinates/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datalinklayer/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapool/*.cpp) +CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapoolglob/*.cpp) +CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapoollocal/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/devicehandlers/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/events/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/events/eventmatching/*.cpp) diff --git a/thermal/TemperatureSensor.h b/thermal/TemperatureSensor.h index 96dedc99..cd277784 100644 --- a/thermal/TemperatureSensor.h +++ b/thermal/TemperatureSensor.h @@ -2,7 +2,7 @@ #define TEMPERATURESENSOR_H_ #include -#include +#include #include /** @@ -68,12 +68,12 @@ public: TemperatureSensor(object_id_t setObjectid, inputType *inputValue, PoolVariableIF *poolVariable, uint8_t vectorIndex, uint32_t datapoolId, Parameters parameters = {0, 0, 0, 0, 0, 0}, - DataSet *outputSet = NULL, ThermalModuleIF *thermalModule = NULL) : + GlobDataSet *outputSet = NULL, ThermalModuleIF *thermalModule = NULL) : AbstractTemperatureSensor(setObjectid, thermalModule), parameters(parameters), inputValue(inputValue), poolVariable(poolVariable), outputTemperature(datapoolId, outputSet, PoolVariableIF::VAR_WRITE), sensorMonitor(setObjectid, DOMAIN_ID_SENSOR, - DataPool::poolIdAndPositionToPid(poolVariable->getDataPoolId(), vectorIndex), + GlobalDataPool::poolIdAndPositionToPid(poolVariable->getDataPoolId(), vectorIndex), DEFAULT_CONFIRMATION_COUNT, parameters.lowerLimit, parameters.upperLimit, TEMP_SENSOR_LOW, TEMP_SENSOR_HIGH), oldTemperature(20), uptimeOfOldTemperature( { INVALID_TEMPERATURE, 0 }) { @@ -111,7 +111,7 @@ protected: PoolVariableIF *poolVariable; - PoolVariable outputTemperature; + gp_float_t outputTemperature; LimitMonitor sensorMonitor; diff --git a/thermal/ThermalComponent.cpp b/thermal/ThermalComponent.cpp index ffe7ba7b..d7024662 100644 --- a/thermal/ThermalComponent.cpp +++ b/thermal/ThermalComponent.cpp @@ -3,7 +3,7 @@ ThermalComponent::ThermalComponent(object_id_t reportingObjectId, uint8_t domainId, uint32_t temperaturePoolId, uint32_t targetStatePoolId, uint32_t currentStatePoolId, - uint32_t requestPoolId, DataSet* dataSet, + uint32_t requestPoolId, GlobDataSet* dataSet, AbstractTemperatureSensor* sensor, AbstractTemperatureSensor* firstRedundantSensor, AbstractTemperatureSensor* secondRedundantSensor, @@ -22,8 +22,8 @@ ThermalComponent::~ThermalComponent() { } ReturnValue_t ThermalComponent::setTargetState(int8_t newState) { - DataSet mySet; - PoolVariable writableTargetState(targetState.getDataPoolId(), + GlobDataSet mySet; + gp_int8_t writableTargetState(targetState.getDataPoolId(), &mySet, PoolVariableIF::VAR_READ_WRITE); mySet.read(); if ((writableTargetState == STATE_REQUEST_OPERATIONAL) diff --git a/thermal/ThermalComponent.h b/thermal/ThermalComponent.h index afe9aa10..195f03b1 100644 --- a/thermal/ThermalComponent.h +++ b/thermal/ThermalComponent.h @@ -44,7 +44,7 @@ public: */ ThermalComponent(object_id_t reportingObjectId, uint8_t domainId, uint32_t temperaturePoolId, uint32_t targetStatePoolId, uint32_t currentStatePoolId, uint32_t requestPoolId, - DataSet *dataSet, AbstractTemperatureSensor *sensor, + GlobDataSet *dataSet, AbstractTemperatureSensor *sensor, AbstractTemperatureSensor *firstRedundantSensor, AbstractTemperatureSensor *secondRedundantSensor, ThermalModuleIF *thermalModule, Parameters parameters, diff --git a/thermal/ThermalModule.cpp b/thermal/ThermalModule.cpp index 24a4c90d..9dc1f237 100644 --- a/thermal/ThermalModule.cpp +++ b/thermal/ThermalModule.cpp @@ -6,7 +6,7 @@ ThermalModule::ThermalModule(uint32_t moduleTemperaturePoolId, uint32_t currentStatePoolId, uint32_t targetStatePoolId, - DataSet *dataSet, Parameters parameters, + GlobDataSet *dataSet, Parameters parameters, RedundantHeater::Parameters heaterParameters) : oldStrategy(ACTIVE_SINGLE), survivalTargetTemp(0), targetTemp(0), heating( false), parameters(parameters), moduleTemperature( @@ -16,7 +16,7 @@ ThermalModule::ThermalModule(uint32_t moduleTemperaturePoolId, heater = new RedundantHeater(heaterParameters); } -ThermalModule::ThermalModule(uint32_t moduleTemperaturePoolId, DataSet* dataSet) : +ThermalModule::ThermalModule(uint32_t moduleTemperaturePoolId, GlobDataSet* dataSet) : oldStrategy(ACTIVE_SINGLE), survivalTargetTemp(0), targetTemp(0), heating( false), parameters( { 0, 0 }), moduleTemperature( moduleTemperaturePoolId, dataSet, PoolVariableIF::VAR_WRITE), heater( @@ -250,8 +250,8 @@ bool ThermalModule::calculateModuleHeaterRequestAndSetModuleStatus( } void ThermalModule::setHeating(bool on) { - DataSet mySet; - PoolVariable writableTargetState(targetState.getDataPoolId(), + GlobDataSet mySet; + gp_int8_t writableTargetState(targetState.getDataPoolId(), &mySet, PoolVariableIF::VAR_WRITE); if (on) { writableTargetState = STATE_REQUEST_HEATING; diff --git a/thermal/ThermalModule.h b/thermal/ThermalModule.h index 65fa13a6..b9e8d8b8 100644 --- a/thermal/ThermalModule.h +++ b/thermal/ThermalModule.h @@ -70,12 +70,12 @@ protected: Parameters parameters; - db_float_t moduleTemperature; + gp_float_t moduleTemperature; RedundantHeater *heater; - db_int8_t currentState; - db_int8_t targetState; + gp_int8_t currentState; + gp_int8_t targetState; std::list sensors; std::list components; From 9056ad36ed69575e499376558839d0bc044ca4d3 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sun, 17 May 2020 14:13:31 +0200 Subject: [PATCH 11/94] object manager better output --- datapoolglob/GlobalPoolVector.h | 3 +++ objectmanager/ObjectManager.cpp | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/datapoolglob/GlobalPoolVector.h b/datapoolglob/GlobalPoolVector.h index 8d2488ea..63536934 100644 --- a/datapoolglob/GlobalPoolVector.h +++ b/datapoolglob/GlobalPoolVector.h @@ -220,4 +220,7 @@ public: } }; +template +using gp_vec_t = GlobPoolVector; + #endif /* POOLVECTOR_H_ */ diff --git a/objectmanager/ObjectManager.cpp b/objectmanager/ObjectManager.cpp index 2f99e1a5..1912715d 100644 --- a/objectmanager/ObjectManager.cpp +++ b/objectmanager/ObjectManager.cpp @@ -67,9 +67,9 @@ void ObjectManager::initialize() { return_value = it->second->initialize(); if ( return_value != RETURN_OK ) { object_id_t var = it->first; - sif::error << "Object " << std::hex << (int) var - << " failed to initialize with code 0x" << return_value - << std::dec << std::endl; + sif::error << "Object 0x" << std::hex << std::setw(8) << + std::setfill('0')<< var << " failed to initialize " << + "with code 0x" << return_value << std::dec << std::endl; error_count++; } } From e9a4056deb17756f70973d6f383182fbabdf90b2 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sun, 17 May 2020 15:19:24 +0200 Subject: [PATCH 12/94] added DHB cookie init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (why was that never a problem beofre????) ¯\_(ツ)_/¯ --- devicehandlers/DeviceHandlerBase.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/devicehandlers/DeviceHandlerBase.cpp b/devicehandlers/DeviceHandlerBase.cpp index 740bb383..22224c12 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/devicehandlers/DeviceHandlerBase.cpp @@ -23,8 +23,9 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, size_t cmdQueueSize) : SystemObject(setObjectId), mode(MODE_OFF), submode(SUBMODE_NONE), wiretappingMode(OFF), storedRawData(StorageManagerIF::INVALID_ADDRESS), - deviceCommunicationId(deviceCommunication), deviceThermalStatePoolId( - thermalStatePoolId),deviceThermalRequestPoolId(thermalRequestPoolId), + 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), From 0467b6a1bf60481b74850096c60fc09304bb7ee6 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sun, 17 May 2020 17:53:18 +0200 Subject: [PATCH 13/94] slight DHB improvements --- devicehandlers/DeviceHandlerBase.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/devicehandlers/DeviceHandlerBase.cpp b/devicehandlers/DeviceHandlerBase.cpp index 16be66fa..23ec1f18 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/devicehandlers/DeviceHandlerBase.cpp @@ -12,6 +12,8 @@ #include #include +#include + object_id_t DeviceHandlerBase::powerSwitcherId = 0; object_id_t DeviceHandlerBase::rawDataReceiverId = 0; object_id_t DeviceHandlerBase::defaultFDIRParentId = 0; @@ -37,6 +39,12 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, CommandMessage::MAX_MESSAGE_SIZE); cookieInfo.state = COOKIE_UNUSED; insertInCommandMap(RAW_COMMAND_ID); + 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 " + "passing a dummy cookie instead!" << std::endl; + } if (this->fdirInstance == nullptr) { this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, defaultFDIRParentId); @@ -44,7 +52,6 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, } DeviceHandlerBase::~DeviceHandlerBase() { - //communicationInterface->close(cookie); delete comCookie; if (defaultFDIRUsed) { delete fdirInstance; @@ -646,8 +653,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; } @@ -658,7 +665,7 @@ 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; } From 8b1fef730dcb4cd4f21c3f90121b1c6a74758f63 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sun, 17 May 2020 18:02:58 +0200 Subject: [PATCH 14/94] resolved conflict --- devicehandlers/DeviceHandlerBase.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index c48fbe5e..454f0751 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -614,11 +614,7 @@ protected: /** * Cookie used for communication */ -<<<<<<< HEAD - CookieIF * comCookie = nullptr; -======= CookieIF * comCookie; ->>>>>>> mueller_framework struct DeviceCommandInfo { bool isExecuting; //!< Indicates if the command is already executing. From 9da0b0b2b299b7abeb9b73dd8fdb624942de996c Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sun, 17 May 2020 22:16:25 +0200 Subject: [PATCH 15/94] glob pool vec implementation in tpp file --- datapoolglob/GlobalPoolVector.h | 270 ++++++++++++------------------ datapoolglob/GlobalPoolVector.tpp | 83 +++++++++ 2 files changed, 186 insertions(+), 167 deletions(-) create mode 100644 datapoolglob/GlobalPoolVector.tpp diff --git a/datapoolglob/GlobalPoolVector.h b/datapoolglob/GlobalPoolVector.h index 63536934..d55fd777 100644 --- a/datapoolglob/GlobalPoolVector.h +++ b/datapoolglob/GlobalPoolVector.h @@ -1,5 +1,5 @@ -#ifndef POOLVECTOR_H_ -#define POOLVECTOR_H_ +#ifndef GLOBALPOOLVECTOR_H_ +#define GLOBALPOOLVECTOR_H_ #include #include @@ -8,139 +8,79 @@ #include /** - * \brief This is the access class for array-type data pool entries. + * @brief This is the access class for array-type data pool entries. * - * \details To ensure safe usage of the data pool, operation is not done directly on the data pool - * entries, but on local copies. This class provides simple type- and length-safe access - * to vector-style data pool entries (i.e. entries with length > 1). - * The class can be instantiated as read-write and read only. - * It provides a commit-and-roll-back semantic, which means that no array entry in - * the data pool is changed until the commit call is executed. - * There are two template parameters: - * \tparam T This template parameter specifies the data type of an array entry. Currently, all - * plain data types are supported, but in principle any type is possible. - * \tparam vector_size This template parameter specifies the vector size of this entry. - * Using a template parameter for this is not perfect, but avoids dynamic memory allocation. - * \ingroup data_pool + * @details + * To ensure safe usage of the data pool, operation is not done directly on the + * data pool entries, but on local copies. This class provides simple type- + * and length-safe access to vector-style data pool entries (i.e. entries with + * length > 1). The class can be instantiated as read-write and read only. + * + * It provides a commit-and-roll-back semantic, which means that no array + * entry in the data pool is changed until the commit call is executed. + * There are two template parameters: + * @tparam T + * This template parameter specifies the data type of an array entry. Currently, + * all plain data types are supported, but in principle any type is possible. + * @tparam vector_size + * This template parameter specifies the vector size of this entry. Using a + * template parameter for this is not perfect, but avoids + * dynamic memory allocation. + * @ingroup data_pool */ -template +template class GlobPoolVector: public PoolVariableIF { -private: - /** - * \brief To access the correct data pool entry on read and commit calls, the data pool id - * is stored. - */ - uint32_t dataPoolId; - /** - * \brief The valid information as it was stored in the data pool is copied to this attribute. - */ - uint8_t valid; - /** - * \brief The information whether the class is read-write or read-only is stored here. - */ - ReadWriteMode_t readWriteMode; - -protected: - /** - * \brief This is a call to read the array's values from the global data pool. - * \details When executed, this operation tries to fetch the pool entry with matching - * data pool id from the global data pool and copies all array values and the valid - * information to its local attributes. In case of a failure (wrong type, size or - * pool id not found), the variable is set to zero and invalid. - * The operation does NOT provide any mutual exclusive protection by itself. - */ - ReturnValue_t read() { - PoolEntry* read_out = glob::dataPool.getData(this->dataPoolId, - vector_size); - if (read_out != NULL) { - this->valid = read_out->valid; - memcpy(this->value, read_out->address, read_out->getByteSize()); - - return HasReturnvaluesIF::RETURN_OK; - - } else { - memset(this->value, 0, vector_size * sizeof(T)); - sif::error << "PoolVector: read of DP Variable 0x" << std::hex - << dataPoolId << std::dec << " failed." << std::endl; - this->valid = INVALID; - return HasReturnvaluesIF::RETURN_FAILED; - } - } - /** - * \brief The commit call copies the array values back to the data pool. - * \details It checks type and size, as well as if the variable is writable. If so, - * the value is copied and the valid flag is automatically set to "valid". - * The operation does NOT provide any mutual exclusive protection by itself. - * - */ - ReturnValue_t commit() { - PoolEntry* write_back = glob::dataPool.getData(this->dataPoolId, - vector_size); - if ((write_back != NULL) && (this->readWriteMode != VAR_READ)) { - write_back->valid = valid; - memcpy(write_back->address, this->value, write_back->getByteSize()); - return HasReturnvaluesIF::RETURN_OK; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } - } public: /** - * \brief This is the local copy of the data pool entry. - * \detials The user can work on this attribute - * just like he would on a local array of this type. - */ - T value[vector_size]; - /** - * \brief In the constructor, the variable can register itself in a DataSet (if not NULL is - * passed). - * \details It DOES NOT fetch the current value from the data pool, but sets the value - * attribute to default (0). The value is fetched within the read() operation. - * \param set_id This is the id in the global data pool this instance of the access class - * corresponds to. - * \param dataSet The data set in which the variable shall register itself. If NULL, - * the variable is not registered. - * \param setWritable If this flag is set to true, changes in the value attribute can be - * written back to the data pool, otherwise not. + * @brief In the constructor, the variable can register itself in a + * DataSet (if no nullptr is passed). + * @details + * It DOES NOT fetch the current value from the data pool, but sets the + * value attribute to default (0). The value is fetched within the + * read() operation. + * @param set_id + * This is the id in the global data pool this instance of the access + * class corresponds to. + * @param dataSet + * The data set in which the variable shall register itself. If nullptr, + * the variable is not registered. + * @param setWritable + * If this flag is set to true, changes in the value attribute can be + * written back to the data pool, otherwise not. */ GlobPoolVector(uint32_t set_id, DataSetIF* set, - ReadWriteMode_t setReadWriteMode) : - dataPoolId(set_id), valid(false), readWriteMode(setReadWriteMode) { - memset(this->value, 0, vector_size * sizeof(T)); - if (set != NULL) { - set->registerVariable(this); - } - } + ReadWriteMode_t setReadWriteMode); + /** - * Copy ctor to copy classes containing Pool Variables. + * @brief This is the local copy of the data pool entry. + * @details The user can work on this attribute + * just like he would on a local array of this type. */ -// PoolVector(const PoolVector& rhs) { -// PoolVector temp(rhs.dataPoolId, rhs.) -// memcpy(value, rhs.value, sizeof(T)*vector_size); -// } + T value[vectorSize]; /** - * \brief The classes destructor is empty. - * \details If commit() was not called, the local value is + * @brief The classes destructor is empty. + * @details If commit() was not called, the local value is * discarded and not written back to the data pool. */ - ~GlobPoolVector() { - } - ; + ~GlobPoolVector() {}; /** - * \brief The operation returns the number of array entries in this variable. + * @brief The operation returns the number of array entries + * in this variable. */ uint8_t getSize() { - return vector_size; + return vectorSize; } /** - * \brief This operation returns the data pool id of the variable. + * @brief This operation returns the data pool id of the variable. */ uint32_t getDataPoolId() const { return dataPoolId; } /** - * This operation sets the data pool id of the variable. - * The method is necessary to set id's of data pool member variables with bad initialization. + * @brief This operation sets the data pool id of the variable. + * @details + * The method is necessary to set id's of data pool member variables + * with bad initialization. */ void setDataPoolId(uint32_t poolId) { dataPoolId = poolId; @@ -151,9 +91,10 @@ public: ReadWriteMode_t getReadWriteMode() const { return readWriteMode; } - ; + + /** - * \brief With this call, the valid information of the variable is returned. + * @brief With this call, the valid information of the variable is returned. */ bool isValid() const { if (valid != INVALID) @@ -161,65 +102,60 @@ public: else return false; } + void setValid(uint8_t valid) {this->valid = valid;} + uint8_t getValid() {return valid;} - void setValid(uint8_t valid) { - this->valid = valid; - } - - uint8_t getValid() { - return valid; - } - - T &operator [](int i) { - return value[i]; - } - - const T &operator [](int i) const { - return value[i]; - } - - GlobPoolVector &operator=( - GlobPoolVector newPoolVector) { - - for (uint16_t i = 0; i < vector_size; i++) { - this->value[i] = newPoolVector.value[i]; - } - return *this; - } + T &operator [](int i) {return value[i];} + const T &operator [](int i) const {return value[i];} virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - const size_t max_size, bool bigEndian) const override { - uint16_t i; - ReturnValue_t result; - for (i = 0; i < vector_size; i++) { - result = SerializeAdapter::serialize(&(value[i]), buffer, size, - max_size, bigEndian); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - } - return result; - } - - virtual size_t getSerializedSize() const override { - return vector_size * SerializeAdapter::getSerializedSize(value); - } + const size_t max_size, bool bigEndian) const override; + virtual size_t getSerializedSize() const override; virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - bool bigEndian) override { - uint16_t i; - ReturnValue_t result; - for (i = 0; i < vector_size; i++) { - result = SerializeAdapter::deSerialize(&(value[i]), buffer, size, - bigEndian); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - } - return result; - } + bool bigEndian) override; +protected: + /** + * @brief This is a call to read the array's values + * from the global data pool. + * @details + * When executed, this operation tries to fetch the pool entry with matching + * data pool id from the global data pool and copies all array values + * and the valid information to its local attributes. + * In case of a failure (wrong type, size or pool id not found), the + * variable is set to zero and invalid. The operation does NOT provide + * any mutual exclusive protection by itself. + */ + ReturnValue_t read(); + + /** + * @brief The commit call copies the array values back to the data pool. + * @details + * It checks type and size, as well as if the variable is writable. If so, + * the value is copied and the valid flag is automatically set to "valid". + * The operation does NOT provide any mutual exclusive protection by itself. + */ + ReturnValue_t commit(); +private: + /** + * @brief To access the correct data pool entry on read and commit calls, + * the data pool id is stored. + */ + uint32_t dataPoolId; + /** + * @brief The valid information as it was stored in the data pool + * is copied to this attribute. + */ + uint8_t valid; + /** + * @brief The information whether the class is read-write or + * read-only is stored here. + */ + ReadWriteMode_t readWriteMode; }; +#include + template using gp_vec_t = GlobPoolVector; diff --git a/datapoolglob/GlobalPoolVector.tpp b/datapoolglob/GlobalPoolVector.tpp new file mode 100644 index 00000000..0b43191b --- /dev/null +++ b/datapoolglob/GlobalPoolVector.tpp @@ -0,0 +1,83 @@ +#ifndef GLOBALPOOLVECTOR_TPP_ +#define GLOBALPOOLVECTOR_TPP_ + + +template +inline GlobPoolVector::GlobPoolVector(uint32_t set_id, + DataSetIF* set, ReadWriteMode_t setReadWriteMode) : + dataPoolId(set_id), valid(false), readWriteMode(setReadWriteMode) { + memset(this->value, 0, vectorSize * sizeof(T)); + if (set != nullptr) { + set->registerVariable(this); + } +} + +template +inline ReturnValue_t GlobPoolVector::read() { + PoolEntry* read_out = glob::dataPool.getData(this->dataPoolId, + vectorSize); + if (read_out != nullptr) { + this->valid = read_out->valid; + memcpy(this->value, read_out->address, read_out->getByteSize()); + + return HasReturnvaluesIF::RETURN_OK; + + } else { + memset(this->value, 0, vectorSize * sizeof(T)); + sif::error << "PoolVector: Read of DP Variable 0x" << std::hex + << std::setw(8) << std::setfill('0') << dataPoolId << + std::dec << " failed." << std::endl; + this->valid = INVALID; + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +template +inline ReturnValue_t GlobPoolVector::commit() { + PoolEntry* writeBack = glob::dataPool.getData(this->dataPoolId, + vectorSize); + if ((writeBack != nullptr) && (this->readWriteMode != VAR_READ)) { + writeBack->valid = valid; + memcpy(writeBack->address, this->value, writeBack->getByteSize()); + return HasReturnvaluesIF::RETURN_OK; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +template +inline ReturnValue_t GlobPoolVector::serialize(uint8_t** buffer, + size_t* size, const size_t max_size, bool bigEndian) const { + uint16_t i; + ReturnValue_t result; + for (i = 0; i < vectorSize; i++) { + result = SerializeAdapter::serialize(&(value[i]), buffer, size, + max_size, bigEndian); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return result; +} + +template +inline size_t GlobPoolVector::getSerializedSize() const { + return vectorSize * SerializeAdapter::getSerializedSize(value); +} + +template +inline ReturnValue_t GlobPoolVector::deSerialize( + const uint8_t** buffer, size_t* size, bool bigEndian) { + uint16_t i; + ReturnValue_t result; + for (i = 0; i < vectorSize; i++) { + result = SerializeAdapter::deSerialize(&(value[i]), buffer, size, + bigEndian); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return result; +} + +#endif From 71f1722b886d002a0b8fe550771ee1ed4cde1cc3 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sun, 17 May 2020 22:20:54 +0200 Subject: [PATCH 16/94] removed old poolVar file --- datapool/PoolVariable.h | 294 ------------------------ datapoolglob/GlobalPoolVariable.h | 4 +- datapoolglob/GlobalPoolVariable.tpp | 5 +- datapoolglob/GlobalPoolVector.h | 1 - devicehandlers/DeviceHandlerBase.cpp | 2 +- internalError/InternalErrorReporter.cpp | 2 +- power/PowerSensor.h | 2 +- thermal/CoreComponent.h | 2 +- thermal/ThermalModule.h | 2 +- 9 files changed, 11 insertions(+), 303 deletions(-) delete mode 100644 datapool/PoolVariable.h diff --git a/datapool/PoolVariable.h b/datapool/PoolVariable.h deleted file mode 100644 index f5442a25..00000000 --- a/datapool/PoolVariable.h +++ /dev/null @@ -1,294 +0,0 @@ -/* - * \file PoolVariable.h - * - * \brief This file contains the PoolVariable class, which locally represents a non-array data pool variable. - * - * \date 10/17/2012 - * - * \author Bastian Baetz - */ - -#ifndef POOLVARIABLE_H_ -#define POOLVARIABLE_H_ - -#include -#include -#include -#include -#include - -template class PoolVarList; - -/** - * \brief This is the access class for non-array data pool entries. - * - * \details To ensure safe usage of the data pool, operation is not done directly on the data pool - * entries, but on local copies. This class provides simple type-safe access to single - * data pool entries (i.e. entries with length = 1). - * The class can be instantiated as read-write and read only. - * It provides a commit-and-roll-back semantic, which means that the variable's value in - * the data pool is not changed until the commit call is executed. - * \tparam T The template parameter sets the type of the variable. Currently, all plain data types - * are supported, but in principle any type is possible. - * \ingroup data_pool - */ -template -class PoolVariable: public PoolVariableIF { - template friend class PoolVarList; -protected: - /** - * \brief To access the correct data pool entry on read and commit calls, the data pool id - * is stored. - */ - uint32_t dataPoolId; - /** - * \brief The valid information as it was stored in the data pool is copied to this attribute. - */ - uint8_t valid; - /** - * \brief The information whether the class is read-write or read-only is stored here. - */ - ReadWriteMode_t readWriteMode; - /** - * \brief This is a call to read the value from the global data pool. - * \details When executed, this operation tries to fetch the pool entry with matching - * data pool id from the global data pool and copies the value and the valid - * information to its local attributes. In case of a failure (wrong type or - * pool id not found), the variable is set to zero and invalid. - * The operation does NOT provide any mutual exclusive protection by itself. - */ - ReturnValue_t read() { - PoolEntry* read_out = ::dataPool.getData(dataPoolId, 1); - if (read_out != NULL) { - valid = read_out->valid; - value = *(read_out->address); - return HasReturnvaluesIF::RETURN_OK; - } else { - value = 0; - valid = false; - sif::error << "PoolVariable: read of DP Variable 0x" << std::hex - << dataPoolId << std::dec << " failed." << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - } - /** - * \brief The commit call writes back the variable's value to the data pool. - * \details It checks type and size, as well as if the variable is writable. If so, - * the value is copied and the valid flag is automatically set to "valid". - * The operation does NOT provide any mutual exclusive protection by itself. - * - */ - ReturnValue_t commit() { - PoolEntry* write_back = ::dataPool.getData(dataPoolId, 1); - if ((write_back != NULL) && (readWriteMode != VAR_READ)) { - write_back->valid = valid; - *(write_back->address) = value; - return HasReturnvaluesIF::RETURN_OK; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - /** - * Empty ctor for List initialization - */ - PoolVariable() : - dataPoolId(PoolVariableIF::NO_PARAMETER), valid( - PoolVariableIF::INVALID), readWriteMode(VAR_READ), value(0) { - - } -public: - /** - * \brief This is the local copy of the data pool entry. - * \details The user can work on this attribute - * just like he would on a simple local variable. - */ - T value; - /** - * \brief In the constructor, the variable can register itself in a DataSet (if not NULL is - * passed). - * \details It DOES NOT fetch the current value from the data pool, but sets the value - * attribute to default (0). The value is fetched within the read() operation. - * \param set_id This is the id in the global data pool this instance of the access class - * corresponds to. - * \param dataSet The data set in which the variable shall register itself. If NULL, - * the variable is not registered. - * \param setReadWriteMode - */ - PoolVariable(uint32_t set_id, DataSetIF* dataSet, - ReadWriteMode_t setReadWriteMode) : - dataPoolId(set_id), valid(PoolVariableIF::INVALID), readWriteMode( - setReadWriteMode), value(0) { - if (dataSet != NULL) { - dataSet->registerVariable(this); - } - } - /** - * Copy ctor to copy classes containing Pool Variables. - */ - PoolVariable(const PoolVariable& rhs) : - dataPoolId(rhs.dataPoolId), valid(rhs.valid), readWriteMode( - rhs.readWriteMode), value(rhs.value) { - } - - /** - * \brief The classes destructor is empty. - * \details If commit() was not called, the local value is - * discarded and not written back to the data pool. - */ - ~PoolVariable() { - - } - /** - * \brief This operation returns the data pool id of the variable. - */ - uint32_t getDataPoolId() const { - return dataPoolId; - } - /** - * This operation sets the data pool id of the variable. - * The method is necessary to set id's of data pool member variables with bad initialization. - */ - void setDataPoolId(uint32_t poolId) { - dataPoolId = poolId; - } - /** - * This method returns if the variable is write-only, read-write or read-only. - */ - ReadWriteMode_t getReadWriteMode() const { - return readWriteMode; - } - /** - * \brief With this call, the valid information of the variable is returned. - */ - bool isValid() const { - if (valid) - return true; - else - return false; - } - - uint8_t getValid() { - return valid; - } - - void setValid(uint8_t valid) { - this->valid = valid; - } - - operator T() { - return value; - } - - operator T() const { - return value; - } - - PoolVariable &operator=(T newValue) { - value = newValue; - return *this; - } - - PoolVariable &operator=(PoolVariable newPoolVariable) { - value = newPoolVariable.value; - return *this; - } - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - const size_t max_size, bool bigEndian) const { - return SerializeAdapter::serialize(&value, buffer, size, max_size, - bigEndian); - } - - virtual size_t getSerializedSize() const { - return SerializeAdapter::getSerializedSize(&value); - } - - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - bool bigEndian) { - return SerializeAdapter::deSerialize(&value, buffer, size, bigEndian); - } -}; - -typedef PoolVariable db_uint8_t; -typedef PoolVariable db_uint16_t; -typedef PoolVariable db_uint32_t; -typedef PoolVariable db_int8_t; -typedef PoolVariable db_int16_t; -typedef PoolVariable db_int32_t; -typedef PoolVariable db_bool_t; -typedef PoolVariable db_float_t; -typedef PoolVariable db_double_t; -//Alternative (but I thing this is not as useful: code duplication, differences too small): - -//template -//class PoolReader : public PoolVariableIF { -//private: -// uint32_t parameter_id; -// uint8_t valid; -//public: -// T value; -// PoolReader( uint32_t set_id, DataSetIF* set ) : parameter_id(set_id), valid(false), value(0) { -// set->registerVariable( this ); -// } -// -// ~PoolReader() {}; -// -// uint8_t commit() { -// return HasReturnvaluesIF::RETURN_OK; -// } -// -// uint8_t read() { -// PoolEntry* read_out = ::dataPool.getData( parameter_id, 1 ); -// if ( read_out != NULL ) { -// valid = read_out->valid; -// value = *(read_out->address); -// return HasReturnvaluesIF::RETURN_OK; -// } else { -// value = 0; -// valid = false; -// return CHECKOUT_FAILED; -// } -// } -// uint32_t getParameterId() { return parameter_id; } -// bool isWritable() { return false; }; -// bool isValid() { if (valid) return true; else return false; } -//}; -// -//template -//class PoolWriter : public PoolVariableIF { -//private: -// uint32_t parameter_id; -//public: -// T value; -// PoolWriter( uint32_t set_id, DataSetIF* set ) : parameter_id(set_id), value(0) { -// set->registerVariable( this ); -// } -// -// ~PoolWriter() {}; -// -// uint8_t commit() { -// PoolEntry* write_back = ::dataPool.getData( parameter_id, 1 ); -// if ( write_back != NULL ) { -// write_back->valid = true; -// *(write_back->address) = value; -// return HasReturnvaluesIF::RETURN_OK; -// } else { -// return CHECKOUT_FAILED; -// } -// } -// uint8_t read() { -// PoolEntry* read_out = ::dataPool.getData( parameter_id, 1 ); -// if ( read_out != NULL ) { -// value = *(read_out->address); -// return HasReturnvaluesIF::RETURN_OK; -// } else { -// value = 0; -// return CHECKOUT_FAILED; -// } -// } -// uint32_t getParameterId() { return parameter_id; } -// bool isWritable() { return true; }; -// bool isValid() { return false; } -//}; - -#endif /* POOLVARIABLE_H_ */ diff --git a/datapoolglob/GlobalPoolVariable.h b/datapoolglob/GlobalPoolVariable.h index 9f80492b..eee9afc1 100644 --- a/datapoolglob/GlobalPoolVariable.h +++ b/datapoolglob/GlobalPoolVariable.h @@ -1,5 +1,5 @@ -#ifndef POOLVARIABLE_H_ -#define POOLVARIABLE_H_ +#ifndef GLOBALPOOLVARIABLE_H_ +#define GLOBALPOOLVARIABLE_H_ #include #include diff --git a/datapoolglob/GlobalPoolVariable.tpp b/datapoolglob/GlobalPoolVariable.tpp index 21b648e6..d55ea4e0 100644 --- a/datapoolglob/GlobalPoolVariable.tpp +++ b/datapoolglob/GlobalPoolVariable.tpp @@ -1,4 +1,5 @@ -#pragma once +#ifndef GLOBALPOOLVARIABLE_TPP_ +#define GLOBALPOOLVARIABLE_TPP_ template inline GlobPoolVar::GlobPoolVar(uint32_t set_id, @@ -82,3 +83,5 @@ template inline void GlobPoolVar::setValid(uint8_t valid) { this->valid = valid; } + +#endif diff --git a/datapoolglob/GlobalPoolVector.h b/datapoolglob/GlobalPoolVector.h index d55fd777..24303457 100644 --- a/datapoolglob/GlobalPoolVector.h +++ b/datapoolglob/GlobalPoolVector.h @@ -111,7 +111,6 @@ public: virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, const size_t max_size, bool bigEndian) const override; virtual size_t getSerializedSize() const override; - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, bool bigEndian) override; protected: diff --git a/devicehandlers/DeviceHandlerBase.cpp b/devicehandlers/DeviceHandlerBase.cpp index 5bd4c56e..f46f854b 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/devicehandlers/DeviceHandlerBase.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include #include diff --git a/internalError/InternalErrorReporter.cpp b/internalError/InternalErrorReporter.cpp index 72ba434a..a1e96695 100644 --- a/internalError/InternalErrorReporter.cpp +++ b/internalError/InternalErrorReporter.cpp @@ -1,7 +1,7 @@ #include "InternalErrorReporter.h" #include -#include +#include #include #include diff --git a/power/PowerSensor.h b/power/PowerSensor.h index 566f93ca..f94088a8 100644 --- a/power/PowerSensor.h +++ b/power/PowerSensor.h @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include #include diff --git a/thermal/CoreComponent.h b/thermal/CoreComponent.h index 0b87d889..a0736c71 100644 --- a/thermal/CoreComponent.h +++ b/thermal/CoreComponent.h @@ -2,7 +2,7 @@ #define MISSION_CONTROLLERS_TCS_CORECOMPONENT_H_ #include -#include +#include #include #include #include diff --git a/thermal/ThermalModule.h b/thermal/ThermalModule.h index b9e8d8b8..21414f15 100644 --- a/thermal/ThermalModule.h +++ b/thermal/ThermalModule.h @@ -2,7 +2,7 @@ #define THERMALMODULE_H_ #include -#include +#include #include #include #include "ThermalModuleIF.h" From 1d28e1398ea927a74a0fc492e4db468122d41afa Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sun, 17 May 2020 23:41:28 +0200 Subject: [PATCH 17/94] DataSetBase class finished --- datapool/DataSetBase.cpp | 148 ++++++++++++++++++++++++ datapool/DataSetBase.h | 135 +++++++++++++++++++++ datapool/DataSetIF.h | 21 ++++ datapool/PIDReader.h | 2 +- datapool/PoolRawAccess.cpp | 2 +- datapool/PoolRawAccessHelper.cpp | 6 +- datapool/PoolRawAccessHelper.h | 1 + datapool/PoolVariableIF.h | 1 + datapoolglob/DataPoolAdmin.cpp | 4 +- datapoolglob/GlobalDataSet.cpp | 140 ++-------------------- datapoolglob/GlobalDataSet.h | 126 +++----------------- datapoolglob/GlobalPoolVariable.h | 2 +- devicehandlers/DeviceHandlerBase.cpp | 2 +- internalError/InternalErrorReporter.cpp | 2 +- power/Fuse.h | 1 + thermal/TemperatureSensor.h | 1 + 16 files changed, 344 insertions(+), 250 deletions(-) create mode 100644 datapool/DataSetBase.cpp create mode 100644 datapool/DataSetBase.h diff --git a/datapool/DataSetBase.cpp b/datapool/DataSetBase.cpp new file mode 100644 index 00000000..6ff2fc83 --- /dev/null +++ b/datapool/DataSetBase.cpp @@ -0,0 +1,148 @@ +#include +#include + +DataSetBase::DataSetBase() { + for (uint8_t count = 0; count < DATA_SET_MAX_SIZE; count++) { + registeredVariables[count] = nullptr; + } +} + +DataSetBase::~DataSetBase() {} + +ReturnValue_t DataSetBase::registerVariable( + PoolVariableIF *variable) { + if (state != States::DATA_SET_UNINITIALISED) { + sif::error << "DataSet::registerVariable: " + "Call made in wrong position." << std::endl; + return DataSetIF::DATA_SET_UNINITIALISED; + } + if (variable == nullptr) { + sif::error << "DataSet::registerVariable: " + "Pool variable is nullptr." << std::endl; + return DataSetIF::POOL_VAR_NULL; + } + if (fillCount >= DATA_SET_MAX_SIZE) { + sif::error << "DataSet::registerVariable: " + "DataSet is full." << std::endl; + return DataSetIF::DATA_SET_FULL; + } + registeredVariables[fillCount] = variable; + fillCount++; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t DataSetBase::read() { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + if (state == States::DATA_SET_UNINITIALISED) { + lockDataPool(); + for (uint16_t count = 0; count < fillCount; count++) { + if (registeredVariables[count]->getReadWriteMode() + != PoolVariableIF::VAR_WRITE + && registeredVariables[count]->getDataPoolId() + != PoolVariableIF::NO_PARAMETER) { + ReturnValue_t status = registeredVariables[count]->read(); + if (status != HasReturnvaluesIF::RETURN_OK) { + result = INVALID_PARAMETER_DEFINITION; + break; + } + } + } + state = States::DATA_SET_WAS_READ; + unlockDataPool(); + } + else { + sif::error << "DataSet::read(): " + "Call made in wrong position." << std::endl; + result = SET_WAS_ALREADY_READ; + } + return result; +} + +ReturnValue_t DataSetBase::commit() { + if (state == States::DATA_SET_WAS_READ) { + handleAlreadyReadDatasetCommit(); + return HasReturnvaluesIF::RETURN_OK; + } + else { + return handleUnreadDatasetCommit(); + } +} + +ReturnValue_t DataSetBase::lockDataPool() { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t DataSetBase::unlockDataPool() { + return HasReturnvaluesIF::RETURN_FAILED; +} + +void DataSetBase::handleAlreadyReadDatasetCommit() { + lockDataPool(); + for (uint16_t count = 0; count < fillCount; count++) { + if (registeredVariables[count]->getReadWriteMode() + != PoolVariableIF::VAR_READ + && registeredVariables[count]->getDataPoolId() + != PoolVariableIF::NO_PARAMETER) { + registeredVariables[count]->commit(); + } + } + state = States::DATA_SET_UNINITIALISED; + unlockDataPool(); +} + +ReturnValue_t DataSetBase::handleUnreadDatasetCommit() { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + lockDataPool(); + for (uint16_t count = 0; count < fillCount; count++) { + if (registeredVariables[count]->getReadWriteMode() + == PoolVariableIF::VAR_WRITE + && registeredVariables[count]->getDataPoolId() + != PoolVariableIF::NO_PARAMETER) { + registeredVariables[count]->commit(); + } else if (registeredVariables[count]->getDataPoolId() + != PoolVariableIF::NO_PARAMETER) { + if (result != COMMITING_WITHOUT_READING) { + sif::error << "DataSet::commit(): commit-without-read call made " + "with non write-only variable." << std::endl; + result = COMMITING_WITHOUT_READING; + } + } + } + state = States::DATA_SET_UNINITIALISED; + unlockDataPool(); + return result; +} + +ReturnValue_t DataSetBase::serialize(uint8_t** buffer, size_t* size, + const size_t maxSize, bool bigEndian) const { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + for (uint16_t count = 0; count < fillCount; count++) { + result = registeredVariables[count]->serialize(buffer, size, maxSize, + bigEndian); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return result; +} + +ReturnValue_t DataSetBase::deSerialize(const uint8_t** buffer, size_t* size, + bool bigEndian) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + for (uint16_t count = 0; count < fillCount; count++) { + result = registeredVariables[count]->deSerialize(buffer, size, + bigEndian); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return result; +} + +size_t DataSetBase::getSerializedSize() const { + uint32_t size = 0; + for (uint16_t count = 0; count < fillCount; count++) { + size += registeredVariables[count]->getSerializedSize(); + } + return size; +} diff --git a/datapool/DataSetBase.h b/datapool/DataSetBase.h new file mode 100644 index 00000000..6b468c11 --- /dev/null +++ b/datapool/DataSetBase.h @@ -0,0 +1,135 @@ +#ifndef FRAMEWORK_DATAPOOL_DATASETBASE_H_ +#define FRAMEWORK_DATAPOOL_DATASETBASE_H_ +#include +#include + +/** + * @brief The DataSetBase class manages a set of locally checked out variables. + * @details + * This class manages a list, where a set of local variables (or pool variables) + * are registered. They are checked-out (i.e. their values are looked + * up and copied) with the read call. After the user finishes working with the + * pool variables, he can write back all variable values to the pool with + * the commit call. The data set manages locking and freeing the data pool, + * to ensure that all values are read and written back at once. + * + * An internal state manages usage of this class. Variables may only be + * registered before the read call is made, and the commit call only + * after the read call. + * + * If pool variables are writable and not committed until destruction + * of the set, the DataSet class automatically sets the valid flag in the + * data pool to invalid (without) changing the variable's value. + * + * The base class lockDataPo + * @author Bastian Baetz + * @ingroup data_pool + */ +class DataSetBase: public DataSetIF, + public SerializeIF, + public HasReturnvaluesIF { +public: + + /** + * @brief Creates an empty dataset. Use registerVariable or + * supply a pointer to this dataset to PoolVariable + * initializations to register pool variables. + */ + DataSetBase(); + virtual~ DataSetBase(); + + /** + * @brief The read call initializes reading out all registered variables. + * @details + * It iterates through the list of registered variables and calls all read() + * functions of the registered pool variables (which read out their values + * from the data pool) which are not write-only. + * In case of an error (e.g. a wrong data type, or an invalid data pool id), + * the operation is aborted and @c INVALID_PARAMETER_DEFINITION returned. + * + * The data pool is locked during the whole read operation and + * freed afterwards.The state changes to "was written" after this operation. + * @return - @c RETURN_OK if all variables were read successfully. + * - @c INVALID_PARAMETER_DEFINITION if PID, size or type of the + * requested variable is invalid. + * - @c SET_WAS_ALREADY_READ if read() is called twice without calling + * commit() in between + */ + virtual ReturnValue_t read(); + + /** + * @brief The commit call initializes writing back the registered variables. + * @details + * It iterates through the list of registered variables and calls the + * commit() method of the remaining registered variables (which write back + * their values to the pool). + * + * The data pool is locked during the whole commit operation and + * freed afterwards. The state changes to "was committed" after this operation. + * + * If the set does contain at least one variable which is not write-only commit() + * can only be called after read(). If the set only contains variables which are + * write only, commit() can be called without a preceding read() call. + * @return - @c RETURN_OK if all variables were read successfully. + * - @c COMMITING_WITHOUT_READING if set was not read yet and + * contains non write-only variables + */ + virtual ReturnValue_t commit(); + + /* DataSetIF implementation */ + virtual ReturnValue_t registerVariable( PoolVariableIF* variable) override; + /** + * Provides the means to lock the underlying data structure to ensure + * thread-safety. Default implementation is empty + * @return Always returns -@c RETURN_OK + */ + virtual ReturnValue_t lockDataPool() override; + /** + * Provides the means to unlock the underlying data structure to ensure + * thread-safety. Default implementation is empty + * @return Always returns -@c RETURN_OK + */ + virtual ReturnValue_t unlockDataPool() override; + + /* SerializeIF implementations */ + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t maxSize, bool bigEndian) const override; + virtual size_t getSerializedSize() const override; + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + bool bigEndian) override; + + //SHOULDDO we could use a linked list of datapool variables + //!< This definition sets the maximum number of variables to + //! register in one DataSet. + static const uint8_t DATA_SET_MAX_SIZE = 63; +protected: + + /** + * @brief The fill_count attribute ensures that the variables + * register in the correct array position and that the maximum + * number of variables is not exceeded. + */ + uint16_t fillCount = 0; + /** + * States of the seet. + */ + enum class States { + DATA_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED + DATA_SET_WAS_READ //!< DATA_SET_WAS_READ + }; + /** + * @brief state manages the internal state of the data set, + * which is important e.g. for the behavior on destruction. + */ + States state = States::DATA_SET_UNINITIALISED; + + /** + * @brief This array represents all pool variables registered in this set. + */ + PoolVariableIF* registeredVariables[DATA_SET_MAX_SIZE] = { }; + + void handleAlreadyReadDatasetCommit(); + ReturnValue_t handleUnreadDatasetCommit(); +}; + +#endif /* FRAMEWORK_DATAPOOL_DATASETBASE_H_ */ diff --git a/datapool/DataSetIF.h b/datapool/DataSetIF.h index 4e351416..d9cc4966 100644 --- a/datapool/DataSetIF.h +++ b/datapool/DataSetIF.h @@ -16,6 +16,17 @@ class PoolVariableIF; */ class DataSetIF { public: + static constexpr uint8_t INTERFACE_ID = CLASS_ID::DATA_SET_CLASS; + static constexpr ReturnValue_t INVALID_PARAMETER_DEFINITION = + MAKE_RETURN_CODE( 0x01 ); + static constexpr ReturnValue_t SET_WAS_ALREADY_READ = MAKE_RETURN_CODE( 0x02 ); + static constexpr ReturnValue_t COMMITING_WITHOUT_READING = + MAKE_RETURN_CODE(0x03); + + static constexpr ReturnValue_t DATA_SET_UNINITIALISED = MAKE_RETURN_CODE( 0x04 ); + static constexpr ReturnValue_t DATA_SET_FULL = MAKE_RETURN_CODE( 0x05 ); + static constexpr ReturnValue_t POOL_VAR_NULL = MAKE_RETURN_CODE( 0x06 ); + /** * @brief This is an empty virtual destructor, * as it is proposed for C++ interfaces. @@ -29,7 +40,17 @@ public: */ virtual ReturnValue_t registerVariable( PoolVariableIF* variable ) = 0; + /** + * @brief Most underlying data structures will have a pool like structure + * and will require a lock and unlock mechanism to ensure + * thread-safety + * @return Lock operation result + */ virtual ReturnValue_t lockDataPool() = 0; + /** + * @brief Unlock call corresponding to the lock call. + * @return Unlock operation result + */ virtual ReturnValue_t unlockDataPool() = 0; }; diff --git a/datapool/PIDReader.h b/datapool/PIDReader.h index f83fa3b9..11206611 100644 --- a/datapool/PIDReader.h +++ b/datapool/PIDReader.h @@ -1,9 +1,9 @@ #ifndef PIDREADER_H_ #define PIDREADER_H_ #include +#include #include #include -#include #include #include diff --git a/datapool/PoolRawAccess.cpp b/datapool/PoolRawAccess.cpp index aea84612..c0bd3c09 100644 --- a/datapool/PoolRawAccess.cpp +++ b/datapool/PoolRawAccess.cpp @@ -1,6 +1,6 @@ +#include #include #include -#include #include #include diff --git a/datapool/PoolRawAccessHelper.cpp b/datapool/PoolRawAccessHelper.cpp index cf02b20a..6e289303 100644 --- a/datapool/PoolRawAccessHelper.cpp +++ b/datapool/PoolRawAccessHelper.cpp @@ -6,10 +6,12 @@ */ #include +#include +#include +#include #include - -#include +#include PoolRawAccessHelper::PoolRawAccessHelper(uint32_t * poolIdBuffer_, uint8_t numberOfParameters_): diff --git a/datapool/PoolRawAccessHelper.h b/datapool/PoolRawAccessHelper.h index ab881a5f..f2434241 100644 --- a/datapool/PoolRawAccessHelper.h +++ b/datapool/PoolRawAccessHelper.h @@ -7,6 +7,7 @@ #ifndef FRAMEWORK_DATAPOOL_POOLRAWACCESSHELPER_H_ #define FRAMEWORK_DATAPOOL_POOLRAWACCESSHELPER_H_ +#include #include #include diff --git a/datapool/PoolVariableIF.h b/datapool/PoolVariableIF.h index 9935ef75..0cbc18c5 100644 --- a/datapool/PoolVariableIF.h +++ b/datapool/PoolVariableIF.h @@ -18,6 +18,7 @@ * @ingroup data_pool */ class PoolVariableIF : public SerializeIF { + friend class DataSetBase; friend class GlobDataSet; friend class LocalDataSet; protected: diff --git a/datapoolglob/DataPoolAdmin.cpp b/datapoolglob/DataPoolAdmin.cpp index 2779ce5c..f32ff567 100644 --- a/datapoolglob/DataPoolAdmin.cpp +++ b/datapoolglob/DataPoolAdmin.cpp @@ -1,5 +1,7 @@ -#include #include +#include +#include +#include #include #include #include diff --git a/datapoolglob/GlobalDataSet.cpp b/datapoolglob/GlobalDataSet.cpp index 6e09a398..503d068e 100644 --- a/datapoolglob/GlobalDataSet.cpp +++ b/datapoolglob/GlobalDataSet.cpp @@ -1,61 +1,12 @@ -#include #include +#include #include -GlobDataSet::GlobDataSet() : - fill_count(0), state(DATA_SET_UNINITIALISED) { - for (unsigned count = 0; count < DATA_SET_MAX_SIZE; count++) { - registeredVariables[count] = nullptr; - } -} +GlobDataSet::GlobDataSet(): DataSetBase() {} -GlobDataSet::~GlobDataSet() { - //Don't do anything with your variables, they are dead already! - // (Destructor is already called) -} - -ReturnValue_t GlobDataSet::registerVariable(PoolVariableIF* variable) { - if (state != DATA_SET_UNINITIALISED) { - sif::error << "DataSet::registerVariable: Call made in wrong position." << std::endl; - return DATA_SET_UNINITIALISED; - } - if (variable == nullptr) { - sif::error << "DataSet::registerVariable: Pool variable is nullptr." << std::endl; - return POOL_VAR_NULL; - } - if (fill_count >= DATA_SET_MAX_SIZE) { - sif::error << "DataSet::registerVariable: DataSet is full." << std::endl; - return DATA_SET_FULL; - } - registeredVariables[fill_count] = variable; - fill_count++; - return RETURN_OK; -} - -ReturnValue_t GlobDataSet::read() { - ReturnValue_t result = RETURN_OK; - if (state == DATA_SET_UNINITIALISED) { - lockDataPool(); - for (uint16_t count = 0; count < fill_count; count++) { - if (registeredVariables[count]->getReadWriteMode() - != PoolVariableIF::VAR_WRITE - && registeredVariables[count]->getDataPoolId() - != PoolVariableIF::NO_PARAMETER) { - ReturnValue_t status = registeredVariables[count]->read(); - if (status != RETURN_OK) { - result = INVALID_PARAMETER_DEFINITION; - break; - } - } - } - state = DATA_SET_WAS_READ; - unlockDataPool(); - } else { - sif::error << "DataSet::read(): Call made in wrong position." << std::endl; - result = SET_WAS_ALREADY_READ; - } - return result; -} +// Don't do anything with your variables, they are dead already! +// (Destructor is already called) +GlobDataSet::~GlobDataSet() {} ReturnValue_t GlobDataSet::commit(bool valid) { setEntriesValid(valid); @@ -64,50 +15,7 @@ ReturnValue_t GlobDataSet::commit(bool valid) { } ReturnValue_t GlobDataSet::commit() { - if (state == DATA_SET_WAS_READ) { - handleAlreadyReadDatasetCommit(); - return RETURN_OK; - } - else { - return handleUnreadDatasetCommit(); - } -} - -void GlobDataSet::handleAlreadyReadDatasetCommit() { - lockDataPool(); - for (uint16_t count = 0; count < fill_count; count++) { - if (registeredVariables[count]->getReadWriteMode() - != PoolVariableIF::VAR_READ - && registeredVariables[count]->getDataPoolId() - != PoolVariableIF::NO_PARAMETER) { - registeredVariables[count]->commit(); - } - } - state = DATA_SET_UNINITIALISED; - unlockDataPool(); -} - -ReturnValue_t GlobDataSet::handleUnreadDatasetCommit() { - ReturnValue_t result = RETURN_OK; - lockDataPool(); - for (uint16_t count = 0; count < fill_count; count++) { - if (registeredVariables[count]->getReadWriteMode() - == PoolVariableIF::VAR_WRITE - && registeredVariables[count]->getDataPoolId() - != PoolVariableIF::NO_PARAMETER) { - registeredVariables[count]->commit(); - } else if (registeredVariables[count]->getDataPoolId() - != PoolVariableIF::NO_PARAMETER) { - if (result != COMMITING_WITHOUT_READING) { - sif::error << "DataSet::commit(): commit-without-read call made " - "with non write-only variable." << std::endl; - result = COMMITING_WITHOUT_READING; - } - } - } - state = DATA_SET_UNINITIALISED; - unlockDataPool(); - return result; + return DataSetBase::commit(); } ReturnValue_t GlobDataSet::unlockDataPool() { @@ -118,29 +26,8 @@ ReturnValue_t GlobDataSet::lockDataPool() { return glob::dataPool.lockDataPool(); } -ReturnValue_t GlobDataSet::serialize(uint8_t** buffer, size_t* size, - const size_t max_size, bool bigEndian) const { - ReturnValue_t result = RETURN_FAILED; - for (uint16_t count = 0; count < fill_count; count++) { - result = registeredVariables[count]->serialize(buffer, size, max_size, - bigEndian); - if (result != RETURN_OK) { - return result; - } - } - return result; -} - -size_t GlobDataSet::getSerializedSize() const { - uint32_t size = 0; - for (uint16_t count = 0; count < fill_count; count++) { - size += registeredVariables[count]->getSerializedSize(); - } - return size; -} - void GlobDataSet::setEntriesValid(bool valid) { - for (uint16_t count = 0; count < fill_count; count++) { + for (uint16_t count = 0; count < fillCount; count++) { if (registeredVariables[count]->getReadWriteMode() != PoolVariableIF::VAR_READ) { registeredVariables[count]->setValid(valid); @@ -152,15 +39,4 @@ void GlobDataSet::setSetValid(bool valid) { this->valid = valid; } -ReturnValue_t GlobDataSet::deSerialize(const uint8_t** buffer, size_t* size, - bool bigEndian) { - ReturnValue_t result = RETURN_FAILED; - for (uint16_t count = 0; count < fill_count; count++) { - result = registeredVariables[count]->deSerialize(buffer, size, - bigEndian); - if (result != RETURN_OK) { - return result; - } - } - return result; -} + diff --git a/datapoolglob/GlobalDataSet.h b/datapoolglob/GlobalDataSet.h index 365de380..c2e0b577 100644 --- a/datapoolglob/GlobalDataSet.h +++ b/datapoolglob/GlobalDataSet.h @@ -1,63 +1,32 @@ #ifndef DATASET_H_ #define DATASET_H_ -#include -#include -#include +#include -#include /** * @brief The DataSet class manages a set of locally checked out variables * for the global data pool. - * * @details - * This class manages a list, where a set of local variables (or pool variables) - * are registered. They are checked-out (i.e. their values are looked - * up and copied) with the read call. After the user finishes working with the - * pool variables, he can write back all variable values to the pool with - * the commit call. The data set manages locking and freeing the data pool, - * to ensure that all values are read and written back at once. + * This class uses the read-commit() semantic provided by the DataSetBase class. + * It extends the base class by using the global data pool, + * having a valid state and implementing lock und unlock calls for the global + * datapool. * - * An internal state manages usage of this class. Variables may only be - * registered before the read call is made, and the commit call only - * after the read call. - * - * If pool variables are writable and not committed until destruction - * of the set, the DataSet class automatically sets the valid flag in the - * data pool to invalid (without) changing the variable's value. + * For more information on how this class works, see the DataSetBase + * documentation. * @author Bastian Baetz * @ingroup data_pool */ -class GlobDataSet: public DataSetIF, public HasReturnvaluesIF, public SerializeIF { +class GlobDataSet: public DataSetBase { public: - //SHOULDDO we could use a linked list of datapool variables - //!< This definition sets the maximum number of variables to - //! register in one DataSet. - static const uint8_t DATA_SET_MAX_SIZE = 63; - - static constexpr uint8_t INTERFACE_ID = CLASS_ID::DATA_SET_CLASS; - static constexpr ReturnValue_t INVALID_PARAMETER_DEFINITION = - MAKE_RETURN_CODE( 0x01 ); - static constexpr ReturnValue_t SET_WAS_ALREADY_READ = MAKE_RETURN_CODE( 0x02 ); - static constexpr ReturnValue_t COMMITING_WITHOUT_READING = - MAKE_RETURN_CODE(0x03); - - static constexpr ReturnValue_t DATA_SET_UNINITIALIZED = MAKE_RETURN_CODE( 0x04 ); - static constexpr ReturnValue_t DATA_SET_FULL = MAKE_RETURN_CODE( 0x05 ); - static constexpr ReturnValue_t POOL_VAR_NULL = MAKE_RETURN_CODE( 0x06 ); /** - * @brief The constructor simply sets the fill_count to zero and sets - * the state to "uninitialized". + * @brief Creates an empty GlobDataSet. Use registerVariable or + * supply a pointer to this dataset to PoolVariable + * initializations to register pool variables. */ GlobDataSet(); - /** - * @brief This operation is used to register the local variables in the set. - * @details It stores the pool variable pointer in a variable list. - */ - ReturnValue_t registerVariable(PoolVariableIF* variable) override; - /** * @brief The destructor automatically manages writing the valid * information of variables. @@ -67,42 +36,7 @@ public: * For each, the valid flag in the data pool is set to "invalid". */ ~GlobDataSet(); - /** - * @brief The read call initializes reading out all registered variables. - * @details - * It iterates through the list of registered variables and calls all read() - * functions of the registered pool variables (which read out their values - * from the data pool) which are not write-only. - * In case of an error (e.g. a wrong data type, or an invalid data pool id), - * the operation is aborted and @c INVALID_PARAMETER_DEFINITION returned. - * - * The data pool is locked during the whole read operation and - * freed afterwards.The state changes to "was written" after this operation. - * @return - @c RETURN_OK if all variables were read successfully. - * - @c INVALID_PARAMETER_DEFINITION if PID, size or type of the - * requested variable is invalid. - * - @c SET_WAS_ALREADY_READ if read() is called twice without calling - * commit() in between - */ - ReturnValue_t read(); - /** - * @brief The commit call initializes writing back the registered variables. - * @details - * It iterates through the list of registered variables and calls the - * commit() method of the remaining registered variables (which write back - * their values to the pool). - * - * The data pool is locked during the whole commit operation and - * freed afterwards. The state changes to "was committed" after this operation. - * - * If the set does contain at least one variable which is not write-only commit() - * can only be called after read(). If the set only contains variables which are - * write only, commit() can be called without a preceding read() call. - * @return - @c RETURN_OK if all variables were read successfully. - * - @c COMMITING_WITHOUT_READING if set was not read yet and - * contains non write-only variables - */ - ReturnValue_t commit(void); + /** * Variant of method above which sets validity of all elements of the set. * @param valid Validity information from PoolVariableIF. @@ -111,6 +45,7 @@ public: * contains non write-only variables */ ReturnValue_t commit(bool valid); + ReturnValue_t commit() override; /** * Set all entries @@ -126,45 +61,16 @@ public: */ void setEntriesValid(bool valid); - ReturnValue_t serialize(uint8_t** buffer, size_t* size, - const size_t max_size, bool bigEndian) const override; - - size_t getSerializedSize() const override; - - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - bool bigEndian) override; private: - - /** - * @brief This array represents all pool variables registered in this set. - */ - PoolVariableIF* registeredVariables[DATA_SET_MAX_SIZE]; - /** - * \brief The fill_count attribute ensures that the variables register in the correct array - * position and that the maximum number of variables is not exceeded. - */ - uint16_t fill_count; - /** - * States of the seet. - */ - enum States { - DATA_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED - DATA_SET_WAS_READ //!< DATA_SET_WAS_READ - }; - /** - * @brief state manages the internal state of the data set, - * which is important e.g. for the behavior on destruction. - */ - States state; - /** * If the valid state of a dataset is always relevant to the whole * data set we can use this flag. */ bool valid = false; + /** * @brief This is a small helper function to facilitate locking - * the underlying data data pool structure + * the global data pool. * @details * It makes use of the lockDataPool method offered by the DataPool class. */ @@ -172,7 +78,7 @@ private: /** * @brief This is a small helper function to facilitate - * unlocking the underlying data data pool structure + * unlocking the global data pool * @details * It makes use of the freeDataPoolLock method offered by the DataPool class. */ diff --git a/datapoolglob/GlobalPoolVariable.h b/datapoolglob/GlobalPoolVariable.h index eee9afc1..cfa28e11 100644 --- a/datapoolglob/GlobalPoolVariable.h +++ b/datapoolglob/GlobalPoolVariable.h @@ -2,9 +2,9 @@ #define GLOBALPOOLVARIABLE_H_ #include +#include #include #include -#include #include #include diff --git a/devicehandlers/DeviceHandlerBase.cpp b/devicehandlers/DeviceHandlerBase.cpp index f46f854b..8efc33d5 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/devicehandlers/DeviceHandlerBase.cpp @@ -1,10 +1,10 @@ +#include #include #include #include #include #include -#include #include #include #include diff --git a/internalError/InternalErrorReporter.cpp b/internalError/InternalErrorReporter.cpp index a1e96695..30a02b44 100644 --- a/internalError/InternalErrorReporter.cpp +++ b/internalError/InternalErrorReporter.cpp @@ -1,6 +1,6 @@ +#include #include "InternalErrorReporter.h" -#include #include #include diff --git a/power/Fuse.h b/power/Fuse.h index a826a125..44f8964f 100644 --- a/power/Fuse.h +++ b/power/Fuse.h @@ -2,6 +2,7 @@ #define FUSE_H_ #include +#include #include #include #include diff --git a/thermal/TemperatureSensor.h b/thermal/TemperatureSensor.h index cd277784..27885b8b 100644 --- a/thermal/TemperatureSensor.h +++ b/thermal/TemperatureSensor.h @@ -3,6 +3,7 @@ #include #include +#include #include /** From d1b315c7df5882427c41c77bf732f606c73ab50b Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sun, 17 May 2020 23:54:56 +0200 Subject: [PATCH 18/94] pool raw access adaptions --- datapool/PoolRawAccess.cpp | 146 ++++++++++++-------- datapool/PoolRawAccess.h | 275 ++++++++++++++++++++++--------------- 2 files changed, 250 insertions(+), 171 deletions(-) diff --git a/datapool/PoolRawAccess.cpp b/datapool/PoolRawAccess.cpp index c0bd3c09..778e1b9c 100644 --- a/datapool/PoolRawAccess.cpp +++ b/datapool/PoolRawAccess.cpp @@ -1,54 +1,76 @@ #include -#include #include #include #include PoolRawAccess::PoolRawAccess(uint32_t set_id, uint8_t setArrayEntry, - DataSetIF* data_set, ReadWriteMode_t setReadWriteMode) : - dataPoolId(set_id), arrayEntry(setArrayEntry), valid(false), type(Type::UNKNOWN_TYPE), typeSize( - 0), arraySize(0), sizeTillEnd(0), readWriteMode(setReadWriteMode) { + DataSetIF* dataSet, ReadWriteMode_t setReadWriteMode) : + dataPoolId(set_id), arrayEntry(setArrayEntry), valid(false), + type(Type::UNKNOWN_TYPE), typeSize(0), arraySize(0), sizeTillEnd(0), + readWriteMode(setReadWriteMode) { memset(value, 0, sizeof(value)); - if (data_set != NULL) { - data_set->registerVariable(this); + if (dataSet != nullptr) { + dataSet->registerVariable(this); } } -PoolRawAccess::~PoolRawAccess() { - -} +PoolRawAccess::~PoolRawAccess() {} ReturnValue_t PoolRawAccess::read() { - PoolEntryIF* read_out = glob::dataPool.getRawData(dataPoolId); - if (read_out != NULL) { - valid = read_out->getValid(); - if (read_out->getSize() > arrayEntry) { - arraySize = read_out->getSize(); - typeSize = read_out->getByteSize() / read_out->getSize(); - type = read_out->getType(); - if (typeSize <= sizeof(value)) { - uint16_t arrayPosition = arrayEntry * typeSize; - sizeTillEnd = read_out->getByteSize() - arrayPosition; - uint8_t* ptr = - &((uint8_t*) read_out->getRawData())[arrayPosition]; - memcpy(value, ptr, typeSize); - return HasReturnvaluesIF::RETURN_OK; - } else { - //Error value type too large. - } - } else { - //Error index requested too large + ReturnValue_t result = RETURN_FAILED; + PoolEntryIF* readOut = glob::dataPool.getRawData(dataPoolId); + if (readOut != nullptr) { + result = handleReadOut(readOut); + if(result == RETURN_OK) { + return result; } } else { - //Error entry does not exist. + result = READ_ENTRY_NON_EXISTENT; } + handleReadError(result); + return result; +} + +ReturnValue_t PoolRawAccess::handleReadOut(PoolEntryIF* readOut) { + ReturnValue_t result = RETURN_FAILED; + valid = readOut->getValid(); + if (readOut->getSize() > arrayEntry) { + arraySize = readOut->getSize(); + typeSize = readOut->getByteSize() / readOut->getSize(); + type = readOut->getType(); + if (typeSize <= sizeof(value)) { + uint16_t arrayPosition = arrayEntry * typeSize; + sizeTillEnd = readOut->getByteSize() - arrayPosition; + uint8_t* ptr = &((uint8_t*) readOut->getRawData())[arrayPosition]; + memcpy(value, ptr, typeSize); + return RETURN_OK; + } else { + result = READ_TYPE_TOO_LARGE; + } + } else { + //debug << "PoolRawAccess: Size: " << (int)read_out->getSize() << std::endl; + result = READ_INDEX_TOO_LARGE; + } + return result; +} + +void PoolRawAccess::handleReadError(ReturnValue_t result) { sif::error << "PoolRawAccess: read of DP Variable 0x" << std::hex << dataPoolId - << std::dec << " failed." << std::endl; + << std::dec << " failed, "; + if(result == READ_TYPE_TOO_LARGE) { + sif::error << "type too large." << std::endl; + } + else if(result == READ_INDEX_TOO_LARGE) { + sif::error << "index too large." << std::endl; + } + else if(result == READ_ENTRY_NON_EXISTENT) { + sif::error << "entry does not exist." << std::endl; + } + valid = INVALID; typeSize = 0; sizeTillEnd = 0; memset(value, 0, sizeof(value)); - return HasReturnvaluesIF::RETURN_FAILED; } ReturnValue_t PoolRawAccess::commit() { @@ -71,7 +93,9 @@ uint8_t* PoolRawAccess::getEntry() { ReturnValue_t PoolRawAccess::getEntryEndianSafe(uint8_t* buffer, uint32_t* writtenBytes, uint32_t max_size) { uint8_t* data_ptr = getEntry(); -// debug << "PoolRawAccess::getEntry: Array position: " << index * size_of_type << " Size of T: " << (int)size_of_type << " ByteSize: " << byte_size << " Position: " << *size << std::endl; + // debug << "PoolRawAccess::getEntry: Array position: " << + // index * size_of_type << " Size of T: " << (int)size_of_type << + // " ByteSize: " << byte_size << " Position: " << *size << std::endl; if (typeSize == 0) return DATA_POOL_ACCESS_FAILED; if (typeSize > max_size) @@ -89,6 +113,32 @@ ReturnValue_t PoolRawAccess::getEntryEndianSafe(uint8_t* buffer, return HasReturnvaluesIF::RETURN_OK; } + +ReturnValue_t PoolRawAccess::serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { + if (typeSize + *size <= max_size) { + if (bigEndian) { +#ifndef BYTE_ORDER_SYSTEM +#error BYTE_ORDER_SYSTEM not defined +#elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN + for (uint8_t count = 0; count < typeSize; count++) { + (*buffer)[count] = value[typeSize - count - 1]; + } +#elif BYTE_ORDER_SYSTEM == BIG_ENDIAN + memcpy(*buffer, value, typeSize); +#endif + } else { + memcpy(*buffer, value, typeSize); + } + *size += typeSize; + (*buffer) += typeSize; + return HasReturnvaluesIF::RETURN_OK; + } else { + return SerializeIF::BUFFER_TOO_SHORT; + } +} + + Type PoolRawAccess::getType() { return type; } @@ -145,29 +195,6 @@ uint16_t PoolRawAccess::getSizeTillEnd() const { return sizeTillEnd; } -ReturnValue_t PoolRawAccess::serialize(uint8_t** buffer, size_t* size, - const size_t max_size, bool bigEndian) const { - if (typeSize + *size <= max_size) { - if (bigEndian) { -#ifndef BYTE_ORDER_SYSTEM -#error BYTE_ORDER_SYSTEM not defined -#elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN - for (uint8_t count = 0; count < typeSize; count++) { - (*buffer)[count] = value[typeSize - count - 1]; - } -#elif BYTE_ORDER_SYSTEM == BIG_ENDIAN - memcpy(*buffer, value, typeSize); -#endif - } else { - memcpy(*buffer, value, typeSize); - } - *size += typeSize; - (*buffer) += typeSize; - return HasReturnvaluesIF::RETURN_OK; - } else { - return SerializeIF::BUFFER_TOO_SHORT; - } -} size_t PoolRawAccess::getSerializedSize() const { return typeSize; @@ -175,8 +202,9 @@ size_t PoolRawAccess::getSerializedSize() const { ReturnValue_t PoolRawAccess::deSerialize(const uint8_t** buffer, size_t* size, bool bigEndian) { + // TODO: Needs to be tested!!! if (*size >= typeSize) { - + *size -= typeSize; if (bigEndian) { #ifndef BYTE_ORDER_SYSTEM #error BYTE_ORDER_SYSTEM not defined @@ -187,12 +215,14 @@ ReturnValue_t PoolRawAccess::deSerialize(const uint8_t** buffer, size_t* size, #elif BYTE_ORDER_SYSTEM == BIG_ENDIAN memcpy(value, *buffer, typeSize); #endif - } else { + } + else { memcpy(value, *buffer, typeSize); } *buffer += typeSize; return HasReturnvaluesIF::RETURN_OK; - } else { + } + else { return SerializeIF::STREAM_TOO_SHORT; } } diff --git a/datapool/PoolRawAccess.h b/datapool/PoolRawAccess.h index f32aac51..452b5397 100644 --- a/datapool/PoolRawAccess.h +++ b/datapool/PoolRawAccess.h @@ -2,36 +2,187 @@ #define POOLRAWACCESS_H_ #include +#include #include #include /** - * This class allows accessing Data Pool variables as raw bytes. - * This is necessary to have an access method for HK data, as the PID's alone do not - * provide a type information. - * \ingroup data_pool + * @brief This class allows accessing Data Pool variables as raw bytes. + * @details + * This is necessary to have an access method for HK data, as the PID's alone + * do not provide type information. Please note that the the raw pool access + * read() and commit() calls are not thread-safe. + * + * Please supply a data set and use the data set read(), commit() calls for + * thread-safe data pool access. + * @ingroup data_pool */ -class PoolRawAccess: public PoolVariableIF { +class PoolRawAccess: public PoolVariableIF, HasReturnvaluesIF { +public: + /** + * This constructor is used to access a data pool entry with a + * given ID if the target type is not known. A DataSet object is supplied + * and the data pool entry with the given ID is registered to that data set. + * Please note that a pool raw access buffer only has a buffer + * with a size of double. As such, for vector entries which have + * @param data_pool_id Target data pool entry ID + * @param arrayEntry + * @param data_set Dataset to register data pool entry to + * @param setReadWriteMode + * @param registerVectors If set to true, the constructor checks if + * there are multiple vector entries to registers + * and registers all of them recursively into the data_set + * + */ + PoolRawAccess(uint32_t data_pool_id, uint8_t arrayEntry, + DataSetIF* data_set, ReadWriteMode_t setReadWriteMode = + PoolVariableIF::VAR_READ); + + /** + * @brief This operation returns a pointer to the entry fetched. + * @details Return pointer to the buffer containing the raw data + * Size and number of data can be retrieved by other means. + */ + uint8_t* getEntry(); + /** + * @brief This operation returns the fetched entry from the data pool and + * flips the bytes, if necessary. + * @details It makes use of the getEntry call of this function, but additionally flips the + * bytes to big endian, which is the default for external communication (as House- + * keeping telemetry). To achieve this, the data is copied directly to the passed + * buffer, if it fits in the given max_size. + * @param buffer A pointer to a buffer to write to + * @param writtenBytes The number of bytes written is returned with this value. + * @param max_size The maximum size that the function may write to buffer. + * @return - @c RETURN_OK if entry could be acquired + * - @c RETURN_FAILED else. + */ + ReturnValue_t getEntryEndianSafe(uint8_t* buffer, uint32_t* size, + uint32_t max_size); + + /** + * @brief Serialize raw pool entry into provided buffer directly + * @param buffer Provided buffer. Raw pool data will be copied here + * @param size [out] Increment provided size value by serialized size + * @param max_size Maximum allowed serialization size + * @param bigEndian Specify endianess + * @return - @c RETURN_OK if serialization was successfull + * - @c SerializeIF::BUFFER_TOO_SHORT if range check failed + */ + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const; + + /** + * With this method, the content can be set from a big endian buffer safely. + * @param buffer Pointer to the data to set + * @param size Size of the data to write. Must fit this->size. + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + ReturnValue_t setEntryFromBigEndian(const uint8_t* buffer, + uint32_t setSize); + /** + * @brief This operation returns the type of the entry currently stored. + */ + Type getType(); + /** + * @brief This operation returns the size of the entry currently stored. + */ + uint8_t getSizeOfType(); + /** + * + * @return the size of the datapool array + */ + uint8_t getArraySize(); + /** + * @brief This operation returns the data pool id of the variable. + */ + uint32_t getDataPoolId() const; + + static const uint8_t INTERFACE_ID = CLASS_ID::POOL_RAW_ACCESS_CLASS; + static const ReturnValue_t INCORRECT_SIZE = MAKE_RETURN_CODE(0x01); + static const ReturnValue_t DATA_POOL_ACCESS_FAILED = MAKE_RETURN_CODE(0x02); + static const ReturnValue_t READ_TYPE_TOO_LARGE = MAKE_RETURN_CODE(0x03); + static const ReturnValue_t READ_INDEX_TOO_LARGE = MAKE_RETURN_CODE(0x04); + static const ReturnValue_t READ_ENTRY_NON_EXISTENT = MAKE_RETURN_CODE(0x05); + static const uint8_t RAW_MAX_SIZE = sizeof(double); + uint8_t value[RAW_MAX_SIZE]; + + + /** + * @brief The classes destructor is empty. If commit() was not called, the local value is + * discarded and not written back to the data pool. + */ + ~PoolRawAccess(); + + /** + * This method returns if the variable is read-write or read-only. + */ + ReadWriteMode_t getReadWriteMode() const; + /** + * @brief With this call, the valid information of the variable is returned. + */ + bool isValid() const; + + void setValid(uint8_t valid); + /** + * Getter for the remaining size. + */ + uint16_t getSizeTillEnd() const; + + size_t getSerializedSize() const; + + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + bool bigEndian); + +protected: + /** + * @brief This is a call to read the value from the global data pool. + * @details When executed, this operation tries to fetch the pool entry with matching + * data pool id from the global data pool and copies the value and the valid + * information to its local attributes. In case of a failure (wrong type or + * pool id not found), the variable is set to zero and invalid. + * The operation does NOT provide any mutual exclusive protection by itself ! + * If reading from the data pool without information about the type is desired, + * initialize the raw pool access by supplying a data set and using the data set + * read function, which calls this read function. + * @return -@c RETURN_OK Read successfull + * -@c READ_TYPE_TOO_LARGE + * -@c READ_INDEX_TOO_LARGE + * -@c READ_ENTRY_NON_EXISTENT + */ + ReturnValue_t read(); + /** + * @brief The commit call writes back the variable's value to the data pool. + * @details It checks type and size, as well as if the variable is writable. If so, + * the value is copied and the valid flag is automatically set to "valid". + * The operation does NOT provide any mutual exclusive protection by itself. + * + */ + ReturnValue_t commit(); + + ReturnValue_t handleReadOut(PoolEntryIF* read_out); + void handleReadError(ReturnValue_t result); private: /** - * \brief To access the correct data pool entry on read and commit calls, the data pool id + * @brief To access the correct data pool entry on read and commit calls, the data pool id * is stored. */ uint32_t dataPoolId; /** - * \brief The array entry that is fetched from the data pool. + * @brief The array entry that is fetched from the data pool. */ uint8_t arrayEntry; /** - * \brief The valid information as it was stored in the data pool is copied to this attribute. + * @brief The valid information as it was stored in the data pool is copied to this attribute. */ uint8_t valid; /** - * \brief This value contains the type of the data pool entry. + * @brief This value contains the type of the data pool entry. */ Type type; /** - * \brief This value contains the size of the data pool entry in bytes. + * @brief This value contains the size of the data pool entry type in bytes. */ uint8_t typeSize; /** @@ -43,111 +194,9 @@ private: */ uint16_t sizeTillEnd; /** - * \brief The information whether the class is read-write or read-only is stored here. + * @brief The information whether the class is read-write or read-only is stored here. */ ReadWriteMode_t readWriteMode; - static const uint8_t RAW_MAX_SIZE = sizeof(double); -protected: - /** - * \brief This is a call to read the value from the global data pool. - * \details When executed, this operation tries to fetch the pool entry with matching - * data pool id from the global data pool and copies the value and the valid - * information to its local attributes. In case of a failure (wrong type or - * pool id not found), the variable is set to zero and invalid. - * The operation does NOT provide any mutual exclusive protection by itself. - */ - ReturnValue_t read(); - /** - * \brief The commit call writes back the variable's value to the data pool. - * \details It checks type and size, as well as if the variable is writable. If so, - * the value is copied and the valid flag is automatically set to "valid". - * The operation does NOT provide any mutual exclusive protection by itself. - * - */ - ReturnValue_t commit(); -public: - static const uint8_t INTERFACE_ID = CLASS_ID::POOL_RAW_ACCESS_CLASS; - static const ReturnValue_t INCORRECT_SIZE = MAKE_RETURN_CODE(0x01); - static const ReturnValue_t DATA_POOL_ACCESS_FAILED = MAKE_RETURN_CODE(0x02); - uint8_t value[RAW_MAX_SIZE]; - PoolRawAccess(uint32_t data_pool_id, uint8_t arrayEntry, - DataSetIF* data_set, ReadWriteMode_t setReadWriteMode = - PoolVariableIF::VAR_READ); - /** - * \brief The classes destructor is empty. If commit() was not called, the local value is - * discarded and not written back to the data pool. - */ - ~PoolRawAccess(); - /** - * \brief This operation returns a pointer to the entry fetched. - * \details This means, it does not return a pointer to byte "index", but to the start byte of - * array entry "index". Example: If the original data pool array consists of an double - * array of size four, getEntry(1) returns &(this->value[8]). - */ - uint8_t* getEntry(); - /** - * \brief This operation returns the fetched entry from the data pool and - * flips the bytes, if necessary. - * \details It makes use of the getEntry call of this function, but additionally flips the - * bytes to big endian, which is the default for external communication (as House- - * keeping telemetry). To achieve this, the data is copied directly to the passed - * buffer, if it fits in the given max_size. - * \param buffer A pointer to a buffer to write to - * \param writtenBytes The number of bytes written is returned with this value. - * \param max_size The maximum size that the function may write to buffer. - * \return - \c RETURN_OK if entry could be acquired - * - \c RETURN_FAILED else. - */ - ReturnValue_t getEntryEndianSafe(uint8_t* buffer, uint32_t* size, - uint32_t max_size); - /** - * With this method, the content can be set from a big endian buffer safely. - * @param buffer Pointer to the data to set - * @param size Size of the data to write. Must fit this->size. - * @return - \c RETURN_OK on success - * - \c RETURN_FAILED on failure - */ - ReturnValue_t setEntryFromBigEndian(const uint8_t* buffer, - uint32_t setSize); - /** - * \brief This operation returns the type of the entry currently stored. - */ - Type getType(); - /** - * \brief This operation returns the size of the entry currently stored. - */ - uint8_t getSizeOfType(); - /** - * - * @return the size of the datapool array - */ - uint8_t getArraySize(); - /** - * \brief This operation returns the data pool id of the variable. - */ - uint32_t getDataPoolId() const; - /** - * This method returns if the variable is read-write or read-only. - */ - ReadWriteMode_t getReadWriteMode() const; - /** - * \brief With this call, the valid information of the variable is returned. - */ - bool isValid() const; - - void setValid(uint8_t valid); - /** - * Getter for the remaining size. - */ - uint16_t getSizeTillEnd() const; - - ReturnValue_t serialize(uint8_t** buffer, size_t* size, - const size_t max_size, bool bigEndian) const; - - size_t getSerializedSize() const; - - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - bool bigEndian); }; #endif /* POOLRAWACCESS_H_ */ From 767850e12546ddb7b17d344ee32a1c5bb389a593 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sun, 17 May 2020 23:58:57 +0200 Subject: [PATCH 19/94] deleted poolvector --- datapool/PoolVector.h | 233 ------------------------------------------ 1 file changed, 233 deletions(-) delete mode 100644 datapool/PoolVector.h diff --git a/datapool/PoolVector.h b/datapool/PoolVector.h deleted file mode 100644 index 3df61528..00000000 --- a/datapool/PoolVector.h +++ /dev/null @@ -1,233 +0,0 @@ -/* - * \file PoolVector.h - * - * \brief This file contains the PoolVector class, the header only class to handle data pool vectors. - * - * \date 10/23/2012 - * - * \author Bastian Baetz - */ - -#ifndef POOLVECTOR_H_ -#define POOLVECTOR_H_ - -#include -#include -#include -#include -#include - -/** - * \brief This is the access class for array-type data pool entries. - * - * \details To ensure safe usage of the data pool, operation is not done directly on the data pool - * entries, but on local copies. This class provides simple type- and length-safe access - * to vector-style data pool entries (i.e. entries with length > 1). - * The class can be instantiated as read-write and read only. - * It provides a commit-and-roll-back semantic, which means that no array entry in - * the data pool is changed until the commit call is executed. - * There are two template parameters: - * \tparam T This template parameter specifies the data type of an array entry. Currently, all - * plain data types are supported, but in principle any type is possible. - * \tparam vector_size This template parameter specifies the vector size of this entry. - * Using a template parameter for this is not perfect, but avoids dynamic memory allocation. - * \ingroup data_pool - */ -template -class PoolVector: public PoolVariableIF { -private: - /** - * \brief To access the correct data pool entry on read and commit calls, the data pool id - * is stored. - */ - uint32_t dataPoolId; - /** - * \brief The valid information as it was stored in the data pool is copied to this attribute. - */ - uint8_t valid; - /** - * \brief The information whether the class is read-write or read-only is stored here. - */ - ReadWriteMode_t readWriteMode; - -protected: - /** - * \brief This is a call to read the array's values from the global data pool. - * \details When executed, this operation tries to fetch the pool entry with matching - * data pool id from the global data pool and copies all array values and the valid - * information to its local attributes. In case of a failure (wrong type, size or - * pool id not found), the variable is set to zero and invalid. - * The operation does NOT provide any mutual exclusive protection by itself. - */ - ReturnValue_t read() { - PoolEntry* read_out = ::dataPool.getData(this->dataPoolId, - vector_size); - if (read_out != NULL) { - this->valid = read_out->valid; - memcpy(this->value, read_out->address, read_out->getByteSize()); - - return HasReturnvaluesIF::RETURN_OK; - - } else { - memset(this->value, 0, vector_size * sizeof(T)); - sif::error << "PoolVector: read of DP Variable 0x" << std::hex - << dataPoolId << std::dec << " failed." << std::endl; - this->valid = INVALID; - return HasReturnvaluesIF::RETURN_FAILED; - } - } - /** - * \brief The commit call copies the array values back to the data pool. - * \details It checks type and size, as well as if the variable is writable. If so, - * the value is copied and the valid flag is automatically set to "valid". - * The operation does NOT provide any mutual exclusive protection by itself. - * - */ - ReturnValue_t commit() { - PoolEntry* write_back = ::dataPool.getData(this->dataPoolId, - vector_size); - if ((write_back != NULL) && (this->readWriteMode != VAR_READ)) { - write_back->valid = valid; - memcpy(write_back->address, this->value, write_back->getByteSize()); - return HasReturnvaluesIF::RETURN_OK; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } - } -public: - /** - * \brief This is the local copy of the data pool entry. - * \detials The user can work on this attribute - * just like he would on a local array of this type. - */ - T value[vector_size]; - /** - * \brief In the constructor, the variable can register itself in a DataSet (if not NULL is - * passed). - * \details It DOES NOT fetch the current value from the data pool, but sets the value - * attribute to default (0). The value is fetched within the read() operation. - * \param set_id This is the id in the global data pool this instance of the access class - * corresponds to. - * \param dataSet The data set in which the variable shall register itself. If NULL, - * the variable is not registered. - * \param setWritable If this flag is set to true, changes in the value attribute can be - * written back to the data pool, otherwise not. - */ - PoolVector(uint32_t set_id, DataSetIF* set, - ReadWriteMode_t setReadWriteMode) : - dataPoolId(set_id), valid(false), readWriteMode(setReadWriteMode) { - memset(this->value, 0, vector_size * sizeof(T)); - if (set != NULL) { - set->registerVariable(this); - } - } - /** - * Copy ctor to copy classes containing Pool Variables. - */ -// PoolVector(const PoolVector& rhs) { -// PoolVector temp(rhs.dataPoolId, rhs.) -// memcpy(value, rhs.value, sizeof(T)*vector_size); -// } - /** - * \brief The classes destructor is empty. - * \details If commit() was not called, the local value is - * discarded and not written back to the data pool. - */ - ~PoolVector() { - } - ; - /** - * \brief The operation returns the number of array entries in this variable. - */ - uint8_t getSize() { - return vector_size; - } - /** - * \brief This operation returns the data pool id of the variable. - */ - uint32_t getDataPoolId() const { - return dataPoolId; - } - /** - * This operation sets the data pool id of the variable. - * The method is necessary to set id's of data pool member variables with bad initialization. - */ - void setDataPoolId(uint32_t poolId) { - dataPoolId = poolId; - } - /** - * This method returns if the variable is write-only, read-write or read-only. - */ - ReadWriteMode_t getReadWriteMode() const { - return readWriteMode; - } - ; - /** - * \brief With this call, the valid information of the variable is returned. - */ - bool isValid() const { - if (valid != INVALID) - return true; - else - return false; - } - - void setValid(uint8_t valid) { - this->valid = valid; - } - - uint8_t getValid() { - return valid; - } - - T &operator [](int i) { - return value[i]; - } - - const T &operator [](int i) const { - return value[i]; - } - - PoolVector &operator=( - PoolVector newPoolVector) { - - for (uint16_t i = 0; i < vector_size; i++) { - this->value[i] = newPoolVector.value[i]; - } - return *this; - } - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - const size_t max_size, bool bigEndian) const { - uint16_t i; - ReturnValue_t result; - for (i = 0; i < vector_size; i++) { - result = SerializeAdapter::serialize(&(value[i]), buffer, size, - max_size, bigEndian); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - } - return result; - } - - virtual size_t getSerializedSize() const { - return vector_size * SerializeAdapter::getSerializedSize(value); - } - - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - bool bigEndian) { - uint16_t i; - ReturnValue_t result; - for (i = 0; i < vector_size; i++) { - result = SerializeAdapter::deSerialize(&(value[i]), buffer, size, - bigEndian); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - } - return result; - } -}; - -#endif /* POOLVECTOR_H_ */ From 355bc2b9057da4f79ead6aa0e7882b9220edffd7 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 15:42:47 +0200 Subject: [PATCH 20/94] improvements --- datapoolglob/GlobalPoolVariable.h | 2 +- datapoollocal/LocalPoolVariable.h | 5 +++-- datapoollocal/LocalPoolVariable.tpp | 5 ++++- globalfunctions/Type.h | 3 +++ housekeeping/HasHkPoolParametersIF.h | 5 +---- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/datapoolglob/GlobalPoolVariable.h b/datapoolglob/GlobalPoolVariable.h index cfa28e11..eb44c307 100644 --- a/datapoolglob/GlobalPoolVariable.h +++ b/datapoolglob/GlobalPoolVariable.h @@ -32,7 +32,7 @@ class GlobPoolVar: public PoolVariableIF { template friend class PoolVarList; static_assert(not std::is_same::value, "Do not use boolean for the PoolEntry type, use uint8_t instead!" - "Warum? Darum :-)"); + "There is no boolean type in CCSDS."); public: /** * @brief In the constructor, the variable can register itself in a diff --git a/datapoollocal/LocalPoolVariable.h b/datapoollocal/LocalPoolVariable.h index 44c16a7c..39c92f60 100644 --- a/datapoollocal/LocalPoolVariable.h +++ b/datapoollocal/LocalPoolVariable.h @@ -1,4 +1,5 @@ -#pragma once +#ifndef FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_ +#define FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_ #include #include @@ -100,4 +101,4 @@ using lp_int64_t = LocalPoolVar; using lp_float_t = LocalPoolVar; using lp_double_t = LocalPoolVar; - +#endif diff --git a/datapoollocal/LocalPoolVariable.tpp b/datapoollocal/LocalPoolVariable.tpp index fdd18bcd..4bc4c662 100644 --- a/datapoollocal/LocalPoolVariable.tpp +++ b/datapoollocal/LocalPoolVariable.tpp @@ -1,4 +1,5 @@ -#pragma once +#ifndef FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVARIABLE_TPP_ +#define FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVARIABLE_TPP_ #include #include @@ -107,3 +108,5 @@ inline ReturnValue_t LocalPoolVar::deSerialize(const uint8_t** buffer, size_t* size, bool bigEndian) { return AutoSerializeAdapter::deSerialize(&value, buffer, size, bigEndian); } + +#endif diff --git a/globalfunctions/Type.h b/globalfunctions/Type.h index f4146f4e..e46a37e4 100644 --- a/globalfunctions/Type.h +++ b/globalfunctions/Type.h @@ -4,6 +4,9 @@ #include #include +/** + * @brief Type definition for CCSDS or ECSS. + */ class Type: public SerializeIF { public: enum ActualType_t { diff --git a/housekeeping/HasHkPoolParametersIF.h b/housekeeping/HasHkPoolParametersIF.h index 5ec9beef..ac248cf3 100644 --- a/housekeeping/HasHkPoolParametersIF.h +++ b/housekeeping/HasHkPoolParametersIF.h @@ -13,8 +13,7 @@ using LocalDataPoolMap = std::map; using LocalDataPoolMapIter = LocalDataPoolMap::iterator; /** - * @brief Interface for the local housekeeping managers used by the device - * handler. + * @brief */ class HasHkPoolParametersIF { public: @@ -27,6 +26,4 @@ public: virtual HousekeepingManager* getHkManagerHandle() = 0; }; - - #endif /* FRAMEWORK_DATAPOOL_HASHKPOOLPARAMETERSIF_H_ */ From 7e04c055b353b1cfe6817a2cc2e0fbbca4db631e Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 16:13:46 +0200 Subject: [PATCH 21/94] tc packet stored formatting --- tmtcpacket/pus/TcPacketStored.cpp | 10 +++++----- tmtcpacket/pus/TcPacketStored.h | 4 +++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tmtcpacket/pus/TcPacketStored.cpp b/tmtcpacket/pus/TcPacketStored.cpp index 0187b08f..6a4d03be 100644 --- a/tmtcpacket/pus/TcPacketStored.cpp +++ b/tmtcpacket/pus/TcPacketStored.cpp @@ -1,22 +1,22 @@ #include #include #include -#include +#include TcPacketStored::TcPacketStored(store_address_t setAddress) : - TcPacketBase(NULL), storeAddress(setAddress) { + TcPacketBase(nullptr), storeAddress(setAddress) { this->setStoreAddress(this->storeAddress); } TcPacketStored::TcPacketStored(uint16_t apid, uint8_t ack, uint8_t service, uint8_t subservice, uint8_t sequence_count, const uint8_t* data, - uint32_t size) : - TcPacketBase(NULL) { + size_t size) : + TcPacketBase(nullptr) { this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; if (!this->checkAndSetStore()) { return; } - uint8_t* p_data = NULL; + uint8_t* p_data = nullptr; ReturnValue_t returnValue = this->store->getFreeElement(&this->storeAddress, (TC_PACKET_MIN_SIZE + size), &p_data); if (returnValue != this->store->RETURN_OK) { diff --git a/tmtcpacket/pus/TcPacketStored.h b/tmtcpacket/pus/TcPacketStored.h index c57f0e0f..50639788 100644 --- a/tmtcpacket/pus/TcPacketStored.h +++ b/tmtcpacket/pus/TcPacketStored.h @@ -64,7 +64,9 @@ public: * @param data The data to be copied to the Application Data Field. * @param size The amount of data to be copied. */ - TcPacketStored( uint16_t apid, uint8_t ack, uint8_t service, uint8_t subservice, uint8_t sequence_count = 0, const uint8_t* data = NULL, uint32_t size = 0 ); + TcPacketStored( uint16_t apid, uint8_t ack, uint8_t service, + uint8_t subservice, uint8_t sequence_count = 0, + const uint8_t* data = nullptr, size_t size = 0 ); /** * Another constructor to create a TcPacket from a raw packet stream. * Takes the data and adds it unchecked to the TcStore. From b12bace3857588cfca51e0b0c8df37fec0d6c31a Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 16:40:11 +0200 Subject: [PATCH 22/94] changed order of input arguments (relevance) default argument for ACK --- tmtcpacket/pus/TcPacketStored.cpp | 6 +++--- tmtcpacket/pus/TcPacketStored.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tmtcpacket/pus/TcPacketStored.cpp b/tmtcpacket/pus/TcPacketStored.cpp index 6a4d03be..57b90bcc 100644 --- a/tmtcpacket/pus/TcPacketStored.cpp +++ b/tmtcpacket/pus/TcPacketStored.cpp @@ -8,9 +8,9 @@ TcPacketStored::TcPacketStored(store_address_t setAddress) : this->setStoreAddress(this->storeAddress); } -TcPacketStored::TcPacketStored(uint16_t apid, uint8_t ack, uint8_t service, - uint8_t subservice, uint8_t sequence_count, const uint8_t* data, - size_t size) : +TcPacketStored::TcPacketStored(uint8_t service, uint8_t subservice, + uint16_t apid, uint8_t sequence_count, const uint8_t* data, + size_t size, uint8_t ack ) : TcPacketBase(nullptr) { this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; if (!this->checkAndSetStore()) { diff --git a/tmtcpacket/pus/TcPacketStored.h b/tmtcpacket/pus/TcPacketStored.h index 50639788..a9c49c2e 100644 --- a/tmtcpacket/pus/TcPacketStored.h +++ b/tmtcpacket/pus/TcPacketStored.h @@ -64,9 +64,9 @@ public: * @param data The data to be copied to the Application Data Field. * @param size The amount of data to be copied. */ - TcPacketStored( uint16_t apid, uint8_t ack, uint8_t service, - uint8_t subservice, uint8_t sequence_count = 0, - const uint8_t* data = nullptr, size_t size = 0 ); + TcPacketStored( uint8_t service, uint8_t subservice, uint16_t apid, + uint8_t sequence_count = 0, const uint8_t* data = nullptr, + size_t size = 0, uint8_t ack = TcPacketBase::ACK_ALL ); /** * Another constructor to create a TcPacket from a raw packet stream. * Takes the data and adds it unchecked to the TcStore. From 1d4d01d1906d1300eb7fe4e65d259afe64210a81 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 17:22:10 +0200 Subject: [PATCH 23/94] Added ISR calls for MQ and task mgmt The task management defines an external function which implements a context switch call from an ISR --- osal/FreeRTOS/MessageQueue.cpp | 95 ++++++++++++++++++++------------ osal/FreeRTOS/MessageQueue.h | 75 +++++++++++++++++-------- osal/FreeRTOS/TaskManagement.cpp | 24 ++++++++ osal/FreeRTOS/TaskManagement.h | 63 +++++++++++++++++++++ 4 files changed, 199 insertions(+), 58 deletions(-) create mode 100644 osal/FreeRTOS/TaskManagement.cpp create mode 100644 osal/FreeRTOS/TaskManagement.h diff --git a/osal/FreeRTOS/MessageQueue.cpp b/osal/FreeRTOS/MessageQueue.cpp index e5da0442..38f425a4 100644 --- a/osal/FreeRTOS/MessageQueue.cpp +++ b/osal/FreeRTOS/MessageQueue.cpp @@ -2,11 +2,14 @@ #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 - -MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) : -defaultDestination(0),lastPartner(0) { - handle = xQueueCreate(message_depth, max_message_size); +// 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 messageDepth, size_t maxMessageSize) : +defaultDestination(0),lastPartner(0), callContext(CallContext::task) { + handle = xQueueCreate(messageDepth, maxMessageSize); if (handle == NULL) { sif::error << "MessageQueue creation failed" << std::endl; } @@ -18,6 +21,10 @@ MessageQueue::~MessageQueue() { } } +void MessageQueue::switchSystemContext(CallContext callContext) { + this->callContext = callContext; +} + ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessage* message, bool ignoreFault) { return sendMessageFrom(sendTo, message, this->getId(), ignoreFault); @@ -27,6 +34,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 +47,27 @@ 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::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 +106,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 +114,28 @@ bool MessageQueue::isDefaultDestinationSet() const { return 0; } + +// static core function to send messages. 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; - + MessageQueueMessage *message, MessageQueueId_t sentFrom, + bool ignoreFault, CallContext callContext) { + message->setSender(sentFrom); + BaseType_t result; + if(callContext == CallContext::task) { + result = xQueueSendToBack(reinterpret_cast(sendTo), + static_cast(message->getBuffer()), 0); + } + else { + // If the call context is from an interrupt, + // request a context switch if a higher priority task + // was blocked by the interrupt. + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + result = xQueueSendFromISR(reinterpret_cast(sendTo), + static_cast(message->getBuffer()), + &xHigherPriorityTaskWoken); + if(xHigherPriorityTaskWoken == pdTRUE) { + TaskManagement::requestContextSwitch(callContext); + } + } + return handleSendResult(result, ignoreFault); } - diff --git a/osal/FreeRTOS/MessageQueue.h b/osal/FreeRTOS/MessageQueue.h index 32f41b44..ce6ed46b 100644 --- a/osal/FreeRTOS/MessageQueue.h +++ b/osal/FreeRTOS/MessageQueue.h @@ -4,9 +4,14 @@ #include #include #include +#include + +extern "C" { +#include +#include +} + -#include -#include //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 +26,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 +54,15 @@ 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(); + + void switchSystemContext(CallContext 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 +89,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 +145,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 +167,20 @@ 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, CallContext callContext = CallContext::task); + + static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); + + private: QueueHandle_t handle; MessageQueueId_t defaultDestination; MessageQueueId_t lastPartner; + CallContext callContext; //!< Stores the current system context }; #endif /* MESSAGEQUEUE_H_ */ diff --git a/osal/FreeRTOS/TaskManagement.cpp b/osal/FreeRTOS/TaskManagement.cpp new file mode 100644 index 00000000..52222531 --- /dev/null +++ b/osal/FreeRTOS/TaskManagement.cpp @@ -0,0 +1,24 @@ +#include + +void TaskManagement::requestContextSwitchFromTask() { + vTaskDelay(0); +} + +void TaskManagement::requestContextSwitch(CallContext callContext = CallContext::task) { + if(callContext == CallContext::isr) { + // This function depends on the partmacro.h definition for the specific device + requestContextSwitchFromISR(); + } else { + requestContextSwitchFromTask(); + } +} + +TaskHandle_t TaskManagement::getCurrentTaskHandle() { + return xTaskGetCurrentTaskHandle(); +} + +configSTACK_DEPTH_TYPE TaskManagement::getTaskStackHighWatermark() { + return uxTaskGetStackHighWaterMark(TaskManagement::getCurrentTaskHandle()); +} + + diff --git a/osal/FreeRTOS/TaskManagement.h b/osal/FreeRTOS/TaskManagement.h new file mode 100644 index 00000000..eaaf97e2 --- /dev/null +++ b/osal/FreeRTOS/TaskManagement.h @@ -0,0 +1,63 @@ +#ifndef FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ +#define FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ + +#include + +extern "C" { +#include +#include +} +#include + +/** + * Architecture dependant portmacro.h function call. + * Should be implemented in bsp. + */ +extern "C" void requestContextSwitchFromISR(); + +/*! + * Used by functions to tell 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 and messages from within an ISR and task. + */ + +enum CallContext { + task = 0x00,//!< task_context + isr = 0xFF //!< isr_context +}; + + +class TaskManagement { +public: + /** + * 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(CallContext callContext); + + /** + * If task preemption in FreeRTOS is disabled, a context switch + * can be requested manually by calling this function. + */ + static void requestContextSwitchFromTask(void); + + /** + * @return The current task handle + */ + static TaskHandle_t getCurrentTaskHandle(); + + /** + * Get returns the minimum amount of remaining stack space in words + * that was a available to the task since the task started executing. + * Please note that the actual value in bytes depends + * on the stack depth type. + * E.g. on a 32 bit machine, a value of 200 means 800 bytes. + * @return Smallest value of stack remaining since the task was started in + * words. + */ + static configSTACK_DEPTH_TYPE getTaskStackHighWatermark(); +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ */ From d1500a78685d18e05b94419be69f9cb09056c127 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 17:31:05 +0200 Subject: [PATCH 24/94] mq doc improvements --- osal/FreeRTOS/MessageQueue.cpp | 9 ++- osal/FreeRTOS/MessageQueue.h | 120 ++++++++++++++++++--------------- 2 files changed, 72 insertions(+), 57 deletions(-) diff --git a/osal/FreeRTOS/MessageQueue.cpp b/osal/FreeRTOS/MessageQueue.cpp index 38f425a4..12a3173a 100644 --- a/osal/FreeRTOS/MessageQueue.cpp +++ b/osal/FreeRTOS/MessageQueue.cpp @@ -50,14 +50,16 @@ 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); + return sendMessageFromMessageQueue(sendTo, message, sentFrom, + ignoreFault, callContext); } ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault) { if (result != pdPASS) { if (!ignoreFault) { - InternalErrorReporterIF* internalErrorReporter = objectManager->get( + InternalErrorReporterIF* internalErrorReporter = + objectManager->get( objects::INTERNAL_ERROR_REPORTER); if (internalErrorReporter != NULL) { internalErrorReporter->queueMessageNotSent(); @@ -78,7 +80,8 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message, } ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message) { - BaseType_t result = xQueueReceive(handle,reinterpret_cast(message->getBuffer()), 0); + BaseType_t result = xQueueReceive(handle,reinterpret_cast( + message->getBuffer()), 0); if (result == pdPASS){ this->lastPartner = message->getSender(); return HasReturnvaluesIF::RETURN_OK; diff --git a/osal/FreeRTOS/MessageQueue.h b/osal/FreeRTOS/MessageQueue.h index ce6ed46b..c278e329 100644 --- a/osal/FreeRTOS/MessageQueue.h +++ b/osal/FreeRTOS/MessageQueue.h @@ -12,52 +12,57 @@ extern "C" { } - //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/ /** - * @brief This class manages sending and receiving of message queue messages. + * @brief This class manages sending and receiving of + * message queue messages. + * @details + * Message queues are used to pass asynchronous messages between processes. + * They work like post boxes, where all incoming messages are stored in FIFO + * order. This class creates a new receiving queue and provides methods to fetch + * received messages. Being a child of MessageQueueSender, this class also + * provides 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. * - * @details Message queues are used to pass asynchronous messages between processes. - * They work like post boxes, where all incoming messages are stored in FIFO - * order. This class creates a new receiving queue and provides methods to fetch - * received messages. Being a child of MessageQueueSender, this class also provides - * 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. * - * 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. - * - * 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 + * 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; public: /** * @brief The constructor initializes and configures the message queue. - * @details By making use of the according operating system call, a message queue is created - * and initialized. The message depth - the maximum number of messages to be - * buffered - may be set with the help of a parameter, whereas the message size is - * automatically set to the maximum message queue message size. The operating system - * sets the message queue id, or i case of failure, it is set to zero. - * @param message_depth The number of messages to be buffered before passing an error to the - * sender. Default is three. - * @param max_message_size With this parameter, the maximum message size can be adjusted. - * This should be left default. + * @details + * By making use of the according operating system call, a message queue is created + * and initialized. The message depth - the maximum number of messages to be + * buffered - may be set with the help of a parameter, whereas the message size is + * automatically set to the maximum message queue message size. The operating system + * sets the message queue id, or i case of failure, it is set to zero. + * @param message_depth + * The number of messages to be buffered before passing an error to the + * sender. Default is three. + * @param max_message_size + * With this parameter, the maximum message size can be adjusted. + * This should be left default. */ - MessageQueue( size_t message_depth = 3, size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE ); + 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. + * @details This is accomplished by using the delete call provided + * by the operating system. */ virtual ~MessageQueue(); @@ -90,27 +95,28 @@ 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 + * @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. + * @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. + * @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. + * @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 ); + 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. @@ -147,27 +153,34 @@ public: MessageQueueId_t getId() const; /** - * \brief This method is a simple setter for the default destination. + * @brief This method is a simple setter for the default destination. */ void setDefaultDestination(MessageQueueId_t defaultDestination); /** - * \brief This method is a simple getter for the default destination. + * @brief This method is a simple getter for the default destination. */ MessageQueueId_t getDefaultDestination() const; bool isDefaultDestinationSet() const; protected: /** - * Implementation to be called from any send Call within MessageQueue and MessageQueueSenderIF - * \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. - * \param context + * @brief Implementation to be called from any send Call within + * MessageQueue and MessageQueueSenderIF. + * @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. + * @param context Specify whether call is made from task or from an ISR. */ static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, @@ -175,7 +188,6 @@ protected: static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); - private: QueueHandle_t handle; MessageQueueId_t defaultDestination; From f8614e23a867d21d64922329164920c41ab55c38 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 17:38:19 +0200 Subject: [PATCH 25/94] deleted copy ans assignment ctor --- osal/FreeRTOS/MessageQueue.cpp | 18 +++++++++--------- osal/FreeRTOS/MessageQueue.h | 16 +++++++++++----- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/osal/FreeRTOS/MessageQueue.cpp b/osal/FreeRTOS/MessageQueue.cpp index 12a3173a..9e4b581b 100644 --- a/osal/FreeRTOS/MessageQueue.cpp +++ b/osal/FreeRTOS/MessageQueue.cpp @@ -7,11 +7,10 @@ // 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 messageDepth, size_t maxMessageSize) : -defaultDestination(0),lastPartner(0), callContext(CallContext::task) { +MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize) { handle = xQueueCreate(messageDepth, maxMessageSize); if (handle == NULL) { - sif::error << "MessageQueue creation failed" << std::endl; + sif::error << "MessageQueue: Creation failed" << std::endl; } } @@ -57,11 +56,11 @@ ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault) { if (result != pdPASS) { - if (!ignoreFault) { + if (not ignoreFault) { InternalErrorReporterIF* internalErrorReporter = objectManager->get( objects::INTERNAL_ERROR_REPORTER); - if (internalErrorReporter != NULL) { + if (internalErrorReporter != nullptr) { internalErrorReporter->queueMessageNotSent(); } } @@ -106,6 +105,7 @@ MessageQueueId_t MessageQueue::getId() const { } void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { + defaultDestinationSet = true; this->defaultDestination = defaultDestination; } @@ -114,7 +114,7 @@ MessageQueueId_t MessageQueue::getDefaultDestination() const { } bool MessageQueue::isDefaultDestinationSet() const { - return 0; + return defaultDestinationSet; } @@ -129,9 +129,9 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, static_cast(message->getBuffer()), 0); } else { - // If the call context is from an interrupt, - // request a context switch if a higher priority task - // was blocked by the interrupt. + /* If the call context is from an interrupt, + * request a context switch if a higher priority task + * was blocked by the interrupt. */ BaseType_t xHigherPriorityTaskWoken = pdFALSE; result = xQueueSendFromISR(reinterpret_cast(sendTo), static_cast(message->getBuffer()), diff --git a/osal/FreeRTOS/MessageQueue.h b/osal/FreeRTOS/MessageQueue.h index c278e329..e88bbcec 100644 --- a/osal/FreeRTOS/MessageQueue.h +++ b/osal/FreeRTOS/MessageQueue.h @@ -56,8 +56,12 @@ public: * With this parameter, the maximum message size can be adjusted. * This should be left default. */ - MessageQueue( size_t message_depth = 3, - size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE ); + MessageQueue( size_t messageDepth = 3, + size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE ); + + /** Copying message queues forbidden */ + MessageQueue(const MessageQueue&) = delete; + MessageQueue& operator=(const MessageQueue&) = delete; /** * @brief The destructor deletes the formerly created message queue. @@ -189,10 +193,12 @@ protected: static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); private: + bool defaultDestinationSet = false; QueueHandle_t handle; - MessageQueueId_t defaultDestination; - MessageQueueId_t lastPartner; - CallContext callContext; //!< Stores the current system context + MessageQueueId_t defaultDestination = 0; + MessageQueueId_t lastPartner = 0; + //!< Stores the current system context + CallContext callContext = CallContext::task; }; #endif /* MESSAGEQUEUE_H_ */ From 41c0ca6c52a728ffaf359805efb0df0319b9dcc3 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 17:39:10 +0200 Subject: [PATCH 26/94] added doc for switchSystemContext --- osal/FreeRTOS/MessageQueue.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osal/FreeRTOS/MessageQueue.h b/osal/FreeRTOS/MessageQueue.h index e88bbcec..07e95ddf 100644 --- a/osal/FreeRTOS/MessageQueue.h +++ b/osal/FreeRTOS/MessageQueue.h @@ -70,6 +70,11 @@ public: */ virtual ~MessageQueue(); + /** + * This function is used to switch the call context. This has to be called + * if a message is sent or received from an ISR! + * @param callContext + */ void switchSystemContext(CallContext callContext); /** From b23728731548d900b97a70e3d32565ebcfcc50e7 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 17:48:16 +0200 Subject: [PATCH 27/94] bin semaph sif replacements --- osal/FreeRTOS/BinarySemaphore.cpp | 11 +++++------ returnvalues/FwClassIds.h | 2 ++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index a6a923aa..acfc53bd 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -11,8 +11,7 @@ BinarySemaphore::BinarySemaphore() { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { - - error << "Binary semaphore creation failure" << std::endl; + sif::error << "Binary semaphore creation failure" << std::endl; } xSemaphoreGive(handle); } @@ -26,7 +25,7 @@ BinarySemaphore::~BinarySemaphore() { BinarySemaphore::BinarySemaphore(const BinarySemaphore& other) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { - error << "Binary semaphore creation failure" << std::endl; + sif::error << "Binary semaphore creation failure" << std::endl; } xSemaphoreGive(handle); } @@ -35,7 +34,7 @@ BinarySemaphore& BinarySemaphore::operator =(const BinarySemaphore& s) { if(this != &s) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { - error << "Binary semaphore creation failure" << std::endl; + sif::error << "Binary semaphore creation failure" << std::endl; } xSemaphoreGive(handle); } @@ -45,7 +44,7 @@ BinarySemaphore& BinarySemaphore::operator =(const BinarySemaphore& s) { BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { - error << "Binary semaphore creation failure" << std::endl; + sif::error << "Binary semaphore creation failure" << std::endl; } xSemaphoreGive(handle); } @@ -55,7 +54,7 @@ BinarySemaphore& BinarySemaphore::operator =( if(&s != this) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { - error << "Binary semaphore creation failure" << std::endl; + sif::error << "Binary semaphore creation failure" << std::endl; } xSemaphoreGive(handle); } diff --git a/returnvalues/FwClassIds.h b/returnvalues/FwClassIds.h index d21861c0..120d8b8c 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 @@ -59,6 +60,7 @@ enum { SGP4PROPAGATOR_CLASS, //SGP4 53 MUTEX_IF, //MUX 54 MESSAGE_QUEUE_IF,//MQI 55 + SEMAPHORE_IF, //SPH 56 FW_CLASS_ID_COUNT //is actually count + 1 ! }; From 45b0193ef38b70a4f1d5be76564258bc6ab5c928 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 18:06:40 +0200 Subject: [PATCH 28/94] bin semaph todo --- osal/FreeRTOS/BinarySemaphore.h | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 0ab9cdea..865da8a6 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -1,27 +1,24 @@ -/** - * @file BinarySempahore.h - * - * @date 25.02.2020 - */ #ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ #define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ #include extern "C" { -#include "FreeRTOS.h" -#include "semphr.h" +#include +#include } - +// TODO: Counting semaphores and implement the new (better) +// task notifications. However, those use task notifications require +// the task handle. Maybe it would be better to make a separate class +// and switch between the classes with #ifdefs. +// Task Notifications require FreeRTOS V8.2 something.. /** * @brief OS Tool to achieve synchronization of between tasks or between task and ISR * @details * Documentation: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html * - * SHOULDDO: check freeRTOS version and use new task notifications, - * if non-ancient freeRTOS version is used. - * + * @author R. Mueller * @ingroup osal */ class BinarySemaphore: public HasReturnvaluesIF { From 87bf843beffe92f7f535609cb83fcb4378f952be Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 19:19:50 +0200 Subject: [PATCH 29/94] binary semaphore IF init --- tasks/SemaphoreIF.h | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tasks/SemaphoreIF.h diff --git a/tasks/SemaphoreIF.h b/tasks/SemaphoreIF.h new file mode 100644 index 00000000..babac05a --- /dev/null +++ b/tasks/SemaphoreIF.h @@ -0,0 +1,8 @@ +#ifndef FRAMEWORK_TASKS_SEMAPHOREIF_H_ +#define FRAMEWORK_TASKS_SEMAPHOREIF_H_ + + + + + +#endif /* FRAMEWORK_TASKS_SEMAPHOREIF_H_ */ From 9ba21b1e288ba9f8e20fae9c4cc7ea6923b2651f Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 19:30:50 +0200 Subject: [PATCH 30/94] semaphore if continued --- tasks/SemaphoreIF.h | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tasks/SemaphoreIF.h b/tasks/SemaphoreIF.h index babac05a..cf56f6f9 100644 --- a/tasks/SemaphoreIF.h +++ b/tasks/SemaphoreIF.h @@ -1,8 +1,49 @@ #ifndef FRAMEWORK_TASKS_SEMAPHOREIF_H_ #define FRAMEWORK_TASKS_SEMAPHOREIF_H_ +#include +#include +#include +/** + * @brief Generic interface for semaphores, which can be used to achieve + * task synchronization. + */ +class SemaphoreIF { + //!< Needs to be defined in implementation. + static const uint32_t NO_TIMEOUT; + static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; + //! Semaphore timeout + static constexpr ReturnValue_t SEMAPHORE_TIMEOUT = MAKE_RETURN_CODE(1); + //! The current semaphore can not be given, because it is not owned + static constexpr ReturnValue_t SEMAPHORE_NOT_OWNED = MAKE_RETURN_CODE(2); + static constexpr ReturnValue_t SEMAPHORE_NULLPOINTER = MAKE_RETURN_CODE(3); + /** + * Generic call to acquire a semaphore. + * If there are no more semaphores to be taken (for a counting semaphore, + * a semaphore may be taken more than once), the taks will block + * for a maximum of timeoutMs while trying to acquire the semaphore. + * This can be used to achieve task synchrnization. + * @param timeoutMs + * @return + */ + ReturnValue_t acquire(uint32_t timeoutMs) = 0; + /** + * Corrensponding call to release a semaphore. + * @return + */ + ReturnValue_t release() = 0; + + /** + * If the semaphore is a counting semaphore then the semaphores current + * count value is returned. If the semaphore is a binary semaphore then 1 + * is returned if the semaphore is available, and 0 is returned if the + * semaphore is not available. + * @return + */ + uint8_t getSemaphoreCounter() = 0; +}; #endif /* FRAMEWORK_TASKS_SEMAPHOREIF_H_ */ From 4dd6594845deb381b80fcb2ba8e0ec27acec27e1 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 19:38:02 +0200 Subject: [PATCH 31/94] integrated interface into bin semaphore --- osal/FreeRTOS/BinarySemaphore.cpp | 11 +++++++++++ osal/FreeRTOS/BinarySemaphore.h | 11 +++++++++-- tasks/SemaphoreIF.h | 14 +++++++------- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index acfc53bd..c0300b81 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -132,6 +132,17 @@ void BinarySemaphore::resetSemaphore() { } } +ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { + return takeBinarySemaphore(timeoutMs); +} + +ReturnValue_t BinarySemaphore::release() { + return giveBinarySemaphore(); +} + +uint8_t BinarySemaphore::getSemaphoreCounter() { + return uxSemaphoreGetCount(handle); +} // Be careful with the stack size here. This is called from an ISR! ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 865da8a6..8271d9d0 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -2,7 +2,7 @@ #define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ #include - +#include extern "C" { #include #include @@ -21,7 +21,8 @@ extern "C" { * @author R. Mueller * @ingroup osal */ -class BinarySemaphore: public HasReturnvaluesIF { +class BinarySemaphore: public SemaphoreIF, + public HasReturnvaluesIF { public: static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; @@ -67,6 +68,12 @@ public: */ virtual ~BinarySemaphore(); + ReturnValue_t acquire(uint32_t timeoutMs = + BinarySemaphore::NO_BLOCK_TIMEOUT) override; + ReturnValue_t release() override; + + uint8_t getSemaphoreCounter() override; + /** * Take the binary semaphore. * If the semaphore has already been taken, the task will be blocked diff --git a/tasks/SemaphoreIF.h b/tasks/SemaphoreIF.h index cf56f6f9..616b992d 100644 --- a/tasks/SemaphoreIF.h +++ b/tasks/SemaphoreIF.h @@ -9,10 +9,11 @@ * task synchronization. */ class SemaphoreIF { +public: + virtual~ SemaphoreIF() {}; //!< Needs to be defined in implementation. static const uint32_t NO_TIMEOUT; static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; - //! Semaphore timeout static constexpr ReturnValue_t SEMAPHORE_TIMEOUT = MAKE_RETURN_CODE(1); //! The current semaphore can not be given, because it is not owned @@ -26,24 +27,23 @@ class SemaphoreIF { * for a maximum of timeoutMs while trying to acquire the semaphore. * This can be used to achieve task synchrnization. * @param timeoutMs - * @return + * @return - c RETURN_OK for successfull acquisition */ - ReturnValue_t acquire(uint32_t timeoutMs) = 0; + virtual ReturnValue_t acquire(uint32_t timeoutMs) = 0; /** * Corrensponding call to release a semaphore. - * @return + * @return -@c RETURN_OK for successfull release */ - ReturnValue_t release() = 0; + virtual ReturnValue_t release() = 0; /** * If the semaphore is a counting semaphore then the semaphores current * count value is returned. If the semaphore is a binary semaphore then 1 * is returned if the semaphore is available, and 0 is returned if the * semaphore is not available. - * @return */ - uint8_t getSemaphoreCounter() = 0; + virtual uint8_t getSemaphoreCounter() = 0; }; #endif /* FRAMEWORK_TASKS_SEMAPHOREIF_H_ */ From b1d9d55f50a0e242ec57604934659c7fff50eb01 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 19:42:05 +0200 Subject: [PATCH 32/94] improved documentation --- tasks/SemaphoreIF.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tasks/SemaphoreIF.h b/tasks/SemaphoreIF.h index 616b992d..7dde27f4 100644 --- a/tasks/SemaphoreIF.h +++ b/tasks/SemaphoreIF.h @@ -6,7 +6,16 @@ /** * @brief Generic interface for semaphores, which can be used to achieve - * task synchronization. + * task synchronization. This is a generic interface which can be + * used for both binary semaphores and counting semaphores. + * @details + * A semaphore is a synchronization primitive. + * See: https://en.wikipedia.org/wiki/Semaphore_(programming) + * A semaphore can be used to achieve task synchonization and track the + * availability of resources. + * + * If mutual exlcusion of a resource is desired, a mutex should be used, + * which is a special form of a semaphore and has an own interface. */ class SemaphoreIF { public: From 067cd9573100952c1398b956a8b7d2cbeab93a3a Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 19:42:45 +0200 Subject: [PATCH 33/94] removed file header --- osal/FreeRTOS/BinarySemaphore.cpp | 5 ----- osal/FreeRTOS/BinarySemaphore.h | 1 - 2 files changed, 6 deletions(-) diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index c0300b81..e4850702 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -1,8 +1,3 @@ -/** - * @file BinarySemaphore.cpp - * - * @date 25.02.2020 - */ #include #include diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 8271d9d0..854cbba4 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -71,7 +71,6 @@ public: ReturnValue_t acquire(uint32_t timeoutMs = BinarySemaphore::NO_BLOCK_TIMEOUT) override; ReturnValue_t release() override; - uint8_t getSemaphoreCounter() override; /** From 7227c3a8667a1ead8c4160b8372d350e79617de4 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 20:35:13 +0200 Subject: [PATCH 34/94] implemented semaph factory --- osal/FreeRTOS/BinarySemaphore.cpp | 45 +++++++++++++------------ osal/FreeRTOS/BinarySemaphore.h | 52 +++++++++++------------------ osal/FreeRTOS/CountingSemaphore.cpp | 26 +++++++++++++++ osal/FreeRTOS/CountingSemaphore.h | 21 ++++++++++++ osal/FreeRTOS/Mutex.h | 8 ++--- osal/FreeRTOS/MutexFactory.cpp | 9 ++--- osal/FreeRTOS/SemaphoreFactory.cpp | 33 ++++++++++++++++++ tasks/SemaphoreFactory.h | 45 +++++++++++++++++++++++++ 8 files changed, 177 insertions(+), 62 deletions(-) create mode 100644 osal/FreeRTOS/CountingSemaphore.cpp create mode 100644 osal/FreeRTOS/CountingSemaphore.h create mode 100644 osal/FreeRTOS/SemaphoreFactory.cpp create mode 100644 tasks/SemaphoreFactory.h diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index e4850702..11e48153 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -3,21 +3,21 @@ #include -BinarySemaphore::BinarySemaphore() { +Semaphore::Semaphore() { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { - sif::error << "Binary semaphore creation failure" << std::endl; + sif::error << "Semaphore: Binary semaph creation failure" << std::endl; } xSemaphoreGive(handle); } -BinarySemaphore::~BinarySemaphore() { +Semaphore::~Semaphore() { vSemaphoreDelete(handle); } // This copy ctor is important as it prevents the assignment to a ressource // (other.handle) variable which is later deleted! -BinarySemaphore::BinarySemaphore(const BinarySemaphore& other) { +Semaphore::Semaphore(const Semaphore& other) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { sif::error << "Binary semaphore creation failure" << std::endl; @@ -25,7 +25,7 @@ BinarySemaphore::BinarySemaphore(const BinarySemaphore& other) { xSemaphoreGive(handle); } -BinarySemaphore& BinarySemaphore::operator =(const BinarySemaphore& s) { +Semaphore& Semaphore::operator =(const Semaphore& s) { if(this != &s) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { @@ -36,7 +36,7 @@ BinarySemaphore& BinarySemaphore::operator =(const BinarySemaphore& s) { return *this; } -BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { +Semaphore::Semaphore(Semaphore&& s) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { sif::error << "Binary semaphore creation failure" << std::endl; @@ -44,8 +44,8 @@ BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { xSemaphoreGive(handle); } -BinarySemaphore& BinarySemaphore::operator =( - BinarySemaphore&& s) { +Semaphore& Semaphore::operator =( + Semaphore&& s) { if(&s != this) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { @@ -56,15 +56,15 @@ BinarySemaphore& BinarySemaphore::operator =( return *this; } -ReturnValue_t BinarySemaphore::takeBinarySemaphore(uint32_t timeoutMs) { +ReturnValue_t Semaphore::takeBinarySemaphore(uint32_t timeoutMs) { if(handle == nullptr) { return SEMAPHORE_NULLPOINTER; } - TickType_t timeout = BinarySemaphore::NO_BLOCK_TICKS; - if(timeoutMs == BinarySemaphore::BLOCK_TIMEOUT) { - timeout = BinarySemaphore::BLOCK_TIMEOUT_TICKS; + TickType_t timeout = Semaphore::NO_BLOCK_TICKS; + if(timeoutMs == Semaphore::BLOCK_TIMEOUT) { + timeout = Semaphore::BLOCK_TIMEOUT_TICKS; } - else if(timeoutMs > BinarySemaphore::NO_BLOCK_TIMEOUT){ + else if(timeoutMs > Semaphore::NO_BLOCK_TIMEOUT){ timeout = pdMS_TO_TICKS(timeoutMs); } @@ -77,7 +77,7 @@ ReturnValue_t BinarySemaphore::takeBinarySemaphore(uint32_t timeoutMs) { } } -ReturnValue_t BinarySemaphore::takeBinarySemaphoreTickTimeout( +ReturnValue_t Semaphore::takeBinarySemaphoreTickTimeout( TickType_t timeoutTicks) { if(handle == nullptr) { return SEMAPHORE_NULLPOINTER; @@ -91,7 +91,7 @@ ReturnValue_t BinarySemaphore::takeBinarySemaphoreTickTimeout( } } -ReturnValue_t BinarySemaphore::giveBinarySemaphore() { +ReturnValue_t Semaphore::giveBinarySemaphore() { if (handle == nullptr) { return SEMAPHORE_NULLPOINTER; } @@ -103,11 +103,11 @@ ReturnValue_t BinarySemaphore::giveBinarySemaphore() { } } -SemaphoreHandle_t BinarySemaphore::getSemaphore() { +SemaphoreHandle_t Semaphore::getSemaphore() { return handle; } -ReturnValue_t BinarySemaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) { +ReturnValue_t Semaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) { if (semaphore == nullptr) { return SEMAPHORE_NULLPOINTER; } @@ -119,7 +119,7 @@ ReturnValue_t BinarySemaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) } } -void BinarySemaphore::resetSemaphore() { +void Semaphore::resetSemaphore() { if(handle != nullptr) { vSemaphoreDelete(handle); handle = xSemaphoreCreateBinary(); @@ -127,20 +127,20 @@ void BinarySemaphore::resetSemaphore() { } } -ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { +ReturnValue_t Semaphore::acquire(uint32_t timeoutMs) { return takeBinarySemaphore(timeoutMs); } -ReturnValue_t BinarySemaphore::release() { +ReturnValue_t Semaphore::release() { return giveBinarySemaphore(); } -uint8_t BinarySemaphore::getSemaphoreCounter() { +uint8_t Semaphore::getSemaphoreCounter() { return uxSemaphoreGetCount(handle); } // Be careful with the stack size here. This is called from an ISR! -ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, +ReturnValue_t Semaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken) { if (semaphore == nullptr) { return SEMAPHORE_NULLPOINTER; @@ -157,3 +157,4 @@ ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t sema return SEMAPHORE_NOT_OWNED; } } + diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 854cbba4..6383432f 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -14,14 +14,16 @@ extern "C" { // and switch between the classes with #ifdefs. // Task Notifications require FreeRTOS V8.2 something.. /** - * @brief OS Tool to achieve synchronization of between tasks or between task and ISR + * @brief OS Tool to achieve synchronization of between tasks or between + * task and ISR. The default semaphore implementation creates a + * binary semaphore, which can only be taken once. * @details * Documentation: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html * * @author R. Mueller * @ingroup osal */ -class BinarySemaphore: public SemaphoreIF, +class Semaphore: public SemaphoreIF, public HasReturnvaluesIF { public: static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; @@ -41,35 +43,21 @@ public: static constexpr ReturnValue_t SEMAPHORE_NOT_OWNED = MAKE_RETURN_CODE(2); static constexpr ReturnValue_t SEMAPHORE_NULLPOINTER = MAKE_RETURN_CODE(3); - BinarySemaphore(); - - /** - * @brief Copy ctor - */ - BinarySemaphore(const BinarySemaphore&); - - /** - * @brief Copy assignment - */ - BinarySemaphore& operator=(const BinarySemaphore&); - - /** - * @brief Move constructor - */ - BinarySemaphore (BinarySemaphore &&); - - /** - * Move assignment - */ - BinarySemaphore & operator=(BinarySemaphore &&); - - /** - * Delete the binary semaphore to prevent a memory leak - */ - virtual ~BinarySemaphore(); + //! @brief Default ctor + Semaphore(); + //! @brief Copy ctor + Semaphore(const Semaphore&); + //! @brief Copy assignment + Semaphore& operator=(const Semaphore&); + //! @brief Move ctor + Semaphore (Semaphore &&); + //! @brief Move assignment + Semaphore & operator=(Semaphore &&); + //! @brief Destructor + virtual ~Semaphore(); ReturnValue_t acquire(uint32_t timeoutMs = - BinarySemaphore::NO_BLOCK_TIMEOUT) override; + Semaphore::NO_BLOCK_TIMEOUT) override; ReturnValue_t release() override; uint8_t getSemaphoreCounter() override; @@ -83,7 +71,7 @@ public: * -@c RETURN_FAILED on failure */ ReturnValue_t takeBinarySemaphore(uint32_t timeoutMs = - BinarySemaphore::NO_BLOCK_TIMEOUT); + Semaphore::NO_BLOCK_TIMEOUT); /** * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. @@ -92,7 +80,7 @@ public: * - @c RETURN_FAILED on failure */ ReturnValue_t takeBinarySemaphoreTickTimeout(TickType_t timeoutTicks = - BinarySemaphore::NO_BLOCK_TICKS); + Semaphore::NO_BLOCK_TICKS); /** * Give back the binary semaphore @@ -130,7 +118,7 @@ public: */ static ReturnValue_t giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken); -private: +protected: SemaphoreHandle_t handle; }; diff --git a/osal/FreeRTOS/CountingSemaphore.cpp b/osal/FreeRTOS/CountingSemaphore.cpp new file mode 100644 index 00000000..adf3f23c --- /dev/null +++ b/osal/FreeRTOS/CountingSemaphore.cpp @@ -0,0 +1,26 @@ +#include +#include + +CountingSemaphore::CountingSemaphore(uint8_t count, uint8_t initCount): + count(count), initCount(initCount) { + handle = xSemaphoreCreateCounting(count, initCount); + if(handle == nullptr) { + sif::error << "CountingSemaphore: Creation failure" << std::endl; + } +} + +CountingSemaphore::CountingSemaphore(CountingSemaphore&& other) { + handle = xSemaphoreCreateCounting(other.count, other.initCount); + if(handle == nullptr) { + sif::error << "CountingSemaphore: Creation failure" << std::endl; + } +} + +CountingSemaphore& CountingSemaphore::operator =( + CountingSemaphore&& other) { + handle = xSemaphoreCreateCounting(other.count, other.initCount); + if(handle == nullptr) { + sif::error << "CountingSemaphore: Creation failure" << std::endl; + } + return * this; +} diff --git a/osal/FreeRTOS/CountingSemaphore.h b/osal/FreeRTOS/CountingSemaphore.h new file mode 100644 index 00000000..8c059af5 --- /dev/null +++ b/osal/FreeRTOS/CountingSemaphore.h @@ -0,0 +1,21 @@ +#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ +#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ +#include + +class CountingSemaphore: public Semaphore { +public: + CountingSemaphore(uint8_t count, uint8_t initCount); + //! @brief Copy ctor, disabled + CountingSemaphore(const CountingSemaphore&) = delete; + //! @brief Copy assignment, disabled + CountingSemaphore& operator=(const CountingSemaphore&) = delete; + //! @brief Move ctor + CountingSemaphore (CountingSemaphore &&); + //! @brief Move assignment + CountingSemaphore & operator=(CountingSemaphore &&); +private: + uint8_t count = 0; + uint8_t initCount = 0; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */ diff --git a/osal/FreeRTOS/Mutex.h b/osal/FreeRTOS/Mutex.h index 91f29585..ccbcad26 100644 --- a/osal/FreeRTOS/Mutex.h +++ b/osal/FreeRTOS/Mutex.h @@ -3,10 +3,10 @@ #include - -#include -#include "semphr.h" - +extern "C" { +#include +#include +} class Mutex : public MutexIF { diff --git a/osal/FreeRTOS/MutexFactory.cpp b/osal/FreeRTOS/MutexFactory.cpp index cadb54fb..08cd68c8 100644 --- a/osal/FreeRTOS/MutexFactory.cpp +++ b/osal/FreeRTOS/MutexFactory.cpp @@ -1,10 +1,11 @@ #include -#include "../FreeRTOS/Mutex.h" +#include -//TODO: Different variant than the lazy loading in QueueFactory. What's better and why? -> one is on heap the other on bss/data +//TODO: Different variant than the lazy loading in QueueFactory. +//What's better and why? -> one is on heap the other on bss/data //MutexFactory* MutexFactory::factoryInstance = new MutexFactory(); -MutexFactory* MutexFactory::factoryInstance = NULL; +MutexFactory* MutexFactory::factoryInstance = nullptr; MutexFactory::MutexFactory() { } @@ -13,7 +14,7 @@ MutexFactory::~MutexFactory() { } MutexFactory* MutexFactory::instance() { - if (factoryInstance == NULL){ + if (factoryInstance == nullptr){ factoryInstance = new MutexFactory(); } return MutexFactory::factoryInstance; diff --git a/osal/FreeRTOS/SemaphoreFactory.cpp b/osal/FreeRTOS/SemaphoreFactory.cpp new file mode 100644 index 00000000..dd319025 --- /dev/null +++ b/osal/FreeRTOS/SemaphoreFactory.cpp @@ -0,0 +1,33 @@ +#include +#include +#include +#include + +SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; + +SemaphoreFactory::SemaphoreFactory() { +} + +SemaphoreFactory::~SemaphoreFactory() { + delete factoryInstance; +} + +SemaphoreFactory* SemaphoreFactory::instance() { + if (factoryInstance == nullptr){ + factoryInstance = new SemaphoreFactory(); + } + return SemaphoreFactory::factoryInstance; +} + +SemaphoreIF* SemaphoreFactory::createBinarySemaphore() { + return new Semaphore(); +} + +SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t count, + uint8_t initCount) { + return new CountingSemaphore(count, initCount); +} + +void SemaphoreFactory::deleteMutex(SemaphoreIF* semaphore) { + delete semaphore; +} diff --git a/tasks/SemaphoreFactory.h b/tasks/SemaphoreFactory.h new file mode 100644 index 00000000..fa95399a --- /dev/null +++ b/tasks/SemaphoreFactory.h @@ -0,0 +1,45 @@ +#ifndef FRAMEWORK_TASKS_SEMAPHOREFACTORY_H_ +#define FRAMEWORK_TASKS_SEMAPHOREFACTORY_H_ +#include + +/** + * Creates Semaphore. + * This class is a "singleton" interface, i.e. it provides an + * interface, but also is the base class for a singleton. + */ +class SemaphoreFactory { +public: + virtual ~SemaphoreFactory(); + /** + * Returns the single instance of SemaphoreFactory. + * The implementation of #instance is found in its subclasses. + * Thus, we choose link-time variability of the instance. + */ + static SemaphoreFactory* instance(); + + /** + * Create a binary semaphore. + * Creator function for a binary semaphore which may only be acquired once + * @return Pointer to newly created semaphore class instance. + */ + SemaphoreIF* createBinarySemaphore(); + /** + * Create a counting semaphore. + * Creator functons for a counting semaphore which may be acquired multiple + * times. + * @param count Semaphore can be taken count times. + * @param initCount Initial count value. + * @return + */ + SemaphoreIF* createCountingSemaphore(uint8_t count, uint8_t initCount); + void deleteMutex(SemaphoreIF* mutex); + +private: + /** + * External instantiation is not allowed. + */ + SemaphoreFactory(); + static SemaphoreFactory* factoryInstance; +}; + +#endif /* FRAMEWORK_TASKS_SEMAPHOREFACTORY_H_ */ From 066930b110730c8c781f0b680e1f7b99f1dbe920 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 20:39:48 +0200 Subject: [PATCH 35/94] improvements --- osal/FreeRTOS/BinarySemaphore.cpp | 42 +++++++++++++++--------------- osal/FreeRTOS/BinarySemaphore.h | 20 +++++++------- osal/FreeRTOS/CountingSemaphore.h | 10 ++++++- osal/FreeRTOS/SemaphoreFactory.cpp | 2 +- 4 files changed, 41 insertions(+), 33 deletions(-) diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index 11e48153..f08e3b81 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -3,7 +3,7 @@ #include -Semaphore::Semaphore() { +BinarySemaphore::BinarySemaphore() { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { sif::error << "Semaphore: Binary semaph creation failure" << std::endl; @@ -11,13 +11,13 @@ Semaphore::Semaphore() { xSemaphoreGive(handle); } -Semaphore::~Semaphore() { +BinarySemaphore::~BinarySemaphore() { vSemaphoreDelete(handle); } // This copy ctor is important as it prevents the assignment to a ressource // (other.handle) variable which is later deleted! -Semaphore::Semaphore(const Semaphore& other) { +BinarySemaphore::BinarySemaphore(const BinarySemaphore& other) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { sif::error << "Binary semaphore creation failure" << std::endl; @@ -25,7 +25,7 @@ Semaphore::Semaphore(const Semaphore& other) { xSemaphoreGive(handle); } -Semaphore& Semaphore::operator =(const Semaphore& s) { +BinarySemaphore& BinarySemaphore::operator =(const BinarySemaphore& s) { if(this != &s) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { @@ -36,7 +36,7 @@ Semaphore& Semaphore::operator =(const Semaphore& s) { return *this; } -Semaphore::Semaphore(Semaphore&& s) { +BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { sif::error << "Binary semaphore creation failure" << std::endl; @@ -44,8 +44,8 @@ Semaphore::Semaphore(Semaphore&& s) { xSemaphoreGive(handle); } -Semaphore& Semaphore::operator =( - Semaphore&& s) { +BinarySemaphore& BinarySemaphore::operator =( + BinarySemaphore&& s) { if(&s != this) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { @@ -56,15 +56,15 @@ Semaphore& Semaphore::operator =( return *this; } -ReturnValue_t Semaphore::takeBinarySemaphore(uint32_t timeoutMs) { +ReturnValue_t BinarySemaphore::takeBinarySemaphore(uint32_t timeoutMs) { if(handle == nullptr) { return SEMAPHORE_NULLPOINTER; } - TickType_t timeout = Semaphore::NO_BLOCK_TICKS; - if(timeoutMs == Semaphore::BLOCK_TIMEOUT) { - timeout = Semaphore::BLOCK_TIMEOUT_TICKS; + TickType_t timeout = BinarySemaphore::NO_BLOCK_TICKS; + if(timeoutMs == BinarySemaphore::BLOCK_TIMEOUT) { + timeout = BinarySemaphore::BLOCK_TIMEOUT_TICKS; } - else if(timeoutMs > Semaphore::NO_BLOCK_TIMEOUT){ + else if(timeoutMs > BinarySemaphore::NO_BLOCK_TIMEOUT){ timeout = pdMS_TO_TICKS(timeoutMs); } @@ -77,7 +77,7 @@ ReturnValue_t Semaphore::takeBinarySemaphore(uint32_t timeoutMs) { } } -ReturnValue_t Semaphore::takeBinarySemaphoreTickTimeout( +ReturnValue_t BinarySemaphore::takeBinarySemaphoreTickTimeout( TickType_t timeoutTicks) { if(handle == nullptr) { return SEMAPHORE_NULLPOINTER; @@ -91,7 +91,7 @@ ReturnValue_t Semaphore::takeBinarySemaphoreTickTimeout( } } -ReturnValue_t Semaphore::giveBinarySemaphore() { +ReturnValue_t BinarySemaphore::giveBinarySemaphore() { if (handle == nullptr) { return SEMAPHORE_NULLPOINTER; } @@ -103,11 +103,11 @@ ReturnValue_t Semaphore::giveBinarySemaphore() { } } -SemaphoreHandle_t Semaphore::getSemaphore() { +SemaphoreHandle_t BinarySemaphore::getSemaphore() { return handle; } -ReturnValue_t Semaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) { +ReturnValue_t BinarySemaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) { if (semaphore == nullptr) { return SEMAPHORE_NULLPOINTER; } @@ -119,7 +119,7 @@ ReturnValue_t Semaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) { } } -void Semaphore::resetSemaphore() { +void BinarySemaphore::resetSemaphore() { if(handle != nullptr) { vSemaphoreDelete(handle); handle = xSemaphoreCreateBinary(); @@ -127,20 +127,20 @@ void Semaphore::resetSemaphore() { } } -ReturnValue_t Semaphore::acquire(uint32_t timeoutMs) { +ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { return takeBinarySemaphore(timeoutMs); } -ReturnValue_t Semaphore::release() { +ReturnValue_t BinarySemaphore::release() { return giveBinarySemaphore(); } -uint8_t Semaphore::getSemaphoreCounter() { +uint8_t BinarySemaphore::getSemaphoreCounter() { return uxSemaphoreGetCount(handle); } // Be careful with the stack size here. This is called from an ISR! -ReturnValue_t Semaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, +ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken) { if (semaphore == nullptr) { return SEMAPHORE_NULLPOINTER; diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 6383432f..bd4ddb95 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -23,7 +23,7 @@ extern "C" { * @author R. Mueller * @ingroup osal */ -class Semaphore: public SemaphoreIF, +class BinarySemaphore: public SemaphoreIF, public HasReturnvaluesIF { public: static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; @@ -44,20 +44,20 @@ public: static constexpr ReturnValue_t SEMAPHORE_NULLPOINTER = MAKE_RETURN_CODE(3); //! @brief Default ctor - Semaphore(); + BinarySemaphore(); //! @brief Copy ctor - Semaphore(const Semaphore&); + BinarySemaphore(const BinarySemaphore&); //! @brief Copy assignment - Semaphore& operator=(const Semaphore&); + BinarySemaphore& operator=(const BinarySemaphore&); //! @brief Move ctor - Semaphore (Semaphore &&); + BinarySemaphore (BinarySemaphore &&); //! @brief Move assignment - Semaphore & operator=(Semaphore &&); + BinarySemaphore & operator=(BinarySemaphore &&); //! @brief Destructor - virtual ~Semaphore(); + virtual ~BinarySemaphore(); ReturnValue_t acquire(uint32_t timeoutMs = - Semaphore::NO_BLOCK_TIMEOUT) override; + BinarySemaphore::NO_BLOCK_TIMEOUT) override; ReturnValue_t release() override; uint8_t getSemaphoreCounter() override; @@ -71,7 +71,7 @@ public: * -@c RETURN_FAILED on failure */ ReturnValue_t takeBinarySemaphore(uint32_t timeoutMs = - Semaphore::NO_BLOCK_TIMEOUT); + BinarySemaphore::NO_BLOCK_TIMEOUT); /** * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. @@ -80,7 +80,7 @@ public: * - @c RETURN_FAILED on failure */ ReturnValue_t takeBinarySemaphoreTickTimeout(TickType_t timeoutTicks = - Semaphore::NO_BLOCK_TICKS); + BinarySemaphore::NO_BLOCK_TICKS); /** * Give back the binary semaphore diff --git a/osal/FreeRTOS/CountingSemaphore.h b/osal/FreeRTOS/CountingSemaphore.h index 8c059af5..a33a0fa5 100644 --- a/osal/FreeRTOS/CountingSemaphore.h +++ b/osal/FreeRTOS/CountingSemaphore.h @@ -2,7 +2,15 @@ #define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ #include -class CountingSemaphore: public Semaphore { +/** + * @brief Counting semaphores, which can be acquire more than once. + * @details + * See: https://www.freertos.org/CreateCounting.html + * API of counting semaphores is almost identical to binary semaphores, + * so we just inherit from binary semaphore and provide the respective + * constructors. + */ +class CountingSemaphore: public BinarySemaphore { public: CountingSemaphore(uint8_t count, uint8_t initCount); //! @brief Copy ctor, disabled diff --git a/osal/FreeRTOS/SemaphoreFactory.cpp b/osal/FreeRTOS/SemaphoreFactory.cpp index dd319025..9a355891 100644 --- a/osal/FreeRTOS/SemaphoreFactory.cpp +++ b/osal/FreeRTOS/SemaphoreFactory.cpp @@ -20,7 +20,7 @@ SemaphoreFactory* SemaphoreFactory::instance() { } SemaphoreIF* SemaphoreFactory::createBinarySemaphore() { - return new Semaphore(); + return new BinarySemaphore(); } SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t count, From 2790a40d6c35d27bb8e86121e02c6ca9f0ddf4ef Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 19 May 2020 18:55:13 +0200 Subject: [PATCH 36/94] some renamings --- tmtcpacket/pus/TcPacketBase.cpp | 30 +++++++++++++++--------------- tmtcpacket/pus/TcPacketBase.h | 4 ++-- tmtcpacket/pus/TcPacketStored.cpp | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/tmtcpacket/pus/TcPacketBase.cpp b/tmtcpacket/pus/TcPacketBase.cpp index 0972ffff..32caf5bb 100644 --- a/tmtcpacket/pus/TcPacketBase.cpp +++ b/tmtcpacket/pus/TcPacketBase.cpp @@ -13,28 +13,28 @@ TcPacketBase::~TcPacketBase() { } uint8_t TcPacketBase::getService() { - return tcData->data_field.service_type; + return tcData->dataField.service_type; } uint8_t TcPacketBase::getSubService() { - return tcData->data_field.service_subtype; + return tcData->dataField.service_subtype; } uint8_t TcPacketBase::getAcknowledgeFlags() { - return tcData->data_field.version_type_ack & 0b00001111; + return tcData->dataField.version_type_ack & 0b00001111; } const uint8_t* TcPacketBase::getApplicationData() const { - return &tcData->data; + return &tcData->appData; } uint16_t TcPacketBase::getApplicationDataSize() { - return getPacketDataLength() - sizeof(tcData->data_field) - CRC_SIZE + 1; + return getPacketDataLength() - sizeof(tcData->dataField) - CRC_SIZE + 1; } uint16_t TcPacketBase::getErrorControl() { uint16_t size = getApplicationDataSize() + CRC_SIZE; - uint8_t* p_to_buffer = &tcData->data; + uint8_t* p_to_buffer = &tcData->appData; return (p_to_buffer[size - 2] << 8) + p_to_buffer[size - 1]; } @@ -42,8 +42,8 @@ void TcPacketBase::setErrorControl() { uint32_t full_size = getFullSize(); uint16_t crc = CRC::crc16ccitt(getWholeData(), full_size - CRC_SIZE); uint32_t size = getApplicationDataSize(); - (&tcData->data)[size] = (crc & 0XFF00) >> 8; // CRCH - (&tcData->data)[size + 1] = (crc) & 0X00FF; // CRCL + (&tcData->appData)[size] = (crc & 0XFF00) >> 8; // CRCH + (&tcData->appData)[size + 1] = (crc) & 0X00FF; // CRCL } void TcPacketBase::setData(const uint8_t* pData) { @@ -59,11 +59,11 @@ void TcPacketBase::setApplicationData(const uint8_t * pData, uint16_t dataLen) { } uint8_t TcPacketBase::getSecondaryHeaderFlag() { - return (tcData->data_field.version_type_ack & 0b10000000) >> 7; + return (tcData->dataField.version_type_ack & 0b10000000) >> 7; } uint8_t TcPacketBase::getPusVersionNumber() { - return (tcData->data_field.version_type_ack & 0b01110000) >> 4; + return (tcData->dataField.version_type_ack & 0b01110000) >> 4; } void TcPacketBase::print() { @@ -78,14 +78,14 @@ void TcPacketBase::print() { void TcPacketBase::initializeTcPacket(uint16_t apid, uint16_t sequenceCount, uint8_t ack, uint8_t service, uint8_t subservice) { initSpacePacketHeader(true, true, apid, sequenceCount); - memset(&tcData->data_field, 0, sizeof(tcData->data_field)); + memset(&tcData->dataField, 0, sizeof(tcData->dataField)); setPacketDataLength(sizeof(PUSTcDataFieldHeader) + CRC_SIZE - 1); //Data Field Header: //Set CCSDS_secondary_header_flag to 0, version number to 001 and ack to 0000 - tcData->data_field.version_type_ack = 0b00010000; - tcData->data_field.version_type_ack |= (ack & 0x0F); - tcData->data_field.service_type = service; - tcData->data_field.service_subtype = subservice; + tcData->dataField.version_type_ack = 0b00010000; + tcData->dataField.version_type_ack |= (ack & 0x0F); + tcData->dataField.service_type = service; + tcData->dataField.service_subtype = subservice; } size_t TcPacketBase::calculateFullPacketLength(size_t appDataLen) { diff --git a/tmtcpacket/pus/TcPacketBase.h b/tmtcpacket/pus/TcPacketBase.h index 136aaa0b..9b858bd9 100644 --- a/tmtcpacket/pus/TcPacketBase.h +++ b/tmtcpacket/pus/TcPacketBase.h @@ -24,8 +24,8 @@ struct PUSTcDataFieldHeader { */ struct TcPacketPointer { CCSDSPrimaryHeader primary; - PUSTcDataFieldHeader data_field; - uint8_t data; + PUSTcDataFieldHeader dataField; + uint8_t appData; }; /** diff --git a/tmtcpacket/pus/TcPacketStored.cpp b/tmtcpacket/pus/TcPacketStored.cpp index 57b90bcc..47cf2ecd 100644 --- a/tmtcpacket/pus/TcPacketStored.cpp +++ b/tmtcpacket/pus/TcPacketStored.cpp @@ -24,7 +24,7 @@ TcPacketStored::TcPacketStored(uint8_t service, uint8_t subservice, } this->setData(p_data); initializeTcPacket(apid, sequence_count, ack, service, subservice); - memcpy(&tcData->data, data, size); + memcpy(&tcData->appData, data, size); this->setPacketDataLength( size + sizeof(PUSTcDataFieldHeader) + CRC_SIZE - 1); this->setErrorControl(); From f612b095c1c508466098576866827dc065dc9809 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 19 May 2020 19:39:19 +0200 Subject: [PATCH 37/94] updated tmtc packet base --- tmtcpacket/pus/TcPacketBase.cpp | 7 +++---- tmtcpacket/pus/TcPacketBase.h | 15 +++++++++------ tmtcpacket/pus/TmPacketBase.cpp | 5 +++++ tmtcpacket/pus/TmPacketBase.h | 7 +++++++ 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/tmtcpacket/pus/TcPacketBase.cpp b/tmtcpacket/pus/TcPacketBase.cpp index 32caf5bb..733c36df 100644 --- a/tmtcpacket/pus/TcPacketBase.cpp +++ b/tmtcpacket/pus/TcPacketBase.cpp @@ -51,11 +51,10 @@ void TcPacketBase::setData(const uint8_t* pData) { tcData = (TcPacketPointer*) pData; } -void TcPacketBase::setApplicationData(const uint8_t * pData, uint16_t dataLen) { - setData(pData); - // packet data length is actual size of data field minus 1 +void TcPacketBase::setAppData(uint8_t * appData, uint16_t dataLen) { + memcpy(&tcData->appData, appData, dataLen); SpacePacketBase::setPacketDataLength(dataLen + - sizeof(PUSTcDataFieldHeader) + TcPacketBase::CRC_SIZE - 1); + sizeof(PUSTcDataFieldHeader) + TcPacketBase::CRC_SIZE - 1); } uint8_t TcPacketBase::getSecondaryHeaderFlag() { diff --git a/tmtcpacket/pus/TcPacketBase.h b/tmtcpacket/pus/TcPacketBase.h index 9b858bd9..73076176 100644 --- a/tmtcpacket/pus/TcPacketBase.h +++ b/tmtcpacket/pus/TcPacketBase.h @@ -168,6 +168,14 @@ public: * current content of the packet. */ void setErrorControl(); + + /** + * Copies the supplied data to the internal TC application data field. + * @param pData + * @param dataLen + */ + void setAppData(uint8_t * appData, uint16_t dataLen); + /** * With this method, the packet data pointer can be redirected to another * location. @@ -178,12 +186,7 @@ public: * @param p_data A pointer to another PUS Telecommand Packet. */ void setData( const uint8_t* pData ); - /** - * Set application data and corresponding length field. - * @param pData - * @param dataLen - */ - void setApplicationData(const uint8_t * pData, uint16_t dataLen); + /** * This is a debugging helper method that prints the whole packet content * to the screen. diff --git a/tmtcpacket/pus/TmPacketBase.cpp b/tmtcpacket/pus/TmPacketBase.cpp index a7bda5af..a2c27ce1 100644 --- a/tmtcpacket/pus/TmPacketBase.cpp +++ b/tmtcpacket/pus/TmPacketBase.cpp @@ -102,6 +102,11 @@ void TmPacketBase::initializeTmPacket(uint16_t apid, uint8_t service, uint8_t su } } +void TmPacketBase::setSourceData(uint8_t* sourceData, size_t sourceSize) { + memcpy(getSourceData(), sourceData, sourceSize); + setSourceDataSize(sourceSize); +} + void TmPacketBase::setSourceDataSize(uint16_t size) { setPacketDataLength(size + sizeof(PUSTmDataFieldHeader) + CRC_SIZE - 1); } diff --git a/tmtcpacket/pus/TmPacketBase.h b/tmtcpacket/pus/TmPacketBase.h index d03beba5..6f3c4b59 100644 --- a/tmtcpacket/pus/TmPacketBase.h +++ b/tmtcpacket/pus/TmPacketBase.h @@ -125,6 +125,13 @@ public: * current content of the packet. */ void setErrorControl(); + /** + * This sets the source data. It copies the provided data to + * the internal TmPacketPointer source data location. + * @param sourceData + * @param sourceSize + */ + void setSourceData(uint8_t* sourceData, size_t sourceSize); /** * With this method, the packet data pointer can be redirected to another * location. From e2418d61a6263f67f2db96ac265f0e271766a28c Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 19 May 2020 19:53:10 +0200 Subject: [PATCH 38/94] improved printer --- globalfunctions/printer.cpp | 24 +++++++++++++++++------- globalfunctions/printer.h | 7 ++++--- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/globalfunctions/printer.cpp b/globalfunctions/printer.cpp index bf4c5848..01ec532c 100644 --- a/globalfunctions/printer.cpp +++ b/globalfunctions/printer.cpp @@ -1,36 +1,46 @@ #include #include -void printer::print(uint8_t *data, size_t size, OutputType type) { - sif::info << "Printing data with size " << size << ": ["; +void printer::print(uint8_t *data, size_t size, OutputType type, bool printInfo, + size_t maxCharPerLine) { + if(printInfo) { + sif::info << "Printing data with size " << size << ": "; + } + sif::info << "["; if(type == OutputType::HEX) { - printer::printHex(data, size); + printer::printHex(data, size, maxCharPerLine); } else { - printer::printDec(data, size); + printer::printDec(data, size, maxCharPerLine); } } -void printer::printHex(uint8_t *data, size_t size) { +void printer::printHex(uint8_t *data, size_t size, size_t maxCharPerLine) { sif::info << std::hex; for(size_t i = 0; i < size; i++) { sif::info << "0x" << static_cast(data[i]); if(i < size - 1){ sif::info << " , "; + if(i > 0 and i % maxCharPerLine == 0) { + sif::info << std::endl; + } } + } sif::info << std::dec; sif::info << "]" << std::endl; } -void printer::printDec(uint8_t *data, size_t size) { +void printer::printDec(uint8_t *data, size_t size, size_t maxCharPerLine) { sif::info << std::dec; for(size_t i = 0; i < size; i++) { sif::info << "0x" << static_cast(data[i]); if(i < size - 1){ sif::info << " , "; + if(i > 0 and i % maxCharPerLine == 0) { + sif::info << std::endl; + } } } sif::info << "]" << std::endl; } - diff --git a/globalfunctions/printer.h b/globalfunctions/printer.h index 3c9d6aa0..db9f343f 100644 --- a/globalfunctions/printer.h +++ b/globalfunctions/printer.h @@ -10,9 +10,10 @@ enum class OutputType { HEX }; -void print(uint8_t* data, size_t size, OutputType type = OutputType::HEX); -void printHex(uint8_t* data, size_t size); -void printDec(uint8_t* data, size_t size); +void print(uint8_t* data, size_t size, OutputType type = OutputType::HEX, + bool printInfo = true, size_t maxCharPerLine = 12); +void printHex(uint8_t* data, size_t size, size_t maxCharPerLine = 12); +void printDec(uint8_t* data, size_t size, size_t maxCharPerLine = 12); } #endif /* FRAMEWORK_GLOBALFUNCTIONS_PRINTER_H_ */ From 1aef000eff336b97917ac4c178d95749ec9cd5dc Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 19 May 2020 20:24:58 +0200 Subject: [PATCH 39/94] printer improvements and fixes tc packet stored getter function --- globalfunctions/printer.cpp | 10 +++++----- globalfunctions/printer.h | 6 +++--- tmtcpacket/pus/TcPacketStored.cpp | 12 ++++++++++++ tmtcpacket/pus/TcPacketStored.h | 3 +++ 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/globalfunctions/printer.cpp b/globalfunctions/printer.cpp index 01ec532c..f099113c 100644 --- a/globalfunctions/printer.cpp +++ b/globalfunctions/printer.cpp @@ -1,8 +1,8 @@ #include #include -void printer::print(uint8_t *data, size_t size, OutputType type, bool printInfo, - size_t maxCharPerLine) { +void printer::print(const uint8_t *data, size_t size, OutputType type, + bool printInfo, size_t maxCharPerLine) { if(printInfo) { sif::info << "Printing data with size " << size << ": "; } @@ -15,7 +15,7 @@ void printer::print(uint8_t *data, size_t size, OutputType type, bool printInfo, } } -void printer::printHex(uint8_t *data, size_t size, size_t maxCharPerLine) { +void printer::printHex(const uint8_t *data, size_t size, size_t maxCharPerLine) { sif::info << std::hex; for(size_t i = 0; i < size; i++) { sif::info << "0x" << static_cast(data[i]); @@ -31,10 +31,10 @@ void printer::printHex(uint8_t *data, size_t size, size_t maxCharPerLine) { sif::info << "]" << std::endl; } -void printer::printDec(uint8_t *data, size_t size, size_t maxCharPerLine) { +void printer::printDec(const uint8_t *data, size_t size, size_t maxCharPerLine) { sif::info << std::dec; for(size_t i = 0; i < size; i++) { - sif::info << "0x" << static_cast(data[i]); + sif::info << static_cast(data[i]); if(i < size - 1){ sif::info << " , "; if(i > 0 and i % maxCharPerLine == 0) { diff --git a/globalfunctions/printer.h b/globalfunctions/printer.h index db9f343f..76d28e5f 100644 --- a/globalfunctions/printer.h +++ b/globalfunctions/printer.h @@ -10,10 +10,10 @@ enum class OutputType { HEX }; -void print(uint8_t* data, size_t size, OutputType type = OutputType::HEX, +void print(const uint8_t* data, size_t size, OutputType type = OutputType::HEX, bool printInfo = true, size_t maxCharPerLine = 12); -void printHex(uint8_t* data, size_t size, size_t maxCharPerLine = 12); -void printDec(uint8_t* data, size_t size, size_t maxCharPerLine = 12); +void printHex(const uint8_t* data, size_t size, size_t maxCharPerLine = 12); +void printDec(const uint8_t* data, size_t size, size_t maxCharPerLine = 12); } #endif /* FRAMEWORK_GLOBALFUNCTIONS_PRINTER_H_ */ diff --git a/tmtcpacket/pus/TcPacketStored.cpp b/tmtcpacket/pus/TcPacketStored.cpp index 47cf2ecd..64aa74dc 100644 --- a/tmtcpacket/pus/TcPacketStored.cpp +++ b/tmtcpacket/pus/TcPacketStored.cpp @@ -1,6 +1,7 @@ #include #include #include + #include TcPacketStored::TcPacketStored(store_address_t setAddress) : @@ -20,6 +21,8 @@ TcPacketStored::TcPacketStored(uint8_t service, uint8_t subservice, ReturnValue_t returnValue = this->store->getFreeElement(&this->storeAddress, (TC_PACKET_MIN_SIZE + size), &p_data); if (returnValue != this->store->RETURN_OK) { + sif::warning << "TcPacketStored: Could not get free element from store!" + << std::endl; return; } this->setData(p_data); @@ -30,6 +33,15 @@ TcPacketStored::TcPacketStored(uint8_t service, uint8_t subservice, this->setErrorControl(); } +ReturnValue_t TcPacketStored::getData(const uint8_t ** dataPtr, + size_t* dataSize) { + auto result = this->store->getData(storeAddress, dataPtr, dataSize); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::warning << "TcPacketStored: Could not get data!" << std::endl; + } + return result; +} + TcPacketStored::TcPacketStored() : TcPacketBase(NULL) { this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; diff --git a/tmtcpacket/pus/TcPacketStored.h b/tmtcpacket/pus/TcPacketStored.h index a9c49c2e..de3eb85f 100644 --- a/tmtcpacket/pus/TcPacketStored.h +++ b/tmtcpacket/pus/TcPacketStored.h @@ -74,6 +74,9 @@ public: * @param Size size of the packet. */ TcPacketStored( const uint8_t* data, uint32_t size); + + ReturnValue_t getData(const uint8_t ** dataPtr, + size_t* dataSize); /** * This is a getter for the current store address of the packet. * @return The current store address. The (raw) value is \c StorageManagerIF::INVALID_ADDRESS if From 7afaa752f37422254f962982a41038afb0fbe8da Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 19 May 2020 20:25:54 +0200 Subject: [PATCH 40/94] form improvement --- globalfunctions/printer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/globalfunctions/printer.cpp b/globalfunctions/printer.cpp index f099113c..b71d70b8 100644 --- a/globalfunctions/printer.cpp +++ b/globalfunctions/printer.cpp @@ -15,7 +15,8 @@ void printer::print(const uint8_t *data, size_t size, OutputType type, } } -void printer::printHex(const uint8_t *data, size_t size, size_t maxCharPerLine) { +void printer::printHex(const uint8_t *data, size_t size, + size_t maxCharPerLine) { sif::info << std::hex; for(size_t i = 0; i < size; i++) { sif::info << "0x" << static_cast(data[i]); @@ -31,7 +32,8 @@ void printer::printHex(const uint8_t *data, size_t size, size_t maxCharPerLine) sif::info << "]" << std::endl; } -void printer::printDec(const uint8_t *data, size_t size, size_t maxCharPerLine) { +void printer::printDec(const uint8_t *data, size_t size, + size_t maxCharPerLine) { sif::info << std::dec; for(size_t i = 0; i < size; i++) { sif::info << static_cast(data[i]); From 9b53e2b64fe9327f55eb12b393a91c666b836dde Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 19 May 2020 22:45:48 +0200 Subject: [PATCH 41/94] added informative comment for counting semaphore --- osal/FreeRTOS/CountingSemaphore.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osal/FreeRTOS/CountingSemaphore.cpp b/osal/FreeRTOS/CountingSemaphore.cpp index adf3f23c..2b81848a 100644 --- a/osal/FreeRTOS/CountingSemaphore.cpp +++ b/osal/FreeRTOS/CountingSemaphore.cpp @@ -1,6 +1,8 @@ #include #include +// Make sure #define configUSE_COUNTING_SEMAPHORES 1 is set in +// free FreeRTOSConfig.h file. CountingSemaphore::CountingSemaphore(uint8_t count, uint8_t initCount): count(count), initCount(initCount) { handle = xSemaphoreCreateCounting(count, initCount); From 338651af2f7a67422cda787b56b513f020325df4 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 19 May 2020 23:07:28 +0200 Subject: [PATCH 42/94] binary printer added --- globalfunctions/printer.cpp | 15 ++++++++++++++- globalfunctions/printer.h | 4 +++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/globalfunctions/printer.cpp b/globalfunctions/printer.cpp index b71d70b8..a68a91ee 100644 --- a/globalfunctions/printer.cpp +++ b/globalfunctions/printer.cpp @@ -1,5 +1,6 @@ #include #include +#include void printer::print(const uint8_t *data, size_t size, OutputType type, bool printInfo, size_t maxCharPerLine) { @@ -10,9 +11,12 @@ void printer::print(const uint8_t *data, size_t size, OutputType type, if(type == OutputType::HEX) { printer::printHex(data, size, maxCharPerLine); } - else { + else if (type == OutputType::DEC) { printer::printDec(data, size, maxCharPerLine); } + else if(type == OutputType::BIN) { + printer::printBin(data, size); + } } void printer::printHex(const uint8_t *data, size_t size, @@ -46,3 +50,12 @@ void printer::printDec(const uint8_t *data, size_t size, } sif::info << "]" << std::endl; } + +void printer::printBin(const uint8_t *data, size_t size) { + sif::info << "\n" << std::flush; + for(size_t i = 0; i < size; i++) { + sif::info << "Byte " << i + 1 << ": 0b"<< + std::bitset<8>(data[i]) << ",\n" << std::flush; + } + sif::info << "]" << std::endl; +} diff --git a/globalfunctions/printer.h b/globalfunctions/printer.h index 76d28e5f..33a382ec 100644 --- a/globalfunctions/printer.h +++ b/globalfunctions/printer.h @@ -7,13 +7,15 @@ namespace printer { enum class OutputType { DEC, - HEX + HEX, + BIN }; void print(const uint8_t* data, size_t size, OutputType type = OutputType::HEX, bool printInfo = true, size_t maxCharPerLine = 12); void printHex(const uint8_t* data, size_t size, size_t maxCharPerLine = 12); void printDec(const uint8_t* data, size_t size, size_t maxCharPerLine = 12); +void printBin(const uint8_t* data, size_t size); } #endif /* FRAMEWORK_GLOBALFUNCTIONS_PRINTER_H_ */ From f6b17d6e2ea6156d06214937c70bee305707a836 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 20 May 2020 12:50:56 +0200 Subject: [PATCH 43/94] deleted copyctor and copy assignment --- osal/FreeRTOS/BinarySemaphore.cpp | 21 --------------------- osal/FreeRTOS/BinarySemaphore.h | 8 ++++---- 2 files changed, 4 insertions(+), 25 deletions(-) diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index c4a363b4..026704d6 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -15,27 +15,6 @@ BinarySemaphore::~BinarySemaphore() { vSemaphoreDelete(handle); } -// This copy ctor is important as it prevents the assignment to a ressource -// (other.handle) variable which is later deleted! -BinarySemaphore::BinarySemaphore(const BinarySemaphore& other) { - handle = xSemaphoreCreateBinary(); - if(handle == nullptr) { - sif::error << "Binary semaphore creation failure" << std::endl; - } - xSemaphoreGive(handle); -} - -BinarySemaphore& BinarySemaphore::operator =(const BinarySemaphore& s) { - if(this != &s) { - handle = xSemaphoreCreateBinary(); - if(handle == nullptr) { - sif::error << "Binary semaphore creation failure" << std::endl; - } - xSemaphoreGive(handle); - } - return *this; -} - BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 0c9c0992..5f69dc90 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -39,10 +39,10 @@ public: //! @brief Default ctor BinarySemaphore(); - //! @brief Copy ctor - BinarySemaphore(const BinarySemaphore&); - //! @brief Copy assignment - BinarySemaphore& operator=(const BinarySemaphore&); + //! @brief Copy ctor, deleted explicitely. + BinarySemaphore(const BinarySemaphore&) = delete; + //! @brief Copy assignment, deleted explicitely. + BinarySemaphore& operator=(const BinarySemaphore&) = delete; //! @brief Move ctor BinarySemaphore (BinarySemaphore &&); //! @brief Move assignment From d2d1ef9a854727a0381ccab719d2a8cba8a4acf0 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 22 May 2020 00:58:30 +0200 Subject: [PATCH 44/94] better include guards --- storagemanager/LocalPool.tpp | 4 ++-- storagemanager/PoolManager.h | 4 ++-- storagemanager/PoolManager.tpp | 4 ++-- storagemanager/StorageAccessor.h | 25 +++++++++++-------------- 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/storagemanager/LocalPool.tpp b/storagemanager/LocalPool.tpp index 59d06ab8..32724bd8 100644 --- a/storagemanager/LocalPool.tpp +++ b/storagemanager/LocalPool.tpp @@ -1,5 +1,5 @@ -#ifndef LOCALPOOL_TPP -#define LOCALPOOL_TPP +#ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_TPP_ +#define FRAMEWORK_STORAGEMANAGER_LOCALPOOL_TPP_ template inline LocalPool::LocalPool(object_id_t setObjectId, diff --git a/storagemanager/PoolManager.h b/storagemanager/PoolManager.h index 87670a82..6e353de2 100644 --- a/storagemanager/PoolManager.h +++ b/storagemanager/PoolManager.h @@ -1,5 +1,5 @@ -#ifndef POOLMANAGER_H_ -#define POOLMANAGER_H_ +#ifndef FRAMEWORK_STORAGEMANAGER_POOLMANAGER_H_ +#define FRAMEWORK_STORAGEMANAGER_POOLMANAGER_H_ #include #include diff --git a/storagemanager/PoolManager.tpp b/storagemanager/PoolManager.tpp index 7025d795..854e22da 100644 --- a/storagemanager/PoolManager.tpp +++ b/storagemanager/PoolManager.tpp @@ -1,5 +1,5 @@ -#ifndef POOLMANAGER_TPP_ -#define POOLMANAGER_TPP_ +#ifndef FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ +#define FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ template inline PoolManager::PoolManager(object_id_t setObjectId, diff --git a/storagemanager/StorageAccessor.h b/storagemanager/StorageAccessor.h index 8949642c..f6964b93 100644 --- a/storagemanager/StorageAccessor.h +++ b/storagemanager/StorageAccessor.h @@ -1,22 +1,19 @@ -/** - * @brief Helper classes to facilitate safe access to storages which is also - * conforming to RAII principles - * @details These helper can be used together with the - * StorageManager classes to manage access to a storage. - * It can take care of thread-safety while also providing - * mechanisms to automatically clear storage data. - */ -#ifndef TEST_PROTOTYPES_STORAGEACCESSOR_H_ -#define TEST_PROTOTYPES_STORAGEACCESSOR_H_ +#ifndef FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ +#define FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ #include #include -#include /** - * @brief Accessor class which can be returned by pool managers - * or passed and set by pool managers to have safe access to the pool - * resources. + * @brief Helper classes to facilitate safe access to storages which is also + * conforming to RAII principles + * @details + * Accessor class which can be returned by pool manager or passed and set by + * pool managers to have safe access to the pool resources. + * + * These helper can be used together with the StorageManager classes to manage + * access to a storage. It can take care of thread-safety while also providing + * mechanisms to automatically clear storage data. */ class ConstStorageAccessor { //! StorageManager classes have exclusive access to private variables. From d4abfacd27b09c17f898e80c62f969610a5d6367 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 22 May 2020 01:15:02 +0200 Subject: [PATCH 45/94] found solution for circ dependency had to put store_address_t in own file though --- storagemanager/StorageAccessor.cpp | 1 + storagemanager/StorageAccessor.h | 4 ++- storagemanager/StorageManagerIF.h | 56 ++---------------------------- storagemanager/storeAddress.h | 54 ++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 54 deletions(-) create mode 100644 storagemanager/storeAddress.h diff --git a/storagemanager/StorageAccessor.cpp b/storagemanager/StorageAccessor.cpp index cc292d6c..c0c8126b 100644 --- a/storagemanager/StorageAccessor.cpp +++ b/storagemanager/StorageAccessor.cpp @@ -1,4 +1,5 @@ #include +#include ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId): storeId(storeId) {} diff --git a/storagemanager/StorageAccessor.h b/storagemanager/StorageAccessor.h index f6964b93..57c9369c 100644 --- a/storagemanager/StorageAccessor.h +++ b/storagemanager/StorageAccessor.h @@ -2,7 +2,9 @@ #define FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ #include -#include +#include + +class StorageManagerIF; /** * @brief Helper classes to facilitate safe access to storages which is also diff --git a/storagemanager/StorageManagerIF.h b/storagemanager/StorageManagerIF.h index 559c4b9a..af5aeb73 100644 --- a/storagemanager/StorageManagerIF.h +++ b/storagemanager/StorageManagerIF.h @@ -3,64 +3,14 @@ #include #include -#include +#include +#include #include - -class StorageAccessor; -class ConstStorageAccessor; +#include using AccessorPair = std::pair; using ConstAccessorPair = std::pair; -/** - * This union defines the type that identifies where a data packet is - * stored in the store. It comprises of a raw part to read it as raw value and - * a structured part to use it in pool-like stores. - */ -union store_address_t { - /** - * Default Constructor, initializing to INVALID_ADDRESS - */ - store_address_t():raw(0xFFFFFFFF){} - /** - * Constructor to create an address object using the raw address - * - * @param rawAddress - */ - store_address_t(uint32_t rawAddress):raw(rawAddress){} - - /** - * Constructor to create an address object using pool - * and packet indices - * - * @param poolIndex - * @param packetIndex - */ - store_address_t(uint16_t poolIndex, uint16_t packetIndex): - pool_index(poolIndex),packet_index(packetIndex){} - /** - * A structure with two elements to access the store address pool-like. - */ - struct { - /** - * The index in which pool the packet lies. - */ - uint16_t pool_index; - /** - * The position in the chosen pool. - */ - uint16_t packet_index; - }; - /** - * Alternative access to the raw value. - */ - uint32_t raw; - - bool operator==(const store_address_t& other) const { - return raw == other.raw; - } -}; - /** * @brief This class provides an interface for intermediate data storage. * @details The Storage manager classes shall be used to store larger chunks of diff --git a/storagemanager/storeAddress.h b/storagemanager/storeAddress.h new file mode 100644 index 00000000..5dd785a3 --- /dev/null +++ b/storagemanager/storeAddress.h @@ -0,0 +1,54 @@ +#ifndef FRAMEWORK_STORAGEMANAGER_STOREADDRESS_H_ +#define FRAMEWORK_STORAGEMANAGER_STOREADDRESS_H_ +#include + +/** + * This union defines the type that identifies where a data packet is + * stored in the store. It comprises of a raw part to read it as raw value and + * a structured part to use it in pool-like stores. + */ +union store_address_t { + /** + * Default Constructor, initializing to INVALID_ADDRESS + */ + store_address_t():raw(0xFFFFFFFF){} + /** + * Constructor to create an address object using the raw address + * + * @param rawAddress + */ + store_address_t(uint32_t rawAddress):raw(rawAddress){} + + /** + * Constructor to create an address object using pool + * and packet indices + * + * @param poolIndex + * @param packetIndex + */ + store_address_t(uint16_t poolIndex, uint16_t packetIndex): + pool_index(poolIndex),packet_index(packetIndex){} + /** + * A structure with two elements to access the store address pool-like. + */ + struct { + /** + * The index in which pool the packet lies. + */ + uint16_t pool_index; + /** + * The position in the chosen pool. + */ + uint16_t packet_index; + }; + /** + * Alternative access to the raw value. + */ + uint32_t raw; + + bool operator==(const store_address_t& other) const { + return raw == other.raw; + } +}; + +#endif /* FRAMEWORK_STORAGEMANAGER_STOREADDRESS_H_ */ From 2f16b1e7336a1b174bfc0da4ae5437c925c6ac21 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 25 May 2020 13:48:43 +0200 Subject: [PATCH 46/94] moved some files --- datapool/PoolRawAccessHelper.h | 2 +- datapoolglob/DataPoolAdmin.cpp | 2 +- datapoolglob/DataPoolParameterWrapper.cpp | 2 +- {datapool => datapoolglob}/PIDReader.h | 0 {datapool => datapoolglob}/PIDReaderList.h | 8 ++++---- {datapool => datapoolglob}/PoolRawAccess.cpp | 2 +- {datapool => datapoolglob}/PoolRawAccess.h | 0 monitoring/MonitorBase.h | 2 +- power/Fuse.h | 2 +- power/PowerSensor.h | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) rename {datapool => datapoolglob}/PIDReader.h (100%) rename {datapool => datapoolglob}/PIDReaderList.h (73%) rename {datapool => datapoolglob}/PoolRawAccess.cpp (99%) rename {datapool => datapoolglob}/PoolRawAccess.h (100%) diff --git a/datapool/PoolRawAccessHelper.h b/datapool/PoolRawAccessHelper.h index f2434241..52d9ebe5 100644 --- a/datapool/PoolRawAccessHelper.h +++ b/datapool/PoolRawAccessHelper.h @@ -7,9 +7,9 @@ #ifndef FRAMEWORK_DATAPOOL_POOLRAWACCESSHELPER_H_ #define FRAMEWORK_DATAPOOL_POOLRAWACCESSHELPER_H_ -#include #include #include +#include /** * @brief This helper function simplifies accessing data pool entries diff --git a/datapoolglob/DataPoolAdmin.cpp b/datapoolglob/DataPoolAdmin.cpp index f32ff567..05de1eb2 100644 --- a/datapoolglob/DataPoolAdmin.cpp +++ b/datapoolglob/DataPoolAdmin.cpp @@ -1,7 +1,7 @@ #include -#include #include #include +#include #include #include #include diff --git a/datapoolglob/DataPoolParameterWrapper.cpp b/datapoolglob/DataPoolParameterWrapper.cpp index d93cd88e..062cff12 100644 --- a/datapoolglob/DataPoolParameterWrapper.cpp +++ b/datapoolglob/DataPoolParameterWrapper.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include diff --git a/datapool/PIDReader.h b/datapoolglob/PIDReader.h similarity index 100% rename from datapool/PIDReader.h rename to datapoolglob/PIDReader.h diff --git a/datapool/PIDReaderList.h b/datapoolglob/PIDReaderList.h similarity index 73% rename from datapool/PIDReaderList.h rename to datapoolglob/PIDReaderList.h index 07d1b8e6..0b838508 100644 --- a/datapool/PIDReaderList.h +++ b/datapoolglob/PIDReaderList.h @@ -1,8 +1,8 @@ -#ifndef FRAMEWORK_DATAPOOL_PIDREADERLIST_H_ -#define FRAMEWORK_DATAPOOL_PIDREADERLIST_H_ +#ifndef FRAMEWORK_DATAPOOLGLOB_PIDREADERLIST_H_ +#define FRAMEWORK_DATAPOOLGLOB_PIDREADERLIST_H_ -#include #include +#include template class PIDReaderList { private: @@ -24,4 +24,4 @@ public: -#endif /* FRAMEWORK_DATAPOOL_PIDREADERLIST_H_ */ +#endif /* FRAMEWORK_DATAPOOLGLOB_PIDREADERLIST_H_ */ diff --git a/datapool/PoolRawAccess.cpp b/datapoolglob/PoolRawAccess.cpp similarity index 99% rename from datapool/PoolRawAccess.cpp rename to datapoolglob/PoolRawAccess.cpp index 778e1b9c..cc04f9b9 100644 --- a/datapool/PoolRawAccess.cpp +++ b/datapoolglob/PoolRawAccess.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include diff --git a/datapool/PoolRawAccess.h b/datapoolglob/PoolRawAccess.h similarity index 100% rename from datapool/PoolRawAccess.h rename to datapoolglob/PoolRawAccess.h diff --git a/monitoring/MonitorBase.h b/monitoring/MonitorBase.h index d66e956d..f18ca4b5 100644 --- a/monitoring/MonitorBase.h +++ b/monitoring/MonitorBase.h @@ -2,7 +2,7 @@ #define MONITORBASE_H_ #include -#include +#include #include #include #include diff --git a/power/Fuse.h b/power/Fuse.h index 44f8964f..0f258b63 100644 --- a/power/Fuse.h +++ b/power/Fuse.h @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include #include diff --git a/power/PowerSensor.h b/power/PowerSensor.h index f94088a8..0fb47506 100644 --- a/power/PowerSensor.h +++ b/power/PowerSensor.h @@ -2,8 +2,8 @@ #define POWERSENSOR_H_ #include -#include #include +#include #include #include #include From 723e715022e6d5ada2dfdee9da5a6f3d7450faa9 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 25 May 2020 14:01:35 +0200 Subject: [PATCH 47/94] consistency fix --- storagemanager/LocalPool.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storagemanager/LocalPool.h b/storagemanager/LocalPool.h index 6892b881..c155f918 100644 --- a/storagemanager/LocalPool.h +++ b/storagemanager/LocalPool.h @@ -12,7 +12,7 @@ /** * @brief The LocalPool class provides an intermediate data storage with * a fixed pool size policy. - * \details The class implements the StorageManagerIF interface. While the + * @details The class implements the StorageManagerIF interface. While the * total number of pools is fixed, the element sizes in one pool and * the number of pool elements per pool are set on construction. * The full amount of memory is allocated on construction. From 50fd86edc1a9d35e681eb730f2e838733a24254d Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 25 May 2020 15:03:31 +0200 Subject: [PATCH 48/94] removed shoulddo, issue will be created --- modes/ModeMessage.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/modes/ModeMessage.h b/modes/ModeMessage.h index 0a72aee0..f72fdeec 100644 --- a/modes/ModeMessage.h +++ b/modes/ModeMessage.h @@ -23,8 +23,6 @@ public: static const Command_t REPLY_MODE_REPLY = MAKE_COMMAND_ID(0x02);//!> Reply to a CMD_MODE_COMMAND or CMD_MODE_READ static const Command_t REPLY_MODE_INFO = MAKE_COMMAND_ID(0x03); //!> Unrequested info about the current mode (used for composites to inform their container of a changed mode) static const Command_t REPLY_CANT_REACH_MODE = MAKE_COMMAND_ID(0x04); //!> Reply in case a mode command can't be executed. Par1: returnCode, Par2: 0 - //SHOULDDO is there a way we can transmit a returnvalue when responding that the mode is wrong, so we can give a nice failure code when commanded by PUS? - // shouldn't that possible with parameter 2 when submode only takes 1 byte? static const Command_t REPLY_WRONG_MODE_REPLY = MAKE_COMMAND_ID(0x05);//!> Reply to a CMD_MODE_COMMAND, indicating that a mode was commanded and a transition started but was aborted; the parameters contain the mode that was reached static const Command_t CMD_MODE_READ = MAKE_COMMAND_ID(0x06);//!> Command to read the current mode and reply with a REPLY_MODE_REPLY static const Command_t CMD_MODE_ANNOUNCE = MAKE_COMMAND_ID(0x07);//!> Command to trigger an ModeInfo Event. This command does NOT have a reply. From a37f01cd0ee31c57f8f76f3b299c2f51718e9d85 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 25 May 2020 23:11:56 +0200 Subject: [PATCH 49/94] improved readability of mode explanations --- devicehandlers/DeviceHandlerIF.h | 60 ++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/devicehandlers/DeviceHandlerIF.h b/devicehandlers/DeviceHandlerIF.h index 34aa4114..59ee1853 100644 --- a/devicehandlers/DeviceHandlerIF.h +++ b/devicehandlers/DeviceHandlerIF.h @@ -28,19 +28,57 @@ public: // 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; //!< It is possible to set the mode to _MODE_TO_ON to use the to on transition if available. + //!< 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; - 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 + //! 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 SUBSYSTEM_ID = SUBSYSTEM_ID::CDH; static const Event DEVICE_BUILDING_COMMAND_FAILED = MAKE_EVENT(0, SEVERITY::LOW); From 18d19fbb2c7575cf7b880e0caebf5cbcbc447358 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 25 May 2020 23:12:25 +0200 Subject: [PATCH 50/94] < removed --- devicehandlers/DeviceHandlerIF.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devicehandlers/DeviceHandlerIF.h b/devicehandlers/DeviceHandlerIF.h index 59ee1853..f6b29e25 100644 --- a/devicehandlers/DeviceHandlerIF.h +++ b/devicehandlers/DeviceHandlerIF.h @@ -28,7 +28,7 @@ public: // 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 + //! 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; From eacda67f027dc24a65f60f08b837b2358aa094f5 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 25 May 2020 23:36:03 +0200 Subject: [PATCH 51/94] added some comments for returnvalues --- devicehandlers/DeviceHandlerBase.h | 34 ++++++++++++++++-------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index 454f0751..cfa9396a 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -509,26 +509,28 @@ protected: */ static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE; - /** - * These returnvalues can be returned from abstract functions + /* These returnvalues can be returned from abstract functions * to alter the behaviour of DHB.For error values, refer to - * DeviceHandlerIF.h returnvalues. - */ - static const ReturnValue_t INVALID_CHANNEL = MAKE_RETURN_CODE(4); + * DeviceHandlerIF.h returnvalues. */ + // (Robin): maybe this would be better in DeviceHandlerIF? + static const ReturnValue_t INVALID_CHANNEL = MAKE_RETURN_CODE(0xA0); + // Returnvalues for scanForReply() - static const ReturnValue_t APERIODIC_REPLY = MAKE_RETURN_CODE(5); //!< This is used to specify for replies from a device which are not replies to requests - static const ReturnValue_t IGNORE_REPLY_DATA = MAKE_RETURN_CODE(6); //!< Ignore parts of the received packet - static const ReturnValue_t IGNORE_FULL_PACKET = MAKE_RETURN_CODE(7); //!< Ignore full received packet + static const ReturnValue_t 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 -// 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); + // 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 NO_SWITCH = MAKE_RETURN_CODE(0xC1); + // (Robin): Maybe this would be better in DeviceHandlerIF? + static const ReturnValue_t COMMAND_MAP_ERROR = MAKE_RETURN_CODE(0xC2); + static const ReturnValue_t NOTHING_TO_SEND = MAKE_RETURN_CODE(0xC3); - //Mode handling error Codes - static const ReturnValue_t CHILD_TIMEOUT = MAKE_RETURN_CODE(0xE1); - static const ReturnValue_t SWITCH_FAILED = MAKE_RETURN_CODE(0xE2); + // (Robin): Maybe this would be better in DeviceHandlerIF? + // Mode handling error Codes + static const ReturnValue_t CHILD_TIMEOUT = MAKE_RETURN_CODE(0xD0); + static const ReturnValue_t SWITCH_FAILED = MAKE_RETURN_CODE(0xD1); static const DeviceCommandId_t RAW_COMMAND_ID = -1; static const DeviceCommandId_t NO_COMMAND_ID = -2; From 243ea9cd8782a4edd74259351b8fb536fdf95bca Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 25 May 2020 23:38:51 +0200 Subject: [PATCH 52/94] improved dhb IF returnvalues --- devicehandlers/DeviceHandlerIF.h | 119 ++++++++++++++++++------------- 1 file changed, 69 insertions(+), 50 deletions(-) diff --git a/devicehandlers/DeviceHandlerIF.h b/devicehandlers/DeviceHandlerIF.h index 34aa4114..666d9efc 100644 --- a/devicehandlers/DeviceHandlerIF.h +++ b/devicehandlers/DeviceHandlerIF.h @@ -28,19 +28,57 @@ public: // 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; //!< It is possible to set the mode to _MODE_TO_ON to use the to on transition if available. + //! 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; - 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 + //! 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 SUBSYSTEM_ID = SUBSYSTEM_ID::CDH; static const Event DEVICE_BUILDING_COMMAND_FAILED = MAKE_EVENT(0, SEVERITY::LOW); @@ -58,47 +96,34 @@ public: static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_IF; // Standard codes used when building commands. - static const ReturnValue_t NOTHING_TO_SEND = MAKE_RETURN_CODE(0xA0); //!< Return this if no command sending in required - // Mostly used for internal handling. - static const ReturnValue_t NO_COMMAND_DATA = MAKE_RETURN_CODE(0xA2); //!< If the command size is 0. Checked in DHB - static const ReturnValue_t NO_REPLY_EXPECTED = MAKE_RETURN_CODE(0xA3); //!< Used to indicate that this is a command-only command. - static const ReturnValue_t COMMAND_NOT_SUPPORTED = MAKE_RETURN_CODE(0xA4); //!< Command ID not in commandMap. Checked in DHB - static const ReturnValue_t COMMAND_ALREADY_SENT = MAKE_RETURN_CODE(0xA5); //!< Command was already executed. Checked in DHB - static const ReturnValue_t COMMAND_WAS_NOT_SENT = MAKE_RETURN_CODE(0xA6); - static const ReturnValue_t CANT_SWITCH_ADDRESS = MAKE_RETURN_CODE(0xA7); - static const ReturnValue_t WRONG_MODE_FOR_COMMAND = MAKE_RETURN_CODE(0xA8); - static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(0xA9); - static const ReturnValue_t BUSY = MAKE_RETURN_CODE(0xAA); - static const ReturnValue_t NON_OP_TEMPERATURE = MAKE_RETURN_CODE(0xAB); - static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xAC); + 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 scanForReply - static const ReturnValue_t APERIODIC_REPLY = MAKE_RETURN_CODE(0xB1); //!< This is used to specify for replies from a device which are not replies to requests - static const ReturnValue_t LENGTH_MISSMATCH = MAKE_RETURN_CODE(0xB2); - static const ReturnValue_t IGNORE_REPLY_DATA = MAKE_RETURN_CODE(0xB3); //!< Ignore parts of the received packet - static const ReturnValue_t IGNORE_FULL_PACKET = MAKE_RETURN_CODE(0xB4); //!< Ignore full received packet - static const ReturnValue_t CHECKSUM_ERROR = MAKE_RETURN_CODE(0xB5); - static const ReturnValue_t INVALID_DATA = MAKE_RETURN_CODE(0xB6); - static const ReturnValue_t PROTOCOL_ERROR = MAKE_RETURN_CODE(0xB7); + 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(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 + 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); - // Standard codes used in getSwitches - static const ReturnValue_t NO_SWITCH = MAKE_RETURN_CODE(0xE1); //!< Return in getSwitches() to specify there are no switches - - // static const ReturnValue_t ONE_SWITCH = MAKE_RETURN_CODE(8); - // static const ReturnValue_t TWO_SWITCHES = MAKE_RETURN_CODE(9); - // where is this used? - // static const ReturnValue_t COMMAND_MAP_ERROR = MAKE_RETURN_CODE(11); - /** * Communication action that will be executed. * @@ -115,16 +140,10 @@ public: /** * 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; From 3fd306356a4b2eefeb78bf6f4cf6d197b7c5c7ec Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 25 May 2020 23:43:44 +0200 Subject: [PATCH 53/94] fix for dh returnvalues --- devicehandlers/DeviceHandlerBase.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index cfa9396a..74b84111 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -522,15 +522,16 @@ protected: // 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 NO_SWITCH = MAKE_RETURN_CODE(0xC1); // (Robin): Maybe this would be better in DeviceHandlerIF? static const ReturnValue_t COMMAND_MAP_ERROR = MAKE_RETURN_CODE(0xC2); - static const ReturnValue_t NOTHING_TO_SEND = MAKE_RETURN_CODE(0xC3); + + // Returnvalues for getSwitches() + static const ReturnValue_t NO_SWITCH = MAKE_RETURN_CODE(0xD0); // (Robin): Maybe this would be better in DeviceHandlerIF? // Mode handling error Codes - static const ReturnValue_t CHILD_TIMEOUT = MAKE_RETURN_CODE(0xD0); - static const ReturnValue_t SWITCH_FAILED = MAKE_RETURN_CODE(0xD1); + 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; From 242ca355f51008eb9ada619295cf397dbc49ae35 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 26 May 2020 00:01:07 +0200 Subject: [PATCH 54/94] removed swappers for arraylist for now --- container/ArrayList.h | 19 ------------------- container/FixedArrayList.h | 9 +++------ 2 files changed, 3 insertions(+), 25 deletions(-) diff --git a/container/ArrayList.h b/container/ArrayList.h index f978c984..a37a1c42 100644 --- a/container/ArrayList.h +++ b/container/ArrayList.h @@ -250,25 +250,6 @@ protected: * true if the array was allocated and needs to be deleted in the destructor. */ bool allocated; - - /** - * Swap the endianness of the Array list (not the length field !) - * Useful if the case the buffer type is larger than uint8_t - * @param list - */ - void swapArrayListEndianness() { - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - count_t i = 0; - // uint8_t buffer does not require swapping of entries. - if(sizeof(T) == 1) { - return; - } - while ((result == HasReturnvaluesIF::RETURN_OK) && (i < size)) { - T newEntry = EndianSwapper::swap(entries[i]); - entries[i] = newEntry; - ++i; - } - } }; #endif /* ARRAYLIST_H_ */ diff --git a/container/FixedArrayList.h b/container/FixedArrayList.h index 5d93db90..a2d2fa25 100644 --- a/container/FixedArrayList.h +++ b/container/FixedArrayList.h @@ -20,7 +20,8 @@ public: ArrayList(data, MAX_SIZE) { } - // (Robin): We could create a constructor to initialize the fixed array list with data and the known size field + // (Robin): We could create a constructor to initialize the fixed array list + // with data and the known size field // so it can be used for serialization too (with SerialFixedArrrayListAdapter) // is this feasible? /** @@ -30,14 +31,10 @@ public: * @param count * @param swapArrayListEndianess */ - FixedArrayList(T * data_, count_t count, - bool swapArrayListEndianess = false): + FixedArrayList(T * data_, count_t count): ArrayList(data, MAX_SIZE) { memcpy(this->data, data_, count * sizeof(T)); this->size = count; - if(swapArrayListEndianess) { - ArrayList::swapArrayListEndianness(); - } } FixedArrayList(const FixedArrayList& other) : From 9f2d5b64e009349a03be6990f43b8a3fddc5a02b Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 26 May 2020 01:03:26 +0200 Subject: [PATCH 55/94] comment improvements --- devicehandlers/DeviceHandlerBase.cpp | 2 +- devicehandlers/DeviceHandlerBase.h | 36 ++++++++++++++++++---------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/devicehandlers/DeviceHandlerBase.cpp b/devicehandlers/DeviceHandlerBase.cpp index 23ec1f18..6c769cdf 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/devicehandlers/DeviceHandlerBase.cpp @@ -417,7 +417,7 @@ void DeviceHandlerBase::setTransition(Mode_t modeTo, Submode_t submodeTo) { transitionSourceSubMode = submode; childTransitionFailure = CHILD_TIMEOUT; -//transitionTargetMode is set by setMode + // transitionTargetMode is set by setMode setMode((modeTo | TRANSITION_MODE_CHILD_ACTION_MASK), submodeTo); } diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index 74b84111..8932e109 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -740,28 +740,40 @@ protected: /** * Do the transition to the main modes (MODE_ON, MODE_NORMAL and MODE_RAW). * - * If the transition is complete, the mode should be set to the target mode, which can be deduced from the current mode which is + * If the transition is complete, the mode should be set to the target mode, + * which can be deduced from the current mode which is * [_MODE_TO_ON, _MODE_TO_NORMAL, _MODE_TO_RAW] * - * The intended target submode is already set. The origin submode can be read in subModeFrom. + * The intended target submode is already set. + * The origin submode can be read in subModeFrom. * - * If the transition can not be completed, the child class can try to reach an working mode by setting the mode either directly - * or setting the mode to an transitional mode (TO_ON, TO_NORMAL, TO_RAW) if the device needs to be reconfigured. + * If the transition can not be completed, the child class can try to reach + * an working mode by setting the mode either directly + * or setting the mode to an transitional mode (TO_ON, TO_NORMAL, TO_RAW) + * if the device needs to be reconfigured. * - * If nothing works, the child class can wait for the timeout and the base class will reset the mode to the mode where the transition + * If nothing works, the child class can wait for the timeout and the base + * class will reset the mode to the mode where the transition * originated from (the child should report the reason for the failed transition). * - * The intended way to send commands is to set a flag (enum) indicating which command is to be sent here - * and then to check in buildTransitionCommand() for the flag. This flag can also be used by doStartUp() and - * doShutDown() to get a nice and clean implementation of buildTransitionCommand() without switching through modes. + * The intended way to send commands is to set a flag (enum) indicating + * which command is to be sent here and then to check in + * buildTransitionCommand() for the flag. This flag can also be used by + * doStartUp() and doShutDown() to get a nice and clean implementation of + * buildTransitionCommand() without switching through modes. * - * When the the condition for the completion of the transition is met, the mode can be set, for example in the parseReply() function. + * When the the condition for the completion of the transition is met, the + * mode can be set, for example in the scanForReply() function. * - * The default implementation goes into the target mode; + * The default implementation goes into the target mode directly. * - * #transitionFailure can be set to a failure code indicating the reason for a failed transition + * #transitionFailure can be set to a failure code indicating the reason + * for a failed transition * - * @param modeFrom the mode the transition originated from: [MODE_ON, MODE_NORMAL, MODE_RAW and _MODE_POWER_DOWN (if the mode changed from _MODE_START_UP to _MODE_TO_ON)] + * @param modeFrom + * The mode the transition originated from: + * [MODE_ON, MODE_NORMAL, MODE_RAW and _MODE_POWER_DOWN (if the mode changed + * from _MODE_START_UP to _MODE_TO_ON)] * @param subModeFrom the subMode of modeFrom */ virtual void doTransition(Mode_t modeFrom, Submode_t subModeFrom); From a19fa231f51c6b83c0417afe08e208e2bc8c2563 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 26 May 2020 01:21:48 +0200 Subject: [PATCH 56/94] comment improvements --- devicehandlers/DeviceHandlerBase.h | 5 +++-- devicehandlers/DeviceHandlerIF.h | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index 8932e109..832d7e08 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -232,8 +232,9 @@ protected: * 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() + * @c _MODE_START_UP and @c _MODE_SHUT_DOWN. So it is used by doStartUp() + * and doShutDown() as well as doTransition(), by setting those + * modes in the respective functions. * * 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 diff --git a/devicehandlers/DeviceHandlerIF.h b/devicehandlers/DeviceHandlerIF.h index 666d9efc..cb190344 100644 --- a/devicehandlers/DeviceHandlerIF.h +++ b/devicehandlers/DeviceHandlerIF.h @@ -47,6 +47,8 @@ public: //! 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. + //! It is possible to set the mode to _MODE_SHUT_DOWN to use the to off + //! transition if available. 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. From 1a623a6a527599efc6ee8d4e28e85c405c58cb9a Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 26 May 2020 11:05:49 +0200 Subject: [PATCH 57/94] added override --- devicehandlers/DeviceHandlerBase.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index 832d7e08..244be322 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -494,7 +494,7 @@ public: ReturnValue_t setHealth(HealthState health); virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex); + const ParameterWrapper *newValues, uint16_t startAtIndex) override; /** * Implementation of ExecutableObjectIF function * From f7dd91891a644c660ff8ae7d6c183e84faf75d9a Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 26 May 2020 16:05:03 +0200 Subject: [PATCH 58/94] removed comments --- devicehandlers/DeviceHandlerBase.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index 244be322..1debcdcb 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -510,26 +510,16 @@ protected: */ static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE; - /* These returnvalues can be returned from abstract functions - * to alter the behaviour of DHB.For error values, refer to - * DeviceHandlerIF.h returnvalues. */ - // (Robin): maybe this would be better in DeviceHandlerIF? 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 - // (Robin): Maybe this would be better in DeviceHandlerIF? static const ReturnValue_t COMMAND_MAP_ERROR = MAKE_RETURN_CODE(0xC2); - // Returnvalues for getSwitches() static const ReturnValue_t NO_SWITCH = MAKE_RETURN_CODE(0xD0); - - // (Robin): Maybe this would be better in DeviceHandlerIF? // Mode handling error Codes static const ReturnValue_t CHILD_TIMEOUT = MAKE_RETURN_CODE(0xE0); static const ReturnValue_t SWITCH_FAILED = MAKE_RETURN_CODE(0xE1); From be4ac0bc8fa03faee1330a9899cb9051485eebba Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 27 May 2020 00:28:13 +0200 Subject: [PATCH 59/94] added semaph factory to linux --- osal/FreeRTOS/BinarySemaphore.cpp | 2 ++ osal/linux/SemaphoreFactory.cpp | 36 +++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 osal/linux/SemaphoreFactory.cpp diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index 026704d6..e6c308db 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -3,6 +3,8 @@ #include +const uint32_t SemaphoreIF::NO_TIMEOUT = 0; + BinarySemaphore::BinarySemaphore() { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { diff --git a/osal/linux/SemaphoreFactory.cpp b/osal/linux/SemaphoreFactory.cpp new file mode 100644 index 00000000..7b80176b --- /dev/null +++ b/osal/linux/SemaphoreFactory.cpp @@ -0,0 +1,36 @@ +#include +#include + +const uint32_t SemaphoreIF::NO_TIMEOUT = 0; + +SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; + +SemaphoreFactory::SemaphoreFactory() { +} + +SemaphoreFactory::~SemaphoreFactory() { + delete factoryInstance; +} + +SemaphoreFactory* SemaphoreFactory::instance() { + if (factoryInstance == nullptr){ + factoryInstance = new SemaphoreFactory(); + } + return SemaphoreFactory::factoryInstance; +} + +SemaphoreIF* SemaphoreFactory::createBinarySemaphore() { + sif::error << "Semaphore not implemented for Linux yet" << std::endl; + return nullptr; +} + +SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t count, + uint8_t initCount) { + sif::error << "Counting Semaphore not implemented for " + "Linux yet" << std::endl; + return nullptr; +} + +void SemaphoreFactory::deleteMutex(SemaphoreIF* semaphore) { + delete semaphore; +} From f6ae0348cb50dddefa867dc3a0344dac99efef2e Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 27 May 2020 11:41:36 +0200 Subject: [PATCH 60/94] some linux mutex tweaks --- osal/linux/Mutex.cpp | 4 +++- osal/linux/Mutex.h | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/osal/linux/Mutex.cpp b/osal/linux/Mutex.cpp index 36bb3ce4..b4773267 100644 --- a/osal/linux/Mutex.cpp +++ b/osal/linux/Mutex.cpp @@ -25,7 +25,9 @@ Mutex::Mutex() { sif::error << "Mutex: creation with name, id " << mutex.__data.__count << ", " << " failed with " << strerror(status) << std::endl; } - //After a mutex attributes object has been used to initialize one or more mutexes, any function affecting the attributes object (including destruction) shall not affect any previously initialized mutexes. + // After a mutex attributes object has been used to initialize one or more + // mutexes, any function affecting the attributes object + // (including destruction) shall not affect any previously initialized mutexes. status = pthread_mutexattr_destroy(&mutexAttr); if (status != 0) { sif::error << "Mutex: Attribute destroy failed with " << strerror(status) << std::endl; diff --git a/osal/linux/Mutex.h b/osal/linux/Mutex.h index d02d008f..872ac3ac 100644 --- a/osal/linux/Mutex.h +++ b/osal/linux/Mutex.h @@ -2,7 +2,11 @@ #define OS_RTEMS_MUTEX_H_ #include + +extern "C" { #include +} + class Mutex : public MutexIF { public: From badcacad49e3790df3cda101dc9da973287238de Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 27 May 2020 11:48:11 +0200 Subject: [PATCH 61/94] added new timeout values --- osal/FreeRTOS/BinarySemaphore.cpp | 2 -- osal/FreeRTOS/SemaphoreFactory.cpp | 2 ++ osal/linux/SemaphoreFactory.cpp | 1 + tasks/SemaphoreIF.h | 4 +++- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index e6c308db..026704d6 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -3,8 +3,6 @@ #include -const uint32_t SemaphoreIF::NO_TIMEOUT = 0; - BinarySemaphore::BinarySemaphore() { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { diff --git a/osal/FreeRTOS/SemaphoreFactory.cpp b/osal/FreeRTOS/SemaphoreFactory.cpp index 9a355891..7bd71dd7 100644 --- a/osal/FreeRTOS/SemaphoreFactory.cpp +++ b/osal/FreeRTOS/SemaphoreFactory.cpp @@ -4,6 +4,8 @@ #include SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; +const uint32_t SemaphoreIF::NO_TIMEOUT = 0; +const uint32_t SemaphoreIF::MAX_TIMEOUT = portMAX_DELAY; SemaphoreFactory::SemaphoreFactory() { } diff --git a/osal/linux/SemaphoreFactory.cpp b/osal/linux/SemaphoreFactory.cpp index 7b80176b..b1100e75 100644 --- a/osal/linux/SemaphoreFactory.cpp +++ b/osal/linux/SemaphoreFactory.cpp @@ -2,6 +2,7 @@ #include const uint32_t SemaphoreIF::NO_TIMEOUT = 0; +const uint32_t SemaphoreIF::MAX_TIMEOUT = 0xFFFFFFFF; SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; diff --git a/tasks/SemaphoreIF.h b/tasks/SemaphoreIF.h index 7dde27f4..b2b113f1 100644 --- a/tasks/SemaphoreIF.h +++ b/tasks/SemaphoreIF.h @@ -20,8 +20,10 @@ class SemaphoreIF { public: virtual~ SemaphoreIF() {}; - //!< Needs to be defined in implementation. + //! Needs to be defined in implementation. No blocking time static const uint32_t NO_TIMEOUT; + //! Needs to be defined in implementation. Blocks indefinitely. + static const uint32_t MAX_TIMEOUT; static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; //! Semaphore timeout static constexpr ReturnValue_t SEMAPHORE_TIMEOUT = MAKE_RETURN_CODE(1); From 968d7fad815877213c154845bc058140e47ee91b Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 27 May 2020 17:07:35 +0200 Subject: [PATCH 62/94] replaced some timeout values --- osal/FreeRTOS/BinarySemaphore.cpp | 9 ++++----- osal/FreeRTOS/BinarySemaphore.h | 20 ++++++-------------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index 026704d6..98911ad1 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -1,6 +1,5 @@ #include #include - #include BinarySemaphore::BinarySemaphore() { @@ -39,11 +38,11 @@ ReturnValue_t BinarySemaphore::takeBinarySemaphore(uint32_t timeoutMs) { if(handle == nullptr) { return SEMAPHORE_NULLPOINTER; } - TickType_t timeout = BinarySemaphore::NO_BLOCK_TICKS; - if(timeoutMs == BinarySemaphore::BLOCK_TIMEOUT) { - timeout = BinarySemaphore::BLOCK_TIMEOUT_TICKS; + TickType_t timeout = SemaphoreIF::NO_TIMEOUT; + if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { + timeout = SemaphoreIF::MAX_TIMEOUT; } - else if(timeoutMs > BinarySemaphore::NO_BLOCK_TIMEOUT){ + else if(timeoutMs > BinarySemaphore::NO_TIMEOUT){ timeout = pdMS_TO_TICKS(timeoutMs); } diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 5f69dc90..7079e91f 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -3,13 +3,14 @@ #include #include + extern "C" { #include #include } -// TODO: Counting semaphores and implement the new (better) -// task notifications. However, those use task notifications require +// TODO: Implement the new (better) task notifications. +// However, those task notifications require // the task handle. Maybe it would be better to make a separate class // and switch between the classes with #ifdefs. // Task Notifications require FreeRTOS V8.2 something.. @@ -27,15 +28,6 @@ class BinarySemaphore: public SemaphoreIF, public HasReturnvaluesIF { public: static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; - - //! No block time, poll the semaphore. Can also be used as tick type. - //! Can be passed as tick type and ms value. - static constexpr uint32_t NO_BLOCK_TIMEOUT = 0; - static constexpr TickType_t NO_BLOCK_TICKS = 0; - //! No block time, poll the semaphore. - //! Can be passed as tick type and ms value. - static constexpr TickType_t BLOCK_TIMEOUT_TICKS = portMAX_DELAY; - static constexpr uint32_t BLOCK_TIMEOUT = portMAX_DELAY; //! @brief Default ctor BinarySemaphore(); @@ -51,7 +43,7 @@ public: virtual ~BinarySemaphore(); ReturnValue_t acquire(uint32_t timeoutMs = - BinarySemaphore::NO_BLOCK_TIMEOUT) override; + SemaphoreIF::NO_TIMEOUT) override; ReturnValue_t release() override; uint8_t getSemaphoreCounter() override; @@ -65,7 +57,7 @@ public: * -@c RETURN_FAILED on failure */ ReturnValue_t takeBinarySemaphore(uint32_t timeoutMs = - BinarySemaphore::NO_BLOCK_TIMEOUT); + SemaphoreIF::NO_TIMEOUT); /** * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. @@ -74,7 +66,7 @@ public: * - @c RETURN_FAILED on failure */ ReturnValue_t takeBinarySemaphoreTickTimeout(TickType_t timeoutTicks = - BinarySemaphore::NO_BLOCK_TICKS); + BinarySemaphore::NO_TIMEOUT); /** * Give back the binary semaphore From 2d33274c2306fd51b4ea512d5d399502755f20fa Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 27 May 2020 17:42:18 +0200 Subject: [PATCH 63/94] implementing new task notifications --- osal/FreeRTOS/BinarySemaphore.cpp | 69 +++++++++++++++++++--- osal/FreeRTOS/BinarySemaphore.h | 95 +++++++++++++++++++++++++++---- 2 files changed, 145 insertions(+), 19 deletions(-) diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index 98911ad1..f7e87983 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -2,6 +2,8 @@ #include #include +#if ( configUSE_OLD_SEMAPHORES == 1 ) + BinarySemaphore::BinarySemaphore() { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { @@ -51,7 +53,7 @@ ReturnValue_t BinarySemaphore::takeBinarySemaphore(uint32_t timeoutMs) { return HasReturnvaluesIF::RETURN_OK; } else { - return SEMAPHORE_TIMEOUT; + return SemaphoreIF::SEMAPHORE_TIMEOUT; } } @@ -96,14 +98,6 @@ ReturnValue_t BinarySemaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) return HasReturnvaluesIF::RETURN_FAILED; } } - -void BinarySemaphore::resetSemaphore() { - if(handle != nullptr) { - vSemaphoreDelete(handle); - handle = xSemaphoreCreateBinary(); - xSemaphoreGive(handle); - } -} ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { return takeBinarySemaphore(timeoutMs); @@ -135,3 +129,60 @@ ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t sema return SEMAPHORE_NOT_OWNED; } } + + +#else + +BinarySemaphore::BinarySemaphore() { + handle = TaskManagement::getCurrentTaskHandle(); +} + +ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { + return takeBinarySemaphore(timeoutMs); +} + +ReturnValue_t BinarySemaphore::release() { + return giveBinarySemaphore(); +} + +ReturnValue_t BinarySemaphore::takeBinarySemaphore(uint32_t timeoutMs) { + TickType_t timeout = SemaphoreIF::NO_TIMEOUT; + if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { + timeout = SemaphoreIF::MAX_TIMEOUT; + } + else if(timeoutMs > BinarySemaphore::NO_TIMEOUT){ + timeout = pdMS_TO_TICKS(timeoutMs); + } + + BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeout); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SemaphoreIF::SEMAPHORE_TIMEOUT; + } +} + +ReturnValue_t BinarySemaphore::takeBinarySemaphoreTickTimeout( + TickType_t timeoutTicks) { + BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeoutTicks); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } else { + return SEMAPHORE_TIMEOUT; + } +} + +ReturnValue_t BinarySemaphore::giveBinarySemaphore() { + if (handle == nullptr) { + return SEMAPHORE_NULLPOINTER; + } + BaseType_t returncode = xTaskNotifyGive(handle); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } else { + return SEMAPHORE_NOT_OWNED; + } +} + +#endif diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 7079e91f..4d95fc27 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -6,7 +6,11 @@ extern "C" { #include +#if ( configUSE_OLD_SEMAPHORES == 1 ) #include +#else +#include +#endif } // TODO: Implement the new (better) task notifications. @@ -24,11 +28,13 @@ extern "C" { * @author R. Mueller * @ingroup osal */ +#if ( configUSE_OLD_SEMAPHORES == 1 ) + class BinarySemaphore: public SemaphoreIF, - public HasReturnvaluesIF { + public HasReturnvaluesIF { public: static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; - + //! @brief Default ctor BinarySemaphore(); //! @brief Copy ctor, deleted explicitely. @@ -46,7 +52,7 @@ public: SemaphoreIF::NO_TIMEOUT) override; ReturnValue_t release() override; uint8_t getSemaphoreCounter() override; - + /** * Take the binary semaphore. * If the semaphore has already been taken, the task will be blocked @@ -81,11 +87,6 @@ public: */ SemaphoreHandle_t getSemaphore(); - /** - * Reset the semaphore. - */ - void resetSemaphore(); - /** * Wrapper function to give back semaphore from handle * @param semaphore @@ -104,9 +105,83 @@ public: */ static ReturnValue_t giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken); - -protected: + +protected: SemaphoreHandle_t handle; }; + +#else + +class BinarySemaphore: public SemaphoreIF, + public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; + + //! @brief Default ctor + BinarySemaphore(); + + ReturnValue_t acquire(uint32_t timeoutMs = + SemaphoreIF::NO_TIMEOUT) override; + ReturnValue_t release() override; + uint8_t getSemaphoreCounter() override; + + /** + * Take the binary semaphore. + * If the semaphore has already been taken, the task will be blocked + * for a maximum of #timeoutMs or until the semaphore is given back, + * for example by an ISR or another task. + * @param timeoutMs + * @return -@c RETURN_OK on success + * -@c RETURN_FAILED on failure + */ + ReturnValue_t takeBinarySemaphore(uint32_t timeoutMs = + SemaphoreIF::NO_TIMEOUT); + + /** + * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. + * @param timeoutTicks + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + ReturnValue_t takeBinarySemaphoreTickTimeout(TickType_t timeoutTicks = + BinarySemaphore::NO_TIMEOUT); + + /** + * Give back the binary semaphore + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + ReturnValue_t giveBinarySemaphore(); + + /** + * Get Handle to the semaphore. + * @return + */ + TaskHandle_t getTaskHandle(); + + /** + * Wrapper function to give back semaphore from handle + * @param semaphore + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + static ReturnValue_t giveBinarySemaphore(TaskHandle_t taskToNotify); + + /** + * Wrapper function to give back semaphore from handle when called from an ISR + * @param semaphore + * @param higherPriorityTaskWoken This will be set to pdPASS if a task with a higher priority + * was unblocked + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + static ReturnValue_t giveBinarySemaphoreFromISR(TaskHandle_t taskToNotify, + BaseType_t * higherPriorityTaskWoken); + +protected: + TaskHandle_t handle; +}; +#endif + #endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ From 8a1e0dab0370c5b454fcb9e95de0f1349000b380 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 27 May 2020 19:03:46 +0200 Subject: [PATCH 64/94] continued with task notifications --- osal/FreeRTOS/BinarySemaphore.cpp | 48 ++++++++++++++++++++++++++--- osal/FreeRTOS/BinarySemaphore.h | 8 +++-- osal/FreeRTOS/CountingSemaphore.cpp | 4 +++ 3 files changed, 53 insertions(+), 7 deletions(-) diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index f7e87983..150f8c99 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -2,7 +2,7 @@ #include #include -#if ( configUSE_OLD_SEMAPHORES == 1 ) +#if ( configUSE_TASK_NOTIFICATIONS == 0 ) BinarySemaphore::BinarySemaphore() { handle = xSemaphoreCreateBinary(); @@ -174,9 +174,6 @@ ReturnValue_t BinarySemaphore::takeBinarySemaphoreTickTimeout( } ReturnValue_t BinarySemaphore::giveBinarySemaphore() { - if (handle == nullptr) { - return SEMAPHORE_NULLPOINTER; - } BaseType_t returncode = xTaskNotifyGive(handle); if (returncode == pdPASS) { return HasReturnvaluesIF::RETURN_OK; @@ -185,4 +182,47 @@ ReturnValue_t BinarySemaphore::giveBinarySemaphore() { } } +TaskHandle_t BinarySemaphore::getTaskHandle() { + return handle; +} + +uint8_t BinarySemaphore::getSemaphoreCounter() { + uint32_t notificationValue; + xTaskNotifyAndQuery(handle, 0, eNoAction, ¬ificationValue); + return notificationValue; +} + +uint8_t BinarySemaphore::getSemaphoreCounterFromISR(TaskHandle_t taskHandle) { + uint32_t notificationValue; + BaseType_t higherPriorityTaskWoken; + xTaskNotifyAndQueryFromISR(taskHandle, 0, eNoAction, ¬ificationValue, + &higherPriorityTaskWoken); + if(higherPriorityTaskWoken) { + TaskManagement::requestContextSwitch(CallContext::isr); + } + return notificationValue; +} + + +ReturnValue_t BinarySemaphore::giveBinarySemaphore(TaskHandle_t taskHandle) { + BaseType_t returncode = xTaskNotifyGive(taskHandle); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } else { + return SEMAPHORE_NOT_OWNED; + } +} + +// Be careful with the stack size here. This is called from an ISR! +ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR( + TaskHandle_t taskHandle, BaseType_t * higherPriorityTaskWoken) { + vTaskNotifyGiveFromISR(taskHandle, higherPriorityTaskWoken); + if(*higherPriorityTaskWoken == pdPASS) { + // Request context switch because unblocking the semaphore + // caused a high priority task unblock. + TaskManagement::requestContextSwitch(CallContext::isr); + } + return HasReturnvaluesIF::RETURN_OK; +} + #endif diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 4d95fc27..2ee10226 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -6,7 +6,7 @@ extern "C" { #include -#if ( configUSE_OLD_SEMAPHORES == 1 ) +#if ( configUSE_TASK_NOTIFICATIONS == 0 ) #include #else #include @@ -28,7 +28,7 @@ extern "C" { * @author R. Mueller * @ingroup osal */ -#if ( configUSE_OLD_SEMAPHORES == 1 ) +#if ( configUSE_TASK_NOTIFICATIONS == 0 ) class BinarySemaphore: public SemaphoreIF, public HasReturnvaluesIF { @@ -155,7 +155,7 @@ public: ReturnValue_t giveBinarySemaphore(); /** - * Get Handle to the semaphore. + * Get handle to the task related to the semaphore. * @return */ TaskHandle_t getTaskHandle(); @@ -179,6 +179,8 @@ public: static ReturnValue_t giveBinarySemaphoreFromISR(TaskHandle_t taskToNotify, BaseType_t * higherPriorityTaskWoken); + static uint8_t getSemaphoreCounterFromISR(TaskHandle_t taskHandle); + protected: TaskHandle_t handle; }; diff --git a/osal/FreeRTOS/CountingSemaphore.cpp b/osal/FreeRTOS/CountingSemaphore.cpp index 2b81848a..e04d3def 100644 --- a/osal/FreeRTOS/CountingSemaphore.cpp +++ b/osal/FreeRTOS/CountingSemaphore.cpp @@ -1,6 +1,10 @@ #include #include +extern "C" { +#include +} + // Make sure #define configUSE_COUNTING_SEMAPHORES 1 is set in // free FreeRTOSConfig.h file. CountingSemaphore::CountingSemaphore(uint8_t count, uint8_t initCount): From b4065c776437b39613542d9beff87ba06e6242ad Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 27 May 2020 19:46:56 +0200 Subject: [PATCH 65/94] seperation of semaph implementations finished --- osal/FreeRTOS/BinSemaphUsingTask.cpp | 95 ++++++++++++++++++++++ osal/FreeRTOS/BinSemaphUsingTask.h | 86 ++++++++++++++++++++ osal/FreeRTOS/BinarySemaphore.cpp | 99 ----------------------- osal/FreeRTOS/BinarySemaphore.h | 93 ++------------------- osal/FreeRTOS/CountingSemaphUsingTask.cpp | 8 ++ osal/FreeRTOS/CountingSemaphUsingTask.h | 25 ++++++ osal/FreeRTOS/CountingSemaphore.cpp | 2 + osal/FreeRTOS/SemaphoreFactory.cpp | 6 +- tasks/SemaphoreFactory.h | 10 ++- 9 files changed, 232 insertions(+), 192 deletions(-) create mode 100644 osal/FreeRTOS/BinSemaphUsingTask.cpp create mode 100644 osal/FreeRTOS/BinSemaphUsingTask.h create mode 100644 osal/FreeRTOS/CountingSemaphUsingTask.cpp create mode 100644 osal/FreeRTOS/CountingSemaphUsingTask.h diff --git a/osal/FreeRTOS/BinSemaphUsingTask.cpp b/osal/FreeRTOS/BinSemaphUsingTask.cpp new file mode 100644 index 00000000..0d732054 --- /dev/null +++ b/osal/FreeRTOS/BinSemaphUsingTask.cpp @@ -0,0 +1,95 @@ +#include +#include + + +BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() { + handle = TaskManagement::getCurrentTaskHandle(); +} + +ReturnValue_t BinarySemaphoreUsingTask::acquire(uint32_t timeoutMs) { + return takeBinarySemaphore(timeoutMs); +} + +ReturnValue_t BinarySemaphoreUsingTask::release() { + return giveBinarySemaphore(); +} + +ReturnValue_t BinarySemaphoreUsingTask::takeBinarySemaphore(uint32_t timeoutMs) { + TickType_t timeout = SemaphoreIF::NO_TIMEOUT; + if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { + timeout = SemaphoreIF::MAX_TIMEOUT; + } + else if(timeoutMs > BinarySemaphoreUsingTask::NO_TIMEOUT){ + timeout = pdMS_TO_TICKS(timeoutMs); + } + + BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeout); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SemaphoreIF::SEMAPHORE_TIMEOUT; + } +} + +ReturnValue_t BinarySemaphoreUsingTask::takeBinarySemaphoreTickTimeout( + TickType_t timeoutTicks) { + BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeoutTicks); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } else { + return SEMAPHORE_TIMEOUT; + } +} + +ReturnValue_t BinarySemaphoreUsingTask::giveBinarySemaphore() { + BaseType_t returncode = xTaskNotifyGive(handle); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } else { + return SEMAPHORE_NOT_OWNED; + } +} + +TaskHandle_t BinarySemaphoreUsingTask::getTaskHandle() { + return handle; +} + +uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter() { + uint32_t notificationValue; + xTaskNotifyAndQuery(handle, 0, eNoAction, ¬ificationValue); + return notificationValue; +} + +uint8_t BinarySemaphoreUsingTask::getSemaphoreCounterFromISR(TaskHandle_t taskHandle) { + uint32_t notificationValue; + BaseType_t higherPriorityTaskWoken; + xTaskNotifyAndQueryFromISR(taskHandle, 0, eNoAction, ¬ificationValue, + &higherPriorityTaskWoken); + if(higherPriorityTaskWoken) { + TaskManagement::requestContextSwitch(CallContext::isr); + } + return notificationValue; +} + + +ReturnValue_t BinarySemaphoreUsingTask::giveBinarySemaphore(TaskHandle_t taskHandle) { + BaseType_t returncode = xTaskNotifyGive(taskHandle); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } else { + return SEMAPHORE_NOT_OWNED; + } +} + +// Be careful with the stack size here. This is called from an ISR! +ReturnValue_t BinarySemaphoreUsingTask::giveBinarySemaphoreFromISR( + TaskHandle_t taskHandle, BaseType_t * higherPriorityTaskWoken) { + vTaskNotifyGiveFromISR(taskHandle, higherPriorityTaskWoken); + if(*higherPriorityTaskWoken == pdPASS) { + // Request context switch because unblocking the semaphore + // caused a high priority task unblock. + TaskManagement::requestContextSwitch(CallContext::isr); + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/osal/FreeRTOS/BinSemaphUsingTask.h b/osal/FreeRTOS/BinSemaphUsingTask.h new file mode 100644 index 00000000..2736b1db --- /dev/null +++ b/osal/FreeRTOS/BinSemaphUsingTask.h @@ -0,0 +1,86 @@ +#ifndef FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ +#define FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ + +#include +#include + +extern "C" { +#include +#include +} + +class BinarySemaphoreUsingTask: public SemaphoreIF, + public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; + + //! @brief Default ctor + BinarySemaphoreUsingTask(); + + ReturnValue_t acquire(uint32_t timeoutMs = + SemaphoreIF::NO_TIMEOUT) override; + ReturnValue_t release() override; + uint8_t getSemaphoreCounter() override; + + /** + * Take the binary semaphore. + * If the semaphore has already been taken, the task will be blocked + * for a maximum of #timeoutMs or until the semaphore is given back, + * for example by an ISR or another task. + * @param timeoutMs + * @return -@c RETURN_OK on success + * -@c RETURN_FAILED on failure + */ + ReturnValue_t takeBinarySemaphore(uint32_t timeoutMs = + SemaphoreIF::NO_TIMEOUT); + + /** + * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. + * @param timeoutTicks + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + ReturnValue_t takeBinarySemaphoreTickTimeout(TickType_t timeoutTicks = + SemaphoreIF::NO_TIMEOUT); + + /** + * Give back the binary semaphore + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + ReturnValue_t giveBinarySemaphore(); + + /** + * Get handle to the task related to the semaphore. + * @return + */ + TaskHandle_t getTaskHandle(); + + /** + * Wrapper function to give back semaphore from handle + * @param semaphore + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + static ReturnValue_t giveBinarySemaphore(TaskHandle_t taskToNotify); + + /** + * Wrapper function to give back semaphore from handle when called from an ISR + * @param semaphore + * @param higherPriorityTaskWoken This will be set to pdPASS if a task with a higher priority + * was unblocked + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + static ReturnValue_t giveBinarySemaphoreFromISR(TaskHandle_t taskToNotify, + BaseType_t * higherPriorityTaskWoken); + + static uint8_t getSemaphoreCounterFromISR(TaskHandle_t taskHandle); + +protected: + TaskHandle_t handle; +}; + + + +#endif /* FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ */ diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index 150f8c99..d56be763 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -2,8 +2,6 @@ #include #include -#if ( configUSE_TASK_NOTIFICATIONS == 0 ) - BinarySemaphore::BinarySemaphore() { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { @@ -129,100 +127,3 @@ ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t sema return SEMAPHORE_NOT_OWNED; } } - - -#else - -BinarySemaphore::BinarySemaphore() { - handle = TaskManagement::getCurrentTaskHandle(); -} - -ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { - return takeBinarySemaphore(timeoutMs); -} - -ReturnValue_t BinarySemaphore::release() { - return giveBinarySemaphore(); -} - -ReturnValue_t BinarySemaphore::takeBinarySemaphore(uint32_t timeoutMs) { - TickType_t timeout = SemaphoreIF::NO_TIMEOUT; - if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { - timeout = SemaphoreIF::MAX_TIMEOUT; - } - else if(timeoutMs > BinarySemaphore::NO_TIMEOUT){ - timeout = pdMS_TO_TICKS(timeoutMs); - } - - BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeout); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - return SemaphoreIF::SEMAPHORE_TIMEOUT; - } -} - -ReturnValue_t BinarySemaphore::takeBinarySemaphoreTickTimeout( - TickType_t timeoutTicks) { - BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeoutTicks); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } else { - return SEMAPHORE_TIMEOUT; - } -} - -ReturnValue_t BinarySemaphore::giveBinarySemaphore() { - BaseType_t returncode = xTaskNotifyGive(handle); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } else { - return SEMAPHORE_NOT_OWNED; - } -} - -TaskHandle_t BinarySemaphore::getTaskHandle() { - return handle; -} - -uint8_t BinarySemaphore::getSemaphoreCounter() { - uint32_t notificationValue; - xTaskNotifyAndQuery(handle, 0, eNoAction, ¬ificationValue); - return notificationValue; -} - -uint8_t BinarySemaphore::getSemaphoreCounterFromISR(TaskHandle_t taskHandle) { - uint32_t notificationValue; - BaseType_t higherPriorityTaskWoken; - xTaskNotifyAndQueryFromISR(taskHandle, 0, eNoAction, ¬ificationValue, - &higherPriorityTaskWoken); - if(higherPriorityTaskWoken) { - TaskManagement::requestContextSwitch(CallContext::isr); - } - return notificationValue; -} - - -ReturnValue_t BinarySemaphore::giveBinarySemaphore(TaskHandle_t taskHandle) { - BaseType_t returncode = xTaskNotifyGive(taskHandle); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } else { - return SEMAPHORE_NOT_OWNED; - } -} - -// Be careful with the stack size here. This is called from an ISR! -ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR( - TaskHandle_t taskHandle, BaseType_t * higherPriorityTaskWoken) { - vTaskNotifyGiveFromISR(taskHandle, higherPriorityTaskWoken); - if(*higherPriorityTaskWoken == pdPASS) { - // Request context switch because unblocking the semaphore - // caused a high priority task unblock. - TaskManagement::requestContextSwitch(CallContext::isr); - } - return HasReturnvaluesIF::RETURN_OK; -} - -#endif diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 2ee10226..e5c0ce4b 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -6,18 +6,9 @@ extern "C" { #include -#if ( configUSE_TASK_NOTIFICATIONS == 0 ) #include -#else -#include -#endif } -// TODO: Implement the new (better) task notifications. -// However, those task notifications require -// the task handle. Maybe it would be better to make a separate class -// and switch between the classes with #ifdefs. -// Task Notifications require FreeRTOS V8.2 something.. /** * @brief OS Tool to achieve synchronization of between tasks or between * task and ISR. The default semaphore implementation creates a @@ -25,11 +16,15 @@ extern "C" { * @details * Documentation: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html * + * Please note that if the semaphore implementation is only related to + * the synchronization of one task, the new task notifications can be used, + * also see the BinSemaphUsingTask and CountingSemaphUsingTask classes. + * These use the task notification value instead of a queue and are + * faster and more efficient. + * * @author R. Mueller * @ingroup osal */ -#if ( configUSE_TASK_NOTIFICATIONS == 0 ) - class BinarySemaphore: public SemaphoreIF, public HasReturnvaluesIF { public: @@ -110,80 +105,4 @@ protected: SemaphoreHandle_t handle; }; - -#else - -class BinarySemaphore: public SemaphoreIF, - public HasReturnvaluesIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; - - //! @brief Default ctor - BinarySemaphore(); - - ReturnValue_t acquire(uint32_t timeoutMs = - SemaphoreIF::NO_TIMEOUT) override; - ReturnValue_t release() override; - uint8_t getSemaphoreCounter() override; - - /** - * Take the binary semaphore. - * If the semaphore has already been taken, the task will be blocked - * for a maximum of #timeoutMs or until the semaphore is given back, - * for example by an ISR or another task. - * @param timeoutMs - * @return -@c RETURN_OK on success - * -@c RETURN_FAILED on failure - */ - ReturnValue_t takeBinarySemaphore(uint32_t timeoutMs = - SemaphoreIF::NO_TIMEOUT); - - /** - * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. - * @param timeoutTicks - * @return - @c RETURN_OK on success - * - @c RETURN_FAILED on failure - */ - ReturnValue_t takeBinarySemaphoreTickTimeout(TickType_t timeoutTicks = - BinarySemaphore::NO_TIMEOUT); - - /** - * Give back the binary semaphore - * @return - @c RETURN_OK on success - * - @c RETURN_FAILED on failure - */ - ReturnValue_t giveBinarySemaphore(); - - /** - * Get handle to the task related to the semaphore. - * @return - */ - TaskHandle_t getTaskHandle(); - - /** - * Wrapper function to give back semaphore from handle - * @param semaphore - * @return - @c RETURN_OK on success - * - @c RETURN_FAILED on failure - */ - static ReturnValue_t giveBinarySemaphore(TaskHandle_t taskToNotify); - - /** - * Wrapper function to give back semaphore from handle when called from an ISR - * @param semaphore - * @param higherPriorityTaskWoken This will be set to pdPASS if a task with a higher priority - * was unblocked - * @return - @c RETURN_OK on success - * - @c RETURN_FAILED on failure - */ - static ReturnValue_t giveBinarySemaphoreFromISR(TaskHandle_t taskToNotify, - BaseType_t * higherPriorityTaskWoken); - - static uint8_t getSemaphoreCounterFromISR(TaskHandle_t taskHandle); - -protected: - TaskHandle_t handle; -}; -#endif - #endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.cpp b/osal/FreeRTOS/CountingSemaphUsingTask.cpp new file mode 100644 index 00000000..6c5d45c7 --- /dev/null +++ b/osal/FreeRTOS/CountingSemaphUsingTask.cpp @@ -0,0 +1,8 @@ +#include +#include + +CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(uint8_t count, + uint8_t initCount): + count(count), initCount(initCount) { + handle = TaskManagement::getCurrentTaskHandle(); +} diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.h b/osal/FreeRTOS/CountingSemaphUsingTask.h new file mode 100644 index 00000000..c4bfb61a --- /dev/null +++ b/osal/FreeRTOS/CountingSemaphUsingTask.h @@ -0,0 +1,25 @@ +#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ +#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ + +#include +#include + +extern "C" { +#include +#include +} + +class CountingSemaphoreUsingTask: public SemaphoreIF { +public: + CountingSemaphoreUsingTask(uint8_t count, uint8_t initCount); + + ReturnValue_t acquire(uint32_t timeoutMs); + ReturnValue_t release(); + +private: + TaskHandle_t handle; + uint8_t count = 0; + uint8_t initCount = 0; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ */ diff --git a/osal/FreeRTOS/CountingSemaphore.cpp b/osal/FreeRTOS/CountingSemaphore.cpp index e04d3def..2f0dfd76 100644 --- a/osal/FreeRTOS/CountingSemaphore.cpp +++ b/osal/FreeRTOS/CountingSemaphore.cpp @@ -1,5 +1,6 @@ #include #include +#include extern "C" { #include @@ -30,3 +31,4 @@ CountingSemaphore& CountingSemaphore::operator =( } return * this; } + diff --git a/osal/FreeRTOS/SemaphoreFactory.cpp b/osal/FreeRTOS/SemaphoreFactory.cpp index 7bd71dd7..1eee1bac 100644 --- a/osal/FreeRTOS/SemaphoreFactory.cpp +++ b/osal/FreeRTOS/SemaphoreFactory.cpp @@ -21,15 +21,15 @@ SemaphoreFactory* SemaphoreFactory::instance() { return SemaphoreFactory::factoryInstance; } -SemaphoreIF* SemaphoreFactory::createBinarySemaphore() { +SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) { return new BinarySemaphore(); } SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t count, - uint8_t initCount) { + uint8_t initCount, uint32_t argument) { return new CountingSemaphore(count, initCount); } -void SemaphoreFactory::deleteMutex(SemaphoreIF* semaphore) { +void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { delete semaphore; } diff --git a/tasks/SemaphoreFactory.h b/tasks/SemaphoreFactory.h index fa95399a..971e97fa 100644 --- a/tasks/SemaphoreFactory.h +++ b/tasks/SemaphoreFactory.h @@ -20,19 +20,23 @@ public: /** * Create a binary semaphore. * Creator function for a binary semaphore which may only be acquired once + * @param argument Can be used to pass implementation specific information. * @return Pointer to newly created semaphore class instance. */ - SemaphoreIF* createBinarySemaphore(); + SemaphoreIF* createBinarySemaphore(uint32_t argument = 0); /** * Create a counting semaphore. * Creator functons for a counting semaphore which may be acquired multiple * times. * @param count Semaphore can be taken count times. * @param initCount Initial count value. + * @param argument Can be used to pass implementation specific information. * @return */ - SemaphoreIF* createCountingSemaphore(uint8_t count, uint8_t initCount); - void deleteMutex(SemaphoreIF* mutex); + SemaphoreIF* createCountingSemaphore(uint8_t count, uint8_t initCount, + uint32_t argument = 0); + + void deleteSemaphore(SemaphoreIF* mutex); private: /** From eabee85ba9f1dd014abc66d13e212427dc328242 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 27 May 2020 19:56:02 +0200 Subject: [PATCH 66/94] tweaked factory to have configurability --- osal/FreeRTOS/CountingSemaphUsingTask.cpp | 13 ++++++++++ osal/FreeRTOS/CountingSemaphUsingTask.h | 5 ++-- osal/FreeRTOS/SemaphoreFactory.cpp | 30 +++++++++++++++++++++-- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.cpp b/osal/FreeRTOS/CountingSemaphUsingTask.cpp index 6c5d45c7..10365d7e 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.cpp +++ b/osal/FreeRTOS/CountingSemaphUsingTask.cpp @@ -6,3 +6,16 @@ CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(uint8_t count, count(count), initCount(initCount) { handle = TaskManagement::getCurrentTaskHandle(); } + +ReturnValue_t CountingSemaphoreUsingTask::acquire( + uint32_t timeoutMs) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t CountingSemaphoreUsingTask::release() { + return HasReturnvaluesIF::RETURN_OK; +} + +uint8_t CountingSemaphoreUsingTask::getSemaphoreCounter() { + return 0; +} diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.h b/osal/FreeRTOS/CountingSemaphUsingTask.h index c4bfb61a..7fc98e93 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.h +++ b/osal/FreeRTOS/CountingSemaphUsingTask.h @@ -13,8 +13,9 @@ class CountingSemaphoreUsingTask: public SemaphoreIF { public: CountingSemaphoreUsingTask(uint8_t count, uint8_t initCount); - ReturnValue_t acquire(uint32_t timeoutMs); - ReturnValue_t release(); + ReturnValue_t acquire(uint32_t timeoutMs) override; + ReturnValue_t release() override; + uint8_t getSemaphoreCounter() override; private: TaskHandle_t handle; diff --git a/osal/FreeRTOS/SemaphoreFactory.cpp b/osal/FreeRTOS/SemaphoreFactory.cpp index 1eee1bac..6acdc7b7 100644 --- a/osal/FreeRTOS/SemaphoreFactory.cpp +++ b/osal/FreeRTOS/SemaphoreFactory.cpp @@ -1,5 +1,7 @@ #include +#include #include +#include #include #include @@ -7,6 +9,9 @@ SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; const uint32_t SemaphoreIF::NO_TIMEOUT = 0; const uint32_t SemaphoreIF::MAX_TIMEOUT = portMAX_DELAY; +static const uint32_t USE_REGULAR_SEMAPHORES = 0; +static const uint32_t USE_TASK_NOTIFICATIONS = 1; + SemaphoreFactory::SemaphoreFactory() { } @@ -22,12 +27,33 @@ SemaphoreFactory* SemaphoreFactory::instance() { } SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) { - return new BinarySemaphore(); + if(argument == USE_REGULAR_SEMAPHORES) { + return new BinarySemaphore(); + } + else if(argument == USE_TASK_NOTIFICATIONS) { + return new BinarySemaphoreUsingTask(); + } + else { + sif::warning << "SemaphoreFactory: Invalid argument, return regular" + "binary semaphore" << std::endl; + return new BinarySemaphore(); + } } SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t count, uint8_t initCount, uint32_t argument) { - return new CountingSemaphore(count, initCount); + if(argument == USE_REGULAR_SEMAPHORES) { + return new CountingSemaphore(count, initCount); + } + else if(argument == USE_TASK_NOTIFICATIONS) { + return new CountingSemaphoreUsingTask(count, initCount); + } + else { + sif::warning << "SemaphoreFactory: Invalid argument, return regular" + "binary semaphore" << std::endl; + return new CountingSemaphore(count, initCount); + } + } void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { From 7145982b4ade5f3da12e8dd05161b11e45512998 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 27 May 2020 19:59:59 +0200 Subject: [PATCH 67/94] improved documentation --- osal/FreeRTOS/BinSemaphUsingTask.cpp | 2 +- osal/FreeRTOS/BinSemaphUsingTask.h | 6 ++++++ tasks/SemaphoreIF.h | 3 ++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/osal/FreeRTOS/BinSemaphUsingTask.cpp b/osal/FreeRTOS/BinSemaphUsingTask.cpp index 0d732054..d6bc02bc 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.cpp +++ b/osal/FreeRTOS/BinSemaphUsingTask.cpp @@ -19,7 +19,7 @@ ReturnValue_t BinarySemaphoreUsingTask::takeBinarySemaphore(uint32_t timeoutMs) if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { timeout = SemaphoreIF::MAX_TIMEOUT; } - else if(timeoutMs > BinarySemaphoreUsingTask::NO_TIMEOUT){ + else if(timeoutMs > SemaphoreIF::NO_TIMEOUT){ timeout = pdMS_TO_TICKS(timeoutMs); } diff --git a/osal/FreeRTOS/BinSemaphUsingTask.h b/osal/FreeRTOS/BinSemaphUsingTask.h index 2736b1db..8b8a7773 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.h +++ b/osal/FreeRTOS/BinSemaphUsingTask.h @@ -9,6 +9,12 @@ extern "C" { #include } +/** + * @brief Binary Semaphore implementation using Task Notifications + * @details + * Additional information: https://www.freertos.org/RTOS-task-notifications.html + * and general semaphore documentation. + */ class BinarySemaphoreUsingTask: public SemaphoreIF, public HasReturnvaluesIF { public: diff --git a/tasks/SemaphoreIF.h b/tasks/SemaphoreIF.h index b2b113f1..fb181cca 100644 --- a/tasks/SemaphoreIF.h +++ b/tasks/SemaphoreIF.h @@ -12,7 +12,8 @@ * A semaphore is a synchronization primitive. * See: https://en.wikipedia.org/wiki/Semaphore_(programming) * A semaphore can be used to achieve task synchonization and track the - * availability of resources. + * availability of resources by using either the binary or the counting + * semaphore types. * * If mutual exlcusion of a resource is desired, a mutex should be used, * which is a special form of a semaphore and has an own interface. From 88e3dc15b2604de0c337f2bf4911ee5e4780588f Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 27 May 2020 21:27:31 +0200 Subject: [PATCH 68/94] replaced old semaph api --- osal/FreeRTOS/BinSemaphUsingTask.cpp | 16 +++++++++++++--- osal/FreeRTOS/BinSemaphUsingTask.h | 3 +++ osal/FreeRTOS/BinarySemaphore.cpp | 22 ++++++++-------------- osal/FreeRTOS/BinarySemaphore.h | 11 ++++------- osal/FreeRTOS/CountingSemaphUsingTask.cpp | 15 ++++++++++++--- osal/FreeRTOS/CountingSemaphUsingTask.h | 6 +++--- osal/FreeRTOS/SemaphoreFactory.cpp | 8 ++++---- tasks/SemaphoreFactory.h | 2 +- 8 files changed, 48 insertions(+), 35 deletions(-) diff --git a/osal/FreeRTOS/BinSemaphUsingTask.cpp b/osal/FreeRTOS/BinSemaphUsingTask.cpp index d6bc02bc..8cdcbc33 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.cpp +++ b/osal/FreeRTOS/BinSemaphUsingTask.cpp @@ -4,6 +4,8 @@ BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() { handle = TaskManagement::getCurrentTaskHandle(); + xTaskNotifyGive(handle); + locked = false; } ReturnValue_t BinarySemaphoreUsingTask::acquire(uint32_t timeoutMs) { @@ -25,6 +27,7 @@ ReturnValue_t BinarySemaphoreUsingTask::takeBinarySemaphore(uint32_t timeoutMs) BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeout); if (returncode == pdPASS) { + locked = true; return HasReturnvaluesIF::RETURN_OK; } else { @@ -36,6 +39,7 @@ ReturnValue_t BinarySemaphoreUsingTask::takeBinarySemaphoreTickTimeout( TickType_t timeoutTicks) { BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeoutTicks); if (returncode == pdPASS) { + locked = true; return HasReturnvaluesIF::RETURN_OK; } else { return SEMAPHORE_TIMEOUT; @@ -43,11 +47,15 @@ ReturnValue_t BinarySemaphoreUsingTask::takeBinarySemaphoreTickTimeout( } ReturnValue_t BinarySemaphoreUsingTask::giveBinarySemaphore() { + if(not locked) { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } BaseType_t returncode = xTaskNotifyGive(handle); if (returncode == pdPASS) { return HasReturnvaluesIF::RETURN_OK; } else { - return SEMAPHORE_NOT_OWNED; + // This should never happen + return HasReturnvaluesIF::RETURN_FAILED; } } @@ -77,8 +85,10 @@ ReturnValue_t BinarySemaphoreUsingTask::giveBinarySemaphore(TaskHandle_t taskHan BaseType_t returncode = xTaskNotifyGive(taskHandle); if (returncode == pdPASS) { return HasReturnvaluesIF::RETURN_OK; - } else { - return SEMAPHORE_NOT_OWNED; + } + else { + // This should never happen. + return HasReturnvaluesIF::RETURN_FAILED; } } diff --git a/osal/FreeRTOS/BinSemaphUsingTask.h b/osal/FreeRTOS/BinSemaphUsingTask.h index 8b8a7773..e44b838c 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.h +++ b/osal/FreeRTOS/BinSemaphUsingTask.h @@ -85,6 +85,9 @@ public: protected: TaskHandle_t handle; + // This boolean is required to track whether the semaphore is locked + // or unlocked. + bool locked; }; diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index d56be763..fa54b71f 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -7,6 +7,7 @@ BinarySemaphore::BinarySemaphore() { if(handle == nullptr) { sif::error << "Semaphore: Binary semaph creation failure" << std::endl; } + // Initiated semaphore must be given before it can be taken. xSemaphoreGive(handle); } @@ -34,7 +35,7 @@ BinarySemaphore& BinarySemaphore::operator =( return *this; } -ReturnValue_t BinarySemaphore::takeBinarySemaphore(uint32_t timeoutMs) { +ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { if(handle == nullptr) { return SEMAPHORE_NULLPOINTER; } @@ -55,7 +56,7 @@ ReturnValue_t BinarySemaphore::takeBinarySemaphore(uint32_t timeoutMs) { } } -ReturnValue_t BinarySemaphore::takeBinarySemaphoreTickTimeout( +ReturnValue_t BinarySemaphore::acquireWithTickTimeout( TickType_t timeoutTicks) { if(handle == nullptr) { return SEMAPHORE_NULLPOINTER; @@ -69,7 +70,7 @@ ReturnValue_t BinarySemaphore::takeBinarySemaphoreTickTimeout( } } -ReturnValue_t BinarySemaphore::giveBinarySemaphore() { +ReturnValue_t BinarySemaphore::release() { if (handle == nullptr) { return SEMAPHORE_NULLPOINTER; } @@ -96,26 +97,19 @@ ReturnValue_t BinarySemaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) return HasReturnvaluesIF::RETURN_FAILED; } } - -ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { - return takeBinarySemaphore(timeoutMs); -} - -ReturnValue_t BinarySemaphore::release() { - return giveBinarySemaphore(); -} uint8_t BinarySemaphore::getSemaphoreCounter() { return uxSemaphoreGetCount(handle); } // Be careful with the stack size here. This is called from an ISR! -ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, - BaseType_t * higherPriorityTaskWoken) { +ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR( + SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken) { if (semaphore == nullptr) { return SEMAPHORE_NULLPOINTER; } - BaseType_t returncode = xSemaphoreGiveFromISR(semaphore, higherPriorityTaskWoken); + BaseType_t returncode = xSemaphoreGiveFromISR(semaphore, + higherPriorityTaskWoken); if (returncode == pdPASS) { if(*higherPriorityTaskWoken == pdPASS) { // Request context switch because unblocking the semaphore diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index e5c0ce4b..0c2fe3bf 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -43,9 +43,6 @@ public: //! @brief Destructor virtual ~BinarySemaphore(); - ReturnValue_t acquire(uint32_t timeoutMs = - SemaphoreIF::NO_TIMEOUT) override; - ReturnValue_t release() override; uint8_t getSemaphoreCounter() override; /** @@ -57,8 +54,8 @@ public: * @return -@c RETURN_OK on success * -@c RETURN_FAILED on failure */ - ReturnValue_t takeBinarySemaphore(uint32_t timeoutMs = - SemaphoreIF::NO_TIMEOUT); + ReturnValue_t acquire(uint32_t timeoutMs = + SemaphoreIF::NO_TIMEOUT) override; /** * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. @@ -66,7 +63,7 @@ public: * @return - @c RETURN_OK on success * - @c RETURN_FAILED on failure */ - ReturnValue_t takeBinarySemaphoreTickTimeout(TickType_t timeoutTicks = + ReturnValue_t acquireWithTickTimeout(TickType_t timeoutTicks = BinarySemaphore::NO_TIMEOUT); /** @@ -74,7 +71,7 @@ public: * @return - @c RETURN_OK on success * - @c RETURN_FAILED on failure */ - ReturnValue_t giveBinarySemaphore(); + ReturnValue_t release() override; /** * Get Handle to the semaphore. diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.cpp b/osal/FreeRTOS/CountingSemaphUsingTask.cpp index 10365d7e..eecd986b 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.cpp +++ b/osal/FreeRTOS/CountingSemaphUsingTask.cpp @@ -1,10 +1,19 @@ #include #include +#include -CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(uint8_t count, - uint8_t initCount): - count(count), initCount(initCount) { +CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(uint8_t maxCount, + uint8_t initCount): maxCount(maxCount) { + if(initCount > maxCount) { + sif::error << "CountingSemaphoreUsingTask: Max count bigger than " + "intial cout. Setting initial count to max count." << std::endl; + initCount = maxCount; + } handle = TaskManagement::getCurrentTaskHandle(); + while(currentCount != initCount) { + xTaskNotifyGive(handle); + currentCount++; + } } ReturnValue_t CountingSemaphoreUsingTask::acquire( diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.h b/osal/FreeRTOS/CountingSemaphUsingTask.h index 7fc98e93..8c881d69 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.h +++ b/osal/FreeRTOS/CountingSemaphUsingTask.h @@ -11,7 +11,7 @@ extern "C" { class CountingSemaphoreUsingTask: public SemaphoreIF { public: - CountingSemaphoreUsingTask(uint8_t count, uint8_t initCount); + CountingSemaphoreUsingTask(uint8_t maxCount, uint8_t initCount); ReturnValue_t acquire(uint32_t timeoutMs) override; ReturnValue_t release() override; @@ -19,8 +19,8 @@ public: private: TaskHandle_t handle; - uint8_t count = 0; - uint8_t initCount = 0; + const uint8_t maxCount; + uint8_t currentCount = 0; }; #endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ */ diff --git a/osal/FreeRTOS/SemaphoreFactory.cpp b/osal/FreeRTOS/SemaphoreFactory.cpp index 6acdc7b7..05a898cd 100644 --- a/osal/FreeRTOS/SemaphoreFactory.cpp +++ b/osal/FreeRTOS/SemaphoreFactory.cpp @@ -40,18 +40,18 @@ SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) { } } -SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t count, +SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t maxCount, uint8_t initCount, uint32_t argument) { if(argument == USE_REGULAR_SEMAPHORES) { - return new CountingSemaphore(count, initCount); + return new CountingSemaphore(maxCount, initCount); } else if(argument == USE_TASK_NOTIFICATIONS) { - return new CountingSemaphoreUsingTask(count, initCount); + return new CountingSemaphoreUsingTask(maxCount, initCount); } else { sif::warning << "SemaphoreFactory: Invalid argument, return regular" "binary semaphore" << std::endl; - return new CountingSemaphore(count, initCount); + return new CountingSemaphore(maxCount, initCount); } } diff --git a/tasks/SemaphoreFactory.h b/tasks/SemaphoreFactory.h index 971e97fa..75bbe25d 100644 --- a/tasks/SemaphoreFactory.h +++ b/tasks/SemaphoreFactory.h @@ -33,7 +33,7 @@ public: * @param argument Can be used to pass implementation specific information. * @return */ - SemaphoreIF* createCountingSemaphore(uint8_t count, uint8_t initCount, + SemaphoreIF* createCountingSemaphore(uint8_t maxCount, uint8_t initCount, uint32_t argument = 0); void deleteSemaphore(SemaphoreIF* mutex); From c4e60946d3282c497714cb9345918069afb11047 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 27 May 2020 21:30:20 +0200 Subject: [PATCH 69/94] improved bin semaph implementation --- osal/FreeRTOS/BinarySemaphore.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index fa54b71f..e6bb8dca 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -37,7 +37,7 @@ BinarySemaphore& BinarySemaphore::operator =( ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { if(handle == nullptr) { - return SEMAPHORE_NULLPOINTER; + return SemaphoreIF::SEMAPHORE_NULLPOINTER; } TickType_t timeout = SemaphoreIF::NO_TIMEOUT; if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { @@ -59,14 +59,14 @@ ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { ReturnValue_t BinarySemaphore::acquireWithTickTimeout( TickType_t timeoutTicks) { if(handle == nullptr) { - return SEMAPHORE_NULLPOINTER; + return SemaphoreIF::SEMAPHORE_NULLPOINTER; } BaseType_t returncode = xSemaphoreTake(handle, timeoutTicks); if (returncode == pdPASS) { return HasReturnvaluesIF::RETURN_OK; } else { - return SEMAPHORE_TIMEOUT; + return SemaphoreIF::SEMAPHORE_TIMEOUT; } } @@ -82,13 +82,17 @@ ReturnValue_t BinarySemaphore::release() { } } +uint8_t BinarySemaphore::getSemaphoreCounter() { + return uxSemaphoreGetCount(handle); +} + SemaphoreHandle_t BinarySemaphore::getSemaphore() { return handle; } ReturnValue_t BinarySemaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) { if (semaphore == nullptr) { - return SEMAPHORE_NULLPOINTER; + return SemaphoreIF::SEMAPHORE_NULLPOINTER; } BaseType_t returncode = xSemaphoreGive(semaphore); if (returncode == pdPASS) { @@ -96,17 +100,13 @@ ReturnValue_t BinarySemaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) } else { return HasReturnvaluesIF::RETURN_FAILED; } -} - -uint8_t BinarySemaphore::getSemaphoreCounter() { - return uxSemaphoreGetCount(handle); } // Be careful with the stack size here. This is called from an ISR! ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR( SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken) { if (semaphore == nullptr) { - return SEMAPHORE_NULLPOINTER; + return SemaphoreIF::SEMAPHORE_NULLPOINTER; } BaseType_t returncode = xSemaphoreGiveFromISR(semaphore, higherPriorityTaskWoken); @@ -117,7 +117,8 @@ ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR( TaskManagement::requestContextSwitch(CallContext::isr); } return HasReturnvaluesIF::RETURN_OK; - } else { - return SEMAPHORE_NOT_OWNED; + } + else { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; } } From 95bf5c1071a84696cc0e15abf9a01102764caaca Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 27 May 2020 21:33:34 +0200 Subject: [PATCH 70/94] improved const correctness --- osal/FreeRTOS/BinSemaphUsingTask.cpp | 2 +- osal/FreeRTOS/BinSemaphUsingTask.h | 2 +- osal/FreeRTOS/BinarySemaphore.cpp | 2 +- osal/FreeRTOS/BinarySemaphore.h | 2 +- osal/FreeRTOS/CountingSemaphUsingTask.cpp | 5 ++--- osal/FreeRTOS/CountingSemaphUsingTask.h | 2 +- tasks/SemaphoreIF.h | 2 +- 7 files changed, 8 insertions(+), 9 deletions(-) diff --git a/osal/FreeRTOS/BinSemaphUsingTask.cpp b/osal/FreeRTOS/BinSemaphUsingTask.cpp index 8cdcbc33..2a5ca3bd 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.cpp +++ b/osal/FreeRTOS/BinSemaphUsingTask.cpp @@ -63,7 +63,7 @@ TaskHandle_t BinarySemaphoreUsingTask::getTaskHandle() { return handle; } -uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter() { +uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter() const { uint32_t notificationValue; xTaskNotifyAndQuery(handle, 0, eNoAction, ¬ificationValue); return notificationValue; diff --git a/osal/FreeRTOS/BinSemaphUsingTask.h b/osal/FreeRTOS/BinSemaphUsingTask.h index e44b838c..b65d4d80 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.h +++ b/osal/FreeRTOS/BinSemaphUsingTask.h @@ -26,7 +26,7 @@ public: ReturnValue_t acquire(uint32_t timeoutMs = SemaphoreIF::NO_TIMEOUT) override; ReturnValue_t release() override; - uint8_t getSemaphoreCounter() override; + uint8_t getSemaphoreCounter() const override; /** * Take the binary semaphore. diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index e6bb8dca..0d8d415c 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -82,7 +82,7 @@ ReturnValue_t BinarySemaphore::release() { } } -uint8_t BinarySemaphore::getSemaphoreCounter() { +uint8_t BinarySemaphore::getSemaphoreCounter() const { return uxSemaphoreGetCount(handle); } diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 0c2fe3bf..b883f801 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -43,7 +43,7 @@ public: //! @brief Destructor virtual ~BinarySemaphore(); - uint8_t getSemaphoreCounter() override; + uint8_t getSemaphoreCounter() const override; /** * Take the binary semaphore. diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.cpp b/osal/FreeRTOS/CountingSemaphUsingTask.cpp index eecd986b..d08a549e 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.cpp +++ b/osal/FreeRTOS/CountingSemaphUsingTask.cpp @@ -16,8 +16,7 @@ CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(uint8_t maxCount, } } -ReturnValue_t CountingSemaphoreUsingTask::acquire( - uint32_t timeoutMs) { +ReturnValue_t CountingSemaphoreUsingTask::acquire(uint32_t timeoutMs) { return HasReturnvaluesIF::RETURN_OK; } @@ -25,6 +24,6 @@ ReturnValue_t CountingSemaphoreUsingTask::release() { return HasReturnvaluesIF::RETURN_OK; } -uint8_t CountingSemaphoreUsingTask::getSemaphoreCounter() { +uint8_t CountingSemaphoreUsingTask::getSemaphoreCounter() const { return 0; } diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.h b/osal/FreeRTOS/CountingSemaphUsingTask.h index 8c881d69..877a975e 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.h +++ b/osal/FreeRTOS/CountingSemaphUsingTask.h @@ -15,7 +15,7 @@ public: ReturnValue_t acquire(uint32_t timeoutMs) override; ReturnValue_t release() override; - uint8_t getSemaphoreCounter() override; + uint8_t getSemaphoreCounter() const override; private: TaskHandle_t handle; diff --git a/tasks/SemaphoreIF.h b/tasks/SemaphoreIF.h index fb181cca..044e03a8 100644 --- a/tasks/SemaphoreIF.h +++ b/tasks/SemaphoreIF.h @@ -55,7 +55,7 @@ public: * is returned if the semaphore is available, and 0 is returned if the * semaphore is not available. */ - virtual uint8_t getSemaphoreCounter() = 0; + virtual uint8_t getSemaphoreCounter() const = 0; }; #endif /* FRAMEWORK_TASKS_SEMAPHOREIF_H_ */ From 63dbf995925f181f406173ba380d36b8faadb393 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 27 May 2020 22:12:52 +0200 Subject: [PATCH 71/94] counting semaph implementation finished --- osal/FreeRTOS/BinSemaphUsingTask.cpp | 42 ++++------- osal/FreeRTOS/BinSemaphUsingTask.h | 32 ++------- osal/FreeRTOS/BinarySemaphore.cpp | 24 +++---- osal/FreeRTOS/CountingSemaphUsingTask.cpp | 88 +++++++++++++++++++++-- osal/FreeRTOS/CountingSemaphUsingTask.h | 32 ++++++++- osal/FreeRTOS/CountingSemaphore.cpp | 13 ++-- osal/FreeRTOS/CountingSemaphore.h | 4 +- tasks/SemaphoreFactory.h | 6 +- 8 files changed, 154 insertions(+), 87 deletions(-) diff --git a/osal/FreeRTOS/BinSemaphUsingTask.cpp b/osal/FreeRTOS/BinSemaphUsingTask.cpp index 2a5ca3bd..9c2afe10 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.cpp +++ b/osal/FreeRTOS/BinSemaphUsingTask.cpp @@ -1,7 +1,6 @@ #include #include - BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() { handle = TaskManagement::getCurrentTaskHandle(); xTaskNotifyGive(handle); @@ -9,44 +8,29 @@ BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() { } ReturnValue_t BinarySemaphoreUsingTask::acquire(uint32_t timeoutMs) { - return takeBinarySemaphore(timeoutMs); -} - -ReturnValue_t BinarySemaphoreUsingTask::release() { - return giveBinarySemaphore(); -} - -ReturnValue_t BinarySemaphoreUsingTask::takeBinarySemaphore(uint32_t timeoutMs) { TickType_t timeout = SemaphoreIF::NO_TIMEOUT; if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { - timeout = SemaphoreIF::MAX_TIMEOUT; + timeout = SemaphoreIF::MAX_TIMEOUT; } else if(timeoutMs > SemaphoreIF::NO_TIMEOUT){ - timeout = pdMS_TO_TICKS(timeoutMs); - } - - BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeout); - if (returncode == pdPASS) { - locked = true; - return HasReturnvaluesIF::RETURN_OK; - } - else { - return SemaphoreIF::SEMAPHORE_TIMEOUT; + timeout = pdMS_TO_TICKS(timeoutMs); } + return acquireWithTickTimeout(timeout); } -ReturnValue_t BinarySemaphoreUsingTask::takeBinarySemaphoreTickTimeout( +ReturnValue_t BinarySemaphoreUsingTask::acquireWithTickTimeout( TickType_t timeoutTicks) { BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeoutTicks); if (returncode == pdPASS) { locked = true; return HasReturnvaluesIF::RETURN_OK; - } else { - return SEMAPHORE_TIMEOUT; + } + else { + return SemaphoreIF::SEMAPHORE_TIMEOUT; } } -ReturnValue_t BinarySemaphoreUsingTask::giveBinarySemaphore() { +ReturnValue_t BinarySemaphoreUsingTask::release() { if(not locked) { return SemaphoreIF::SEMAPHORE_NOT_OWNED; } @@ -69,7 +53,9 @@ uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter() const { return notificationValue; } -uint8_t BinarySemaphoreUsingTask::getSemaphoreCounterFromISR(TaskHandle_t taskHandle) { + +uint8_t BinarySemaphoreUsingTask::getSemaphoreCounterFromISR( + TaskHandle_t taskHandle) { uint32_t notificationValue; BaseType_t higherPriorityTaskWoken; xTaskNotifyAndQueryFromISR(taskHandle, 0, eNoAction, ¬ificationValue, @@ -80,8 +66,8 @@ uint8_t BinarySemaphoreUsingTask::getSemaphoreCounterFromISR(TaskHandle_t taskHa return notificationValue; } - -ReturnValue_t BinarySemaphoreUsingTask::giveBinarySemaphore(TaskHandle_t taskHandle) { +ReturnValue_t BinarySemaphoreUsingTask::release( + TaskHandle_t taskHandle) { BaseType_t returncode = xTaskNotifyGive(taskHandle); if (returncode == pdPASS) { return HasReturnvaluesIF::RETURN_OK; @@ -93,7 +79,7 @@ ReturnValue_t BinarySemaphoreUsingTask::giveBinarySemaphore(TaskHandle_t taskHan } // Be careful with the stack size here. This is called from an ISR! -ReturnValue_t BinarySemaphoreUsingTask::giveBinarySemaphoreFromISR( +ReturnValue_t BinarySemaphoreUsingTask::releaseFromISR( TaskHandle_t taskHandle, BaseType_t * higherPriorityTaskWoken) { vTaskNotifyGiveFromISR(taskHandle, higherPriorityTaskWoken); if(*higherPriorityTaskWoken == pdPASS) { diff --git a/osal/FreeRTOS/BinSemaphUsingTask.h b/osal/FreeRTOS/BinSemaphUsingTask.h index b65d4d80..cb6f6287 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.h +++ b/osal/FreeRTOS/BinSemaphUsingTask.h @@ -27,35 +27,17 @@ public: SemaphoreIF::NO_TIMEOUT) override; ReturnValue_t release() override; uint8_t getSemaphoreCounter() const override; + static uint8_t getSemaphoreCounterFromISR(TaskHandle_t taskHandle); /** - * Take the binary semaphore. - * If the semaphore has already been taken, the task will be blocked - * for a maximum of #timeoutMs or until the semaphore is given back, - * for example by an ISR or another task. - * @param timeoutMs - * @return -@c RETURN_OK on success - * -@c RETURN_FAILED on failure - */ - ReturnValue_t takeBinarySemaphore(uint32_t timeoutMs = - SemaphoreIF::NO_TIMEOUT); - - /** - * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. + * Same as acquire() with timeout in FreeRTOS ticks. * @param timeoutTicks * @return - @c RETURN_OK on success * - @c RETURN_FAILED on failure */ - ReturnValue_t takeBinarySemaphoreTickTimeout(TickType_t timeoutTicks = + ReturnValue_t acquireWithTickTimeout(TickType_t timeoutTicks = SemaphoreIF::NO_TIMEOUT); - /** - * Give back the binary semaphore - * @return - @c RETURN_OK on success - * - @c RETURN_FAILED on failure - */ - ReturnValue_t giveBinarySemaphore(); - /** * Get handle to the task related to the semaphore. * @return @@ -68,7 +50,7 @@ public: * @return - @c RETURN_OK on success * - @c RETURN_FAILED on failure */ - static ReturnValue_t giveBinarySemaphore(TaskHandle_t taskToNotify); + static ReturnValue_t release(TaskHandle_t taskToNotify); /** * Wrapper function to give back semaphore from handle when called from an ISR @@ -78,11 +60,9 @@ public: * @return - @c RETURN_OK on success * - @c RETURN_FAILED on failure */ - static ReturnValue_t giveBinarySemaphoreFromISR(TaskHandle_t taskToNotify, + static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify, BaseType_t * higherPriorityTaskWoken); - static uint8_t getSemaphoreCounterFromISR(TaskHandle_t taskHandle); - protected: TaskHandle_t handle; // This boolean is required to track whether the semaphore is locked @@ -90,6 +70,4 @@ protected: bool locked; }; - - #endif /* FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ */ diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index 0d8d415c..8891b755 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -43,21 +43,13 @@ ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { timeout = SemaphoreIF::MAX_TIMEOUT; } - else if(timeoutMs > BinarySemaphore::NO_TIMEOUT){ + else if(timeoutMs > SemaphoreIF::NO_TIMEOUT){ timeout = pdMS_TO_TICKS(timeoutMs); } - - BaseType_t returncode = xSemaphoreTake(handle, timeout); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - return SemaphoreIF::SEMAPHORE_TIMEOUT; - } + return acquireWithTickTimeout(timeout); } -ReturnValue_t BinarySemaphore::acquireWithTickTimeout( - TickType_t timeoutTicks) { +ReturnValue_t BinarySemaphore::acquireWithTickTimeout(TickType_t timeoutTicks) { if(handle == nullptr) { return SemaphoreIF::SEMAPHORE_NULLPOINTER; } @@ -65,20 +57,22 @@ ReturnValue_t BinarySemaphore::acquireWithTickTimeout( BaseType_t returncode = xSemaphoreTake(handle, timeoutTicks); if (returncode == pdPASS) { return HasReturnvaluesIF::RETURN_OK; - } else { + } + else { return SemaphoreIF::SEMAPHORE_TIMEOUT; } } ReturnValue_t BinarySemaphore::release() { if (handle == nullptr) { - return SEMAPHORE_NULLPOINTER; + return SemaphoreIF::SEMAPHORE_NULLPOINTER; } BaseType_t returncode = xSemaphoreGive(handle); if (returncode == pdPASS) { return HasReturnvaluesIF::RETURN_OK; - } else { - return SEMAPHORE_NOT_OWNED; + } + else { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; } } diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.cpp b/osal/FreeRTOS/CountingSemaphUsingTask.cpp index d08a549e..9beca310 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.cpp +++ b/osal/FreeRTOS/CountingSemaphUsingTask.cpp @@ -2,7 +2,7 @@ #include #include -CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(uint8_t maxCount, +CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(const uint8_t maxCount, uint8_t initCount): maxCount(maxCount) { if(initCount > maxCount) { sif::error << "CountingSemaphoreUsingTask: Max count bigger than " @@ -17,13 +17,93 @@ CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(uint8_t maxCount, } ReturnValue_t CountingSemaphoreUsingTask::acquire(uint32_t timeoutMs) { - return HasReturnvaluesIF::RETURN_OK; + TickType_t timeout = SemaphoreIF::NO_TIMEOUT; + if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { + timeout = SemaphoreIF::MAX_TIMEOUT; + } + else if(timeoutMs > SemaphoreIF::NO_TIMEOUT){ + timeout = pdMS_TO_TICKS(timeoutMs); + } + + BaseType_t returncode = ulTaskNotifyTake(pdFALSE, timeout); + if (returncode == pdPASS) { + currentCount--; + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SemaphoreIF::SEMAPHORE_TIMEOUT; + } +} + +ReturnValue_t CountingSemaphoreUsingTask::acquireWithTickTimeout( + TickType_t timeoutTicks) { + BaseType_t returncode = ulTaskNotifyTake(pdFALSE, timeoutTicks); + if (returncode == pdPASS) { + currentCount--; + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SemaphoreIF::SEMAPHORE_TIMEOUT; + } } ReturnValue_t CountingSemaphoreUsingTask::release() { - return HasReturnvaluesIF::RETURN_OK; + if(currentCount == maxCount) { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } + BaseType_t returncode = xTaskNotifyGive(handle); + if (returncode == pdPASS) { + currentCount++; + return HasReturnvaluesIF::RETURN_OK; + } + else { + // This should never happen + return HasReturnvaluesIF::RETURN_FAILED; + } } uint8_t CountingSemaphoreUsingTask::getSemaphoreCounter() const { - return 0; + uint32_t notificationValue; + xTaskNotifyAndQuery(handle, 0, eNoAction, ¬ificationValue); + return notificationValue; +} + +TaskHandle_t CountingSemaphoreUsingTask::getTaskHandle() { + return handle; +} + + +uint8_t CountingSemaphoreUsingTask::getSemaphoreCounterFromISR( + TaskHandle_t task) { + uint32_t notificationValue; + BaseType_t higherPriorityTaskWoken = 0; + xTaskNotifyAndQueryFromISR(task, 0, eNoAction, ¬ificationValue, + &higherPriorityTaskWoken); + if(higherPriorityTaskWoken == pdTRUE) { + TaskManagement::requestContextSwitch(CallContext::isr); + } + return notificationValue; +} + +ReturnValue_t CountingSemaphoreUsingTask::release( + TaskHandle_t taskToNotify) { + BaseType_t returncode = xTaskNotifyGive(taskToNotify); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + // This should never happen. + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t CountingSemaphoreUsingTask::releaseFromISR( + TaskHandle_t taskToNotify, BaseType_t* higherPriorityTaskWoken) { + vTaskNotifyGiveFromISR(taskToNotify, higherPriorityTaskWoken); + if(*higherPriorityTaskWoken == pdPASS) { + // Request context switch because unblocking the semaphore + // caused a high priority task unblock. + TaskManagement::requestContextSwitch(CallContext::isr); + } + return HasReturnvaluesIF::RETURN_OK; } diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.h b/osal/FreeRTOS/CountingSemaphUsingTask.h index 877a975e..ac0425b5 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.h +++ b/osal/FreeRTOS/CountingSemaphUsingTask.h @@ -11,11 +11,39 @@ extern "C" { class CountingSemaphoreUsingTask: public SemaphoreIF { public: - CountingSemaphoreUsingTask(uint8_t maxCount, uint8_t initCount); + CountingSemaphoreUsingTask(const uint8_t maxCount, uint8_t initCount); - ReturnValue_t acquire(uint32_t timeoutMs) override; + ReturnValue_t acquire(uint32_t timeoutMs = SemaphoreIF::NO_TIMEOUT) override; ReturnValue_t release() override; uint8_t getSemaphoreCounter() const override; + static uint8_t getSemaphoreCounterFromISR(TaskHandle_t task); + /** + * Acquire, using a timeout value in ticks + * @param timeoutTicks + * @return + */ + ReturnValue_t acquireWithTickTimeout( + TickType_t timeoutTicks= SemaphoreIF::NO_TIMEOUT); + + /** + * Get handle to the task related to the semaphore. + * @return + */ + TaskHandle_t getTaskHandle(); + + /** + * Release semaphore of task by supplying task handle + * @param taskToNotify + * @return + */ + static ReturnValue_t release(TaskHandle_t taskToNotify); + /** + * Release seamphore of a task from an ISR. + * @param taskToNotify + * @return + */ + static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify, + BaseType_t* higherPriorityTaskWoken); private: TaskHandle_t handle; diff --git a/osal/FreeRTOS/CountingSemaphore.cpp b/osal/FreeRTOS/CountingSemaphore.cpp index 2f0dfd76..a23f32a0 100644 --- a/osal/FreeRTOS/CountingSemaphore.cpp +++ b/osal/FreeRTOS/CountingSemaphore.cpp @@ -8,16 +8,17 @@ extern "C" { // Make sure #define configUSE_COUNTING_SEMAPHORES 1 is set in // free FreeRTOSConfig.h file. -CountingSemaphore::CountingSemaphore(uint8_t count, uint8_t initCount): - count(count), initCount(initCount) { - handle = xSemaphoreCreateCounting(count, initCount); +CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): + maxCount(maxCount), initCount(initCount) { + handle = xSemaphoreCreateCounting(maxCount, initCount); if(handle == nullptr) { sif::error << "CountingSemaphore: Creation failure" << std::endl; } } -CountingSemaphore::CountingSemaphore(CountingSemaphore&& other) { - handle = xSemaphoreCreateCounting(other.count, other.initCount); +CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): + maxCount(other.maxCount), initCount(other.initCount) { + handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); if(handle == nullptr) { sif::error << "CountingSemaphore: Creation failure" << std::endl; } @@ -25,7 +26,7 @@ CountingSemaphore::CountingSemaphore(CountingSemaphore&& other) { CountingSemaphore& CountingSemaphore::operator =( CountingSemaphore&& other) { - handle = xSemaphoreCreateCounting(other.count, other.initCount); + handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); if(handle == nullptr) { sif::error << "CountingSemaphore: Creation failure" << std::endl; } diff --git a/osal/FreeRTOS/CountingSemaphore.h b/osal/FreeRTOS/CountingSemaphore.h index a33a0fa5..77050f90 100644 --- a/osal/FreeRTOS/CountingSemaphore.h +++ b/osal/FreeRTOS/CountingSemaphore.h @@ -12,7 +12,7 @@ */ class CountingSemaphore: public BinarySemaphore { public: - CountingSemaphore(uint8_t count, uint8_t initCount); + CountingSemaphore(const uint8_t maxCount, uint8_t initCount); //! @brief Copy ctor, disabled CountingSemaphore(const CountingSemaphore&) = delete; //! @brief Copy assignment, disabled @@ -22,7 +22,7 @@ public: //! @brief Move assignment CountingSemaphore & operator=(CountingSemaphore &&); private: - uint8_t count = 0; + const uint8_t maxCount; uint8_t initCount = 0; }; diff --git a/tasks/SemaphoreFactory.h b/tasks/SemaphoreFactory.h index 75bbe25d..3e21be36 100644 --- a/tasks/SemaphoreFactory.h +++ b/tasks/SemaphoreFactory.h @@ -23,7 +23,7 @@ public: * @param argument Can be used to pass implementation specific information. * @return Pointer to newly created semaphore class instance. */ - SemaphoreIF* createBinarySemaphore(uint32_t argument = 0); + SemaphoreIF* createBinarySemaphore(uint32_t arguments = 0); /** * Create a counting semaphore. * Creator functons for a counting semaphore which may be acquired multiple @@ -33,8 +33,8 @@ public: * @param argument Can be used to pass implementation specific information. * @return */ - SemaphoreIF* createCountingSemaphore(uint8_t maxCount, uint8_t initCount, - uint32_t argument = 0); + SemaphoreIF* createCountingSemaphore(const uint8_t maxCount, + uint8_t initCount, uint32_t arguments = 0); void deleteSemaphore(SemaphoreIF* mutex); From 7ce505fdf9234630298dc6560b625cc44f41770a Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 27 May 2020 23:29:06 +0200 Subject: [PATCH 72/94] some safety updates and fixes --- osal/FreeRTOS/BinSemaphUsingTask.cpp | 10 ++++++ osal/FreeRTOS/BinSemaphUsingTask.h | 6 +++- osal/FreeRTOS/CountingSemaphUsingTask.cpp | 40 ++++++++++++++++------- osal/FreeRTOS/CountingSemaphUsingTask.h | 9 +++++ 4 files changed, 52 insertions(+), 13 deletions(-) diff --git a/osal/FreeRTOS/BinSemaphUsingTask.cpp b/osal/FreeRTOS/BinSemaphUsingTask.cpp index 9c2afe10..84b0b488 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.cpp +++ b/osal/FreeRTOS/BinSemaphUsingTask.cpp @@ -1,12 +1,22 @@ #include #include +#include BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() { handle = TaskManagement::getCurrentTaskHandle(); + if(handle == nullptr) { + sif::error << "Could not retrieve task handle. Please ensure the" + "constructor was called inside a task." << std::endl; + } xTaskNotifyGive(handle); locked = false; } +BinarySemaphoreUsingTask::~BinarySemaphoreUsingTask() { + // Clear notification value on destruction. + xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr); +} + ReturnValue_t BinarySemaphoreUsingTask::acquire(uint32_t timeoutMs) { TickType_t timeout = SemaphoreIF::NO_TIMEOUT; if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { diff --git a/osal/FreeRTOS/BinSemaphUsingTask.h b/osal/FreeRTOS/BinSemaphUsingTask.h index cb6f6287..cad42783 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.h +++ b/osal/FreeRTOS/BinSemaphUsingTask.h @@ -10,7 +10,9 @@ extern "C" { } /** - * @brief Binary Semaphore implementation using Task Notifications + * @brief Binary Semaphore implementation using the task notification value. + * The notification value should therefore not be used + * for other purposes. * @details * Additional information: https://www.freertos.org/RTOS-task-notifications.html * and general semaphore documentation. @@ -22,6 +24,8 @@ public: //! @brief Default ctor BinarySemaphoreUsingTask(); + //! @brief Default dtor + virtual~ BinarySemaphoreUsingTask(); ReturnValue_t acquire(uint32_t timeoutMs = SemaphoreIF::NO_TIMEOUT) override; diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.cpp b/osal/FreeRTOS/CountingSemaphUsingTask.cpp index 9beca310..c29f5258 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.cpp +++ b/osal/FreeRTOS/CountingSemaphUsingTask.cpp @@ -9,13 +9,35 @@ CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(const uint8_t maxCount, "intial cout. Setting initial count to max count." << std::endl; initCount = maxCount; } + handle = TaskManagement::getCurrentTaskHandle(); + if(handle == nullptr) { + sif::error << "Could not retrieve task handle. Please ensure the" + "constructor was called inside a task." << std::endl; + } + + uint32_t oldNotificationValue; + xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, + &oldNotificationValue); + if(oldNotificationValue != 0) { + sif::warning << "Semaphore initiated but current notification value" + " is not 0. Please ensure the notification value is not used" + "for other purposes!" << std::endl; + } + while(currentCount != initCount) { xTaskNotifyGive(handle); currentCount++; } } +CountingSemaphoreUsingTask::~CountingSemaphoreUsingTask() { + // Clear notification value on destruction. + // If this is not desired, don't call the destructor + // (or implement a boolea which disables the reset) + xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr); +} + ReturnValue_t CountingSemaphoreUsingTask::acquire(uint32_t timeoutMs) { TickType_t timeout = SemaphoreIF::NO_TIMEOUT; if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { @@ -24,22 +46,16 @@ ReturnValue_t CountingSemaphoreUsingTask::acquire(uint32_t timeoutMs) { else if(timeoutMs > SemaphoreIF::NO_TIMEOUT){ timeout = pdMS_TO_TICKS(timeoutMs); } + return acquireWithTickTimeout(timeout); - BaseType_t returncode = ulTaskNotifyTake(pdFALSE, timeout); - if (returncode == pdPASS) { - currentCount--; - return HasReturnvaluesIF::RETURN_OK; - } - else { - return SemaphoreIF::SEMAPHORE_TIMEOUT; - } } ReturnValue_t CountingSemaphoreUsingTask::acquireWithTickTimeout( TickType_t timeoutTicks) { - BaseType_t returncode = ulTaskNotifyTake(pdFALSE, timeoutTicks); - if (returncode == pdPASS) { - currentCount--; + // Decrement notfication value without resetting it. + BaseType_t oldCount = ulTaskNotifyTake(pdFALSE, timeoutTicks); + if (getSemaphoreCounter() == oldCount - 1) { + currentCount --; return HasReturnvaluesIF::RETURN_OK; } else { @@ -63,7 +79,7 @@ ReturnValue_t CountingSemaphoreUsingTask::release() { } uint8_t CountingSemaphoreUsingTask::getSemaphoreCounter() const { - uint32_t notificationValue; + uint32_t notificationValue = 0; xTaskNotifyAndQuery(handle, 0, eNoAction, ¬ificationValue); return notificationValue; } diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.h b/osal/FreeRTOS/CountingSemaphUsingTask.h index ac0425b5..2c54b31b 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.h +++ b/osal/FreeRTOS/CountingSemaphUsingTask.h @@ -9,9 +9,18 @@ extern "C" { #include } +/** + * @brief Couting Semaphore implementation which uses the notification value + * of the task. The notification value should therefore not be used + * for other purposes + * @details + * Additional information: https://www.freertos.org/RTOS-task-notifications.html + * and general semaphore documentation. + */ class CountingSemaphoreUsingTask: public SemaphoreIF { public: CountingSemaphoreUsingTask(const uint8_t maxCount, uint8_t initCount); + virtual ~CountingSemaphoreUsingTask(); ReturnValue_t acquire(uint32_t timeoutMs = SemaphoreIF::NO_TIMEOUT) override; ReturnValue_t release() override; From 08ffe89682e72c70876d3dbfd0555161e16608e9 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 27 May 2020 23:41:59 +0200 Subject: [PATCH 73/94] doc and api improvements --- osal/FreeRTOS/BinarySemaphore.cpp | 4 +-- osal/FreeRTOS/BinarySemaphore.h | 27 ++++++++++--------- osal/FreeRTOS/CountingSemaphUsingTask.h | 36 ++++++++++++++++++++----- osal/FreeRTOS/CountingSemaphore.h | 4 +++ 4 files changed, 51 insertions(+), 20 deletions(-) diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index 8891b755..7d882aff 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -84,7 +84,7 @@ SemaphoreHandle_t BinarySemaphore::getSemaphore() { return handle; } -ReturnValue_t BinarySemaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) { +ReturnValue_t BinarySemaphore::release(SemaphoreHandle_t semaphore) { if (semaphore == nullptr) { return SemaphoreIF::SEMAPHORE_NULLPOINTER; } @@ -97,7 +97,7 @@ ReturnValue_t BinarySemaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) } // Be careful with the stack size here. This is called from an ISR! -ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR( +ReturnValue_t BinarySemaphore::releaseFromISR( SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken) { if (semaphore == nullptr) { return SemaphoreIF::SEMAPHORE_NULLPOINTER; diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index b883f801..f3839151 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -52,7 +52,7 @@ public: * for example by an ISR or another task. * @param timeoutMs * @return -@c RETURN_OK on success - * -@c RETURN_FAILED on failure + * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout */ ReturnValue_t acquire(uint32_t timeoutMs = SemaphoreIF::NO_TIMEOUT) override; @@ -60,16 +60,17 @@ public: /** * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. * @param timeoutTicks - * @return - @c RETURN_OK on success - * - @c RETURN_FAILED on failure + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout */ ReturnValue_t acquireWithTickTimeout(TickType_t timeoutTicks = BinarySemaphore::NO_TIMEOUT); /** - * Give back the binary semaphore - * @return - @c RETURN_OK on success - * - @c RETURN_FAILED on failure + * Release the binary semaphore. + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is + * already available. */ ReturnValue_t release() override; @@ -82,20 +83,22 @@ public: /** * Wrapper function to give back semaphore from handle * @param semaphore - * @return - @c RETURN_OK on success - * - @c RETURN_FAILED on failure + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is + * already available. */ - static ReturnValue_t giveBinarySemaphore(SemaphoreHandle_t semaphore); + static ReturnValue_t release(SemaphoreHandle_t semaphore); /** * Wrapper function to give back semaphore from handle when called from an ISR * @param semaphore * @param higherPriorityTaskWoken This will be set to pdPASS if a task with a higher priority * was unblocked - * @return - @c RETURN_OK on success - * - @c RETURN_FAILED on failure + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is + * already available. */ - static ReturnValue_t giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, + static ReturnValue_t releaseFromISR(SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken); protected: diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.h b/osal/FreeRTOS/CountingSemaphUsingTask.h index 2c54b31b..73d3f987 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.h +++ b/osal/FreeRTOS/CountingSemaphUsingTask.h @@ -12,7 +12,7 @@ extern "C" { /** * @brief Couting Semaphore implementation which uses the notification value * of the task. The notification value should therefore not be used - * for other purposes + * for other purposes. * @details * Additional information: https://www.freertos.org/RTOS-task-notifications.html * and general semaphore documentation. @@ -22,17 +22,37 @@ public: CountingSemaphoreUsingTask(const uint8_t maxCount, uint8_t initCount); virtual ~CountingSemaphoreUsingTask(); + /** + * Acquire the counting semaphore. + * If no semaphores are available, the task will be blocked + * for a maximum of #timeoutMs or until one is given back, + * for example by an ISR or another task. + * @param timeoutMs + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout + */ ReturnValue_t acquire(uint32_t timeoutMs = SemaphoreIF::NO_TIMEOUT) override; + + /** + * Release a semaphore, increasing the number of available counting + * semaphores up to the #maxCount value. + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are + * already available. + */ ReturnValue_t release() override; + uint8_t getSemaphoreCounter() const override; static uint8_t getSemaphoreCounterFromISR(TaskHandle_t task); + /** - * Acquire, using a timeout value in ticks + * Acquire with a timeout value in ticks * @param timeoutTicks - * @return + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout */ ReturnValue_t acquireWithTickTimeout( - TickType_t timeoutTicks= SemaphoreIF::NO_TIMEOUT); + TickType_t timeoutTicks = SemaphoreIF::NO_TIMEOUT); /** * Get handle to the task related to the semaphore. @@ -43,13 +63,17 @@ public: /** * Release semaphore of task by supplying task handle * @param taskToNotify - * @return + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are + * already available. */ static ReturnValue_t release(TaskHandle_t taskToNotify); /** * Release seamphore of a task from an ISR. * @param taskToNotify - * @return + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are + * already available. */ static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify, BaseType_t* higherPriorityTaskWoken); diff --git a/osal/FreeRTOS/CountingSemaphore.h b/osal/FreeRTOS/CountingSemaphore.h index 77050f90..bed3c726 100644 --- a/osal/FreeRTOS/CountingSemaphore.h +++ b/osal/FreeRTOS/CountingSemaphore.h @@ -21,6 +21,10 @@ public: CountingSemaphore (CountingSemaphore &&); //! @brief Move assignment CountingSemaphore & operator=(CountingSemaphore &&); + + /* Same API as binary semaphore otherwise. acquire() can be called + * until there are not semaphores left and release() can be called + * until maxCount is reached. */ private: const uint8_t maxCount; uint8_t initCount = 0; From 60872f936ce2c2566b388e1e40bdb24194178453 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 27 May 2020 23:43:40 +0200 Subject: [PATCH 74/94] some output improvements --- osal/FreeRTOS/CountingSemaphUsingTask.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.cpp b/osal/FreeRTOS/CountingSemaphUsingTask.cpp index c29f5258..d34c7d6a 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.cpp +++ b/osal/FreeRTOS/CountingSemaphUsingTask.cpp @@ -12,19 +12,19 @@ CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(const uint8_t maxCount, handle = TaskManagement::getCurrentTaskHandle(); if(handle == nullptr) { - sif::error << "Could not retrieve task handle. Please ensure the" - "constructor was called inside a task." << std::endl; + sif::error << "CountingSemaphoreUsingTask: Could not retrieve task " + "handle. Please ensure the constructor was called inside a " + "task." << std::endl; } uint32_t oldNotificationValue; xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, &oldNotificationValue); if(oldNotificationValue != 0) { - sif::warning << "Semaphore initiated but current notification value" - " is not 0. Please ensure the notification value is not used" - "for other purposes!" << std::endl; + sif::warning << "CountinSemaphoreUsingTask: Semaphore initiated but " + "current notification value is not 0. Please ensure the " + "notification value is not used for other purposes!" << std::endl; } - while(currentCount != initCount) { xTaskNotifyGive(handle); currentCount++; From 8676fcd9a929b619b65c1598434c75261fdb74b1 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 00:47:54 +0200 Subject: [PATCH 75/94] yay, linux bin semaph finished --- osal/linux/BinarySemaphore.cpp | 127 ++++++++++++++++++++++++++++++++ osal/linux/BinarySemaphore.h | 68 +++++++++++++++++ osal/linux/MessageQueue.cpp | 2 +- osal/linux/Mutex.h | 4 +- osal/linux/SemaphoreFactory.cpp | 6 +- tasks/SemaphoreFactory.h | 2 +- tasks/SemaphoreIF.h | 2 +- 7 files changed, 203 insertions(+), 8 deletions(-) create mode 100644 osal/linux/BinarySemaphore.cpp create mode 100644 osal/linux/BinarySemaphore.h diff --git a/osal/linux/BinarySemaphore.cpp b/osal/linux/BinarySemaphore.cpp new file mode 100644 index 00000000..ed1045e0 --- /dev/null +++ b/osal/linux/BinarySemaphore.cpp @@ -0,0 +1,127 @@ +#include +#include + +extern "C" { +#include +#include +} + +BinarySemaphore::BinarySemaphore() { + // Using unnamed semaphores for now + initSemaphore(); +} + +BinarySemaphore::~BinarySemaphore() { + sem_destroy(&handle); +} + +BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { + initSemaphore(); +} + +BinarySemaphore& BinarySemaphore::operator =( + BinarySemaphore&& s) { + initSemaphore(); + return * this; +} + +ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { + int result = 0; + if(timeoutMs == SemaphoreIF::NO_TIMEOUT) { + result = sem_trywait(&handle); + } + if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { + result = sem_wait(&handle); + } + else if(timeoutMs > SemaphoreIF::NO_TIMEOUT){ + timespec timeOut; + clock_gettime(CLOCK_REALTIME, &timeOut); + uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec; + nseconds += timeoutMs * 1000000; + timeOut.tv_sec = nseconds / 1000000000; + timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000; + result = sem_timedwait(&handle, &timeOut); + if(result != 0 and errno == EINVAL) { + sif::debug << "BinarySemaphore::acquire: Invalid time value possible" + << std::endl; + } + } + if(result == 0) { + return HasReturnvaluesIF::RETURN_OK; + } + + switch(result) { + case(EAGAIN): + // Operation could not be performed without blocking (for sem_trywait) + case(ETIMEDOUT): + // Semaphore is 0 + return SemaphoreIF::SEMAPHORE_TIMEOUT; + case(EINVAL): + // Semaphore invalid + return SemaphoreIF::SEMAPHORE_INVALID; + case(EINTR): + // Call was interrupted by signal handler + sif::debug << "BinarySemaphore::acquire: Signal handler interrupted" + << std::endl; + /* No break */ + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t BinarySemaphore::release() { + return release(&this->handle); +} + +ReturnValue_t BinarySemaphore::release(sem_t *handle) { + int result = sem_post(handle); + if(result == 0) { + return HasReturnvaluesIF::RETURN_OK; + } + + switch(errno) { + case(EINVAL): + // Semaphore invalid + return SemaphoreIF::SEMAPHORE_INVALID; + case(EOVERFLOW): + // SEM_MAX_VALUE overflow. This should never happen + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +uint8_t BinarySemaphore::getSemaphoreCounter() const { + // And another ugly cast :-D + return getSemaphoreCounter(const_cast(&this->handle)); +} + +uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) { + int value = 0; + int result = sem_getvalue(handle, &value); + if (result == 0) { + return value; + } + else if(result != 0 and errno == EINVAL) { + sif::debug << "BInarySemaphore::getSemaphoreCounter: Invalid" + " Semaphore." << std::endl; + return 0; + } + else { + // This should never happen. + return 0; + } +} + +void BinarySemaphore::initSemaphore() { + auto result = sem_init(&handle, true, 1); + if(result == -1) { + switch(errno) { + case(EINVAL): + // Value excees SEM_VALUE_MAX + case(ENOSYS): + // System does not support process-shared semaphores + sif::error << "BinarySemaphore: Init failed with" << strerror(errno) + << std::endl; + } + } +} diff --git a/osal/linux/BinarySemaphore.h b/osal/linux/BinarySemaphore.h new file mode 100644 index 00000000..d18b3eaa --- /dev/null +++ b/osal/linux/BinarySemaphore.h @@ -0,0 +1,68 @@ +#ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ +#define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ + +#include +#include + +extern "C" { +#include +} + +/** + * @brief OS Tool to achieve synchronization of between tasks or between + * task and ISR. The default semaphore implementation creates a + * binary semaphore, which can only be taken once. + * @details + * See: http://www.man7.org/linux/man-pages/man7/sem_overview.7.html + * @author R. Mueller + * @ingroup osal + */ +class BinarySemaphore: public SemaphoreIF, + public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; + + //! @brief Default ctor + BinarySemaphore(); + //! @brief Copy ctor, deleted explicitely. + BinarySemaphore(const BinarySemaphore&) = delete; + //! @brief Copy assignment, deleted explicitely. + BinarySemaphore& operator=(const BinarySemaphore&) = delete; + //! @brief Move ctor + BinarySemaphore (BinarySemaphore &&); + //! @brief Move assignment + BinarySemaphore & operator=(BinarySemaphore &&); + //! @brief Destructor + virtual ~BinarySemaphore(); + + void initSemaphore(); + + uint8_t getSemaphoreCounter() const override; + static uint8_t getSemaphoreCounter(sem_t* handle); + /** + * Take the binary semaphore. + * If the semaphore has already been taken, the task will be blocked + * for a maximum of #timeoutMs or until the semaphore is given back, + * for example by an ISR or another task. + * @param timeoutMs + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout + */ + ReturnValue_t acquire(uint32_t timeoutMs = + SemaphoreIF::NO_TIMEOUT) override; + + /** + * Release the binary semaphore. + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is + * already available. + */ + ReturnValue_t release() override; + + static ReturnValue_t release(sem_t* handle); + +protected: + sem_t handle; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ diff --git a/osal/linux/MessageQueue.cpp b/osal/linux/MessageQueue.cpp index 96d9fb4d..48ba29e8 100644 --- a/osal/linux/MessageQueue.cpp +++ b/osal/linux/MessageQueue.cpp @@ -7,7 +7,7 @@ #include -MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize) : +MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): id(0), lastPartner(0), defaultDestination(NO_QUEUE) { //debug << "MessageQueue::MessageQueue: Creating a queue" << std::endl; mq_attr attributes; diff --git a/osal/linux/Mutex.h b/osal/linux/Mutex.h index 872ac3ac..607337ae 100644 --- a/osal/linux/Mutex.h +++ b/osal/linux/Mutex.h @@ -1,5 +1,5 @@ -#ifndef OS_RTEMS_MUTEX_H_ -#define OS_RTEMS_MUTEX_H_ +#ifndef OS_LINUX_MUTEX_H_ +#define OS_LINUX_MUTEX_H_ #include diff --git a/osal/linux/SemaphoreFactory.cpp b/osal/linux/SemaphoreFactory.cpp index b1100e75..db4bebb3 100644 --- a/osal/linux/SemaphoreFactory.cpp +++ b/osal/linux/SemaphoreFactory.cpp @@ -20,18 +20,18 @@ SemaphoreFactory* SemaphoreFactory::instance() { return SemaphoreFactory::factoryInstance; } -SemaphoreIF* SemaphoreFactory::createBinarySemaphore() { +SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t arguments) { sif::error << "Semaphore not implemented for Linux yet" << std::endl; return nullptr; } SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t count, - uint8_t initCount) { + uint8_t initCount, uint32_t arguments) { sif::error << "Counting Semaphore not implemented for " "Linux yet" << std::endl; return nullptr; } -void SemaphoreFactory::deleteMutex(SemaphoreIF* semaphore) { +void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { delete semaphore; } diff --git a/tasks/SemaphoreFactory.h b/tasks/SemaphoreFactory.h index 3e21be36..7f8edaf1 100644 --- a/tasks/SemaphoreFactory.h +++ b/tasks/SemaphoreFactory.h @@ -36,7 +36,7 @@ public: SemaphoreIF* createCountingSemaphore(const uint8_t maxCount, uint8_t initCount, uint32_t arguments = 0); - void deleteSemaphore(SemaphoreIF* mutex); + void deleteSemaphore(SemaphoreIF* semaphore); private: /** diff --git a/tasks/SemaphoreIF.h b/tasks/SemaphoreIF.h index 044e03a8..a7c5a97b 100644 --- a/tasks/SemaphoreIF.h +++ b/tasks/SemaphoreIF.h @@ -30,7 +30,7 @@ public: static constexpr ReturnValue_t SEMAPHORE_TIMEOUT = MAKE_RETURN_CODE(1); //! The current semaphore can not be given, because it is not owned static constexpr ReturnValue_t SEMAPHORE_NOT_OWNED = MAKE_RETURN_CODE(2); - static constexpr ReturnValue_t SEMAPHORE_NULLPOINTER = MAKE_RETURN_CODE(3); + static constexpr ReturnValue_t SEMAPHORE_INVALID = MAKE_RETURN_CODE(3); /** * Generic call to acquire a semaphore. From 56498e5bc12076330e8f1b74ce7955b16005d0aa Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 00:50:44 +0200 Subject: [PATCH 76/94] linux bin semaph unlocked --- osal/linux/SemaphoreFactory.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osal/linux/SemaphoreFactory.cpp b/osal/linux/SemaphoreFactory.cpp index db4bebb3..8d29ffe3 100644 --- a/osal/linux/SemaphoreFactory.cpp +++ b/osal/linux/SemaphoreFactory.cpp @@ -1,4 +1,5 @@ #include +#include #include const uint32_t SemaphoreIF::NO_TIMEOUT = 0; @@ -21,8 +22,7 @@ SemaphoreFactory* SemaphoreFactory::instance() { } SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t arguments) { - sif::error << "Semaphore not implemented for Linux yet" << std::endl; - return nullptr; + return new BinarySemaphore(); } SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t count, From 671f298935a640e33274e1a5fd52339e790068b6 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 01:41:16 +0200 Subject: [PATCH 77/94] implemented counting semaph for linux --- osal/FreeRTOS/CountingSemaphore.cpp | 10 ++++++ osal/FreeRTOS/CountingSemaphore.h | 1 + osal/linux/BinarySemaphore.cpp | 43 +++++++++++++++++------ osal/linux/BinarySemaphore.h | 23 +++++++++--- osal/linux/CountingSemaphore.cpp | 54 +++++++++++++++++++++++++++++ osal/linux/CountingSemaphore.h | 37 ++++++++++++++++++++ osal/linux/SemaphoreFactory.cpp | 7 ++-- 7 files changed, 155 insertions(+), 20 deletions(-) create mode 100644 osal/linux/CountingSemaphore.cpp create mode 100644 osal/linux/CountingSemaphore.h diff --git a/osal/FreeRTOS/CountingSemaphore.cpp b/osal/FreeRTOS/CountingSemaphore.cpp index a23f32a0..c838f3e2 100644 --- a/osal/FreeRTOS/CountingSemaphore.cpp +++ b/osal/FreeRTOS/CountingSemaphore.cpp @@ -10,6 +10,12 @@ extern "C" { // free FreeRTOSConfig.h file. CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): maxCount(maxCount), initCount(initCount) { + if(initCount > maxCount) { + sif::error << "CountingSemaphoreUsingTask: Max count bigger than " + "intial cout. Setting initial count to max count." << std::endl; + initCount = maxCount; + } + handle = xSemaphoreCreateCounting(maxCount, initCount); if(handle == nullptr) { sif::error << "CountingSemaphore: Creation failure" << std::endl; @@ -33,3 +39,7 @@ CountingSemaphore& CountingSemaphore::operator =( return * this; } + +uint8_t CountingSemaphore::getMaxCount() const { + return maxCount; +} diff --git a/osal/FreeRTOS/CountingSemaphore.h b/osal/FreeRTOS/CountingSemaphore.h index bed3c726..dca3ab0e 100644 --- a/osal/FreeRTOS/CountingSemaphore.h +++ b/osal/FreeRTOS/CountingSemaphore.h @@ -25,6 +25,7 @@ public: /* Same API as binary semaphore otherwise. acquire() can be called * until there are not semaphores left and release() can be called * until maxCount is reached. */ + uint8_t getMaxCount() const; private: const uint8_t maxCount; uint8_t initCount = 0; diff --git a/osal/linux/BinarySemaphore.cpp b/osal/linux/BinarySemaphore.cpp index ed1045e0..7c76a5c4 100644 --- a/osal/linux/BinarySemaphore.cpp +++ b/osal/linux/BinarySemaphore.cpp @@ -30,7 +30,7 @@ ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { if(timeoutMs == SemaphoreIF::NO_TIMEOUT) { result = sem_trywait(&handle); } - if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { + else if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { result = sem_wait(&handle); } else if(timeoutMs > SemaphoreIF::NO_TIMEOUT){ @@ -50,7 +50,7 @@ ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { return HasReturnvaluesIF::RETURN_OK; } - switch(result) { + switch(errno) { case(EAGAIN): // Operation could not be performed without blocking (for sem_trywait) case(ETIMEDOUT): @@ -61,8 +61,8 @@ ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { return SemaphoreIF::SEMAPHORE_INVALID; case(EINTR): // Call was interrupted by signal handler - sif::debug << "BinarySemaphore::acquire: Signal handler interrupted" - << std::endl; + sif::debug << "BinarySemaphore::acquire: Signal handler interrupted." + "Code " << strerror(errno) << std::endl; /* No break */ default: return HasReturnvaluesIF::RETURN_FAILED; @@ -70,10 +70,15 @@ ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { } ReturnValue_t BinarySemaphore::release() { - return release(&this->handle); + return BinarySemaphore::release(&this->handle); } ReturnValue_t BinarySemaphore::release(sem_t *handle) { + ReturnValue_t countResult = checkCount(handle, 1); + if(countResult != HasReturnvaluesIF::RETURN_OK) { + return countResult; + } + int result = sem_post(handle); if(result == 0) { return HasReturnvaluesIF::RETURN_OK; @@ -102,8 +107,8 @@ uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) { return value; } else if(result != 0 and errno == EINVAL) { - sif::debug << "BInarySemaphore::getSemaphoreCounter: Invalid" - " Semaphore." << std::endl; + // Could be called from interrupt, use lightweight printf + printf("BinarySemaphore::getSemaphoreCounter: Invalid semaphore\n"); return 0; } else { @@ -112,16 +117,32 @@ uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) { } } -void BinarySemaphore::initSemaphore() { - auto result = sem_init(&handle, true, 1); +void BinarySemaphore::initSemaphore(uint8_t initCount) { + auto result = sem_init(&handle, true, initCount); if(result == -1) { switch(errno) { case(EINVAL): - // Value excees SEM_VALUE_MAX + // Value exceeds SEM_VALUE_MAX case(ENOSYS): // System does not support process-shared semaphores sif::error << "BinarySemaphore: Init failed with" << strerror(errno) - << std::endl; + << std::endl; } } } + +ReturnValue_t BinarySemaphore::checkCount(sem_t* handle, uint8_t maxCount) { + int value = getSemaphoreCounter(handle); + if(value >= maxCount) { + if(maxCount == 1 and value > 1) { + // Binary Semaphore special case. + // This is a config error use lightweight printf is this is called + // from an interrupt + printf("BinarySemaphore::release: Value of binary semaphore greater" + " than 1!\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/osal/linux/BinarySemaphore.h b/osal/linux/BinarySemaphore.h index d18b3eaa..7836cd41 100644 --- a/osal/linux/BinarySemaphore.h +++ b/osal/linux/BinarySemaphore.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ -#define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ +#ifndef FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_ +#define FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_ #include #include @@ -35,10 +35,11 @@ public: //! @brief Destructor virtual ~BinarySemaphore(); - void initSemaphore(); + void initSemaphore(uint8_t initCount = 1); uint8_t getSemaphoreCounter() const override; static uint8_t getSemaphoreCounter(sem_t* handle); + /** * Take the binary semaphore. * If the semaphore has already been taken, the task will be blocked @@ -57,10 +58,22 @@ public: * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is * already available. */ - ReturnValue_t release() override; - + virtual ReturnValue_t release() override; + /** + * This static function can be used to release a semaphore by providing + * its handle. + * @param handle + * @return + */ static ReturnValue_t release(sem_t* handle); + /** Checks the validity of the semaphore count against a specified + * known maxCount + * @param handle + * @param maxCount + * @return + */ + static ReturnValue_t checkCount(sem_t* handle, uint8_t maxCount); protected: sem_t handle; }; diff --git a/osal/linux/CountingSemaphore.cpp b/osal/linux/CountingSemaphore.cpp new file mode 100644 index 00000000..dfc4d801 --- /dev/null +++ b/osal/linux/CountingSemaphore.cpp @@ -0,0 +1,54 @@ +#include +#include + +CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): + maxCount(maxCount), initCount(initCount) { + if(initCount > maxCount) { + sif::error << "CountingSemaphoreUsingTask: Max count bigger than " + "intial cout. Setting initial count to max count." << std::endl; + initCount = maxCount; + } + + initSemaphore(initCount); +} + +CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): + maxCount(other.maxCount), initCount(other.initCount) { + initSemaphore(initCount); +} + +CountingSemaphore& CountingSemaphore::operator =( + CountingSemaphore&& other) { + initSemaphore(other.initCount); + return * this; +} + +ReturnValue_t CountingSemaphore::release() { + ReturnValue_t result = checkCount(&handle, maxCount); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return CountingSemaphore::release(&this->handle); +} + +ReturnValue_t CountingSemaphore::release(sem_t* handle) { + int result = sem_post(handle); + if(result == 0) { + return HasReturnvaluesIF::RETURN_OK; + } + + switch(errno) { + case(EINVAL): + // Semaphore invalid + return SemaphoreIF::SEMAPHORE_INVALID; + case(EOVERFLOW): + // SEM_MAX_VALUE overflow. This should never happen + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +uint8_t CountingSemaphore::getMaxCount() const { + return maxCount; +} + diff --git a/osal/linux/CountingSemaphore.h b/osal/linux/CountingSemaphore.h new file mode 100644 index 00000000..ba606595 --- /dev/null +++ b/osal/linux/CountingSemaphore.h @@ -0,0 +1,37 @@ +#ifndef FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_ +#define FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_ +#include + +/** + * @brief Counting semaphores, which can be acquired more than once. + * @details + * See: https://www.freertos.org/CreateCounting.html + * API of counting semaphores is almost identical to binary semaphores, + * so we just inherit from binary semaphore and provide the respective + * constructors. + */ +class CountingSemaphore: public BinarySemaphore { +public: + CountingSemaphore(const uint8_t maxCount, uint8_t initCount); + //! @brief Copy ctor, disabled + CountingSemaphore(const CountingSemaphore&) = delete; + //! @brief Copy assignment, disabled + CountingSemaphore& operator=(const CountingSemaphore&) = delete; + //! @brief Move ctor + CountingSemaphore (CountingSemaphore &&); + //! @brief Move assignment + CountingSemaphore & operator=(CountingSemaphore &&); + + ReturnValue_t release() override; + static ReturnValue_t release(sem_t* sem); + /* Same API as binary semaphore otherwise. acquire() can be called + * until there are not semaphores left and release() can be called + * until maxCount is reached. */ + + uint8_t getMaxCount() const; +private: + const uint8_t maxCount; + uint8_t initCount = 0; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */ diff --git a/osal/linux/SemaphoreFactory.cpp b/osal/linux/SemaphoreFactory.cpp index 8d29ffe3..5aec84ea 100644 --- a/osal/linux/SemaphoreFactory.cpp +++ b/osal/linux/SemaphoreFactory.cpp @@ -1,5 +1,6 @@ #include #include +#include #include const uint32_t SemaphoreIF::NO_TIMEOUT = 0; @@ -25,11 +26,9 @@ SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t arguments) { return new BinarySemaphore(); } -SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t count, +SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount, uint8_t initCount, uint32_t arguments) { - sif::error << "Counting Semaphore not implemented for " - "Linux yet" << std::endl; - return nullptr; + return new CountingSemaphore(maxCount, initCount); } void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { From ccf79ab5b63d5870dfd8aabde90895746f9cdc08 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 01:55:20 +0200 Subject: [PATCH 78/94] output correction for linux --- osal/linux/PeriodicPosixTask.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osal/linux/PeriodicPosixTask.cpp b/osal/linux/PeriodicPosixTask.cpp index 28a0b946..f6a74901 100644 --- a/osal/linux/PeriodicPosixTask.cpp +++ b/osal/linux/PeriodicPosixTask.cpp @@ -57,9 +57,11 @@ void PeriodicPosixTask::taskFunctionality(void){ char name[20] = {0}; int status = pthread_getname_np(pthread_self(),name,sizeof(name)); if(status==0){ - sif::error << "ObjectTask: " << name << " Deadline missed." << std::endl; + sif::error << "PeriodicPosixTask " << name << ": Deadline " + "missed." << std::endl; }else{ - sif::error << "ObjectTask: X Deadline missed. " << status << std::endl; + sif::error << "PeriodicPosixTask X: Deadline missed. " << + status << std::endl; } if (this->deadlineMissedFunc != NULL) { this->deadlineMissedFunc(); From 3d2935ac6917b6d8f20c68011cd77cf9d5890686 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 02:23:14 +0200 Subject: [PATCH 79/94] linux time lib improvements stop watch other function used (more precise for linux) --- osal/linux/Clock.cpp | 17 ++++++++++++++--- timemanager/Clock.h | 18 ++++++++++-------- timemanager/Stopwatch.cpp | 14 +++++--------- timemanager/Stopwatch.h | 9 ++------- 4 files changed, 31 insertions(+), 27 deletions(-) diff --git a/osal/linux/Clock.cpp b/osal/linux/Clock.cpp index e24a4fe4..b3e5c84b 100644 --- a/osal/linux/Clock.cpp +++ b/osal/linux/Clock.cpp @@ -1,11 +1,13 @@ -#include -#include +#include #include - +extern "C" { +#include #include #include +#include #include +} //#include uint16_t Clock::leapSeconds = 0; @@ -65,6 +67,15 @@ ReturnValue_t Clock::getClock_usecs(uint64_t* time) { return HasReturnvaluesIF::RETURN_OK; } +timeval Clock::getUptime() { + timeval uptime; + auto result = getUptime(&uptime); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "Clock::getUptime: Error getting uptime" << std::endl; + } + return uptime; +} + ReturnValue_t Clock::getUptime(timeval* uptime) { //TODO This is not posix compatible and delivers only seconds precision struct sysinfo sysInfo; diff --git a/timemanager/Clock.h b/timemanager/Clock.h index 5f18de3e..fcfacbc0 100644 --- a/timemanager/Clock.h +++ b/timemanager/Clock.h @@ -2,11 +2,12 @@ #define FRAMEWORK_TIMEMANAGER_CLOCK_H_ #include -#include -#include #include #include +#include +#include + typedef uint32_t millis_t; typedef float seconds_t; @@ -22,7 +23,7 @@ public: uint32_t usecond; //!< Microseconds, 0 .. 999999 } TimeOfDay_t; - /**static Clock* TimeOfDay_t(); + /** * This method returns the number of clock ticks per second. * In RTEMS, this is typically 1000. * @return The number of ticks. @@ -34,22 +35,23 @@ public: * This system call sets the system time. * To set the time, it uses a TimeOfDay_t struct. * @param time The struct with the time settings to set. - * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned. + * @return -@c RETURN_OK on success. Otherwise, the OS failure code + * is returned. */ static ReturnValue_t setClock(const TimeOfDay_t* time); /** * This system call sets the system time. * To set the time, it uses a timeval struct. * @param time The struct with the time settings to set. - * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned. + * @return -@c RETURN_OK on success. Otherwise, the OS failure code is returned. */ static ReturnValue_t setClock(const timeval* time); /** * This system call returns the current system clock in timeval format. - * The timval format has the fields \c tv_sec with seconds and \c tv_usec with + * The timval format has the fields @c tv_sec with seconds and @c tv_usec with * microseconds since an OS-defined epoch. * @param time A pointer to a timeval struct where the current time is stored. - * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned. + * @return @c RETURN_OK on success. Otherwise, the OS failure code is returned. */ static ReturnValue_t getClock_timeval(timeval* time); @@ -57,7 +59,7 @@ public: * Get the time since boot in a timeval struct * * @param[out] time A pointer to a timeval struct where the uptime is stored. - * @return\c RETURN_OK on success. Otherwise, the OS failure code is returned. + * @return @c RETURN_OK on success. Otherwise, the OS failure code is returned. * * @deprecated, I do not think this should be able to fail, use timeval getUptime() */ diff --git a/timemanager/Stopwatch.cpp b/timemanager/Stopwatch.cpp index 1f287fb3..bc8b4149 100644 --- a/timemanager/Stopwatch.cpp +++ b/timemanager/Stopwatch.cpp @@ -1,9 +1,3 @@ -/** - * @file Stopwatch.cpp - * - * @date 08.04.2020 - */ - #include #include #include @@ -12,11 +6,11 @@ Stopwatch::Stopwatch(bool displayOnDestruction, StopwatchDisplayMode displayMode): displayOnDestruction( displayOnDestruction), displayMode(displayMode) { // Measures start time on initialization. - startTime = Clock::getUptime(); + Clock::getClock_timeval(&startTime); } void Stopwatch::start() { - startTime = Clock::getUptime(); + Clock::getClock_timeval(&startTime); } millis_t Stopwatch::stop() { @@ -57,5 +51,7 @@ StopwatchDisplayMode Stopwatch::getDisplayMode() const { } void Stopwatch::stopInternal() { - elapsedTime = Clock::getUptime() - startTime; + timeval endTime; + Clock::getClock_timeval(&endTime); + elapsedTime = endTime - startTime; } diff --git a/timemanager/Stopwatch.h b/timemanager/Stopwatch.h index f48c04ec..c57200b0 100644 --- a/timemanager/Stopwatch.h +++ b/timemanager/Stopwatch.h @@ -1,9 +1,3 @@ -/** - * @file Stopwatch.h - * - * @date 08.04.2020 - */ - #ifndef FRAMEWORK_TIMEMANAGER_STOPWATCH_H_ #define FRAMEWORK_TIMEMANAGER_STOPWATCH_H_ #include @@ -14,12 +8,13 @@ enum class StopwatchDisplayMode { }; /** - * @brief Simple Stopwatch implementation to measure elapsed time + * @brief Simple Stopwatch implementation to measure elapsed time * @details * This class can be used to measure elapsed times. It also displays elapsed * times automatically on destruction if not explicitely deactivated in the * constructor. The default time format is the elapsed time in miliseconds * as a float. + * @author R. Mueller */ class Stopwatch { public: From da403c01d0178d814896d4c26561e092c1ac2a6e Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 03:03:48 +0200 Subject: [PATCH 80/94] retval fix, unittest running again --- osal/FreeRTOS/BinSemaphUsingTask.cpp | 71 ++++++++++------------- osal/FreeRTOS/BinSemaphUsingTask.h | 9 ++- osal/FreeRTOS/BinarySemaphore.cpp | 40 ++++++------- osal/FreeRTOS/CountingSemaphUsingTask.cpp | 69 +++++++++------------- osal/FreeRTOS/CountingSemaphUsingTask.h | 17 +++++- 5 files changed, 94 insertions(+), 112 deletions(-) diff --git a/osal/FreeRTOS/BinSemaphUsingTask.cpp b/osal/FreeRTOS/BinSemaphUsingTask.cpp index 84b0b488..51a3c563 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.cpp +++ b/osal/FreeRTOS/BinSemaphUsingTask.cpp @@ -9,7 +9,6 @@ BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() { "constructor was called inside a task." << std::endl; } xTaskNotifyGive(handle); - locked = false; } BinarySemaphoreUsingTask::~BinarySemaphoreUsingTask() { @@ -32,7 +31,6 @@ ReturnValue_t BinarySemaphoreUsingTask::acquireWithTickTimeout( TickType_t timeoutTicks) { BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeoutTicks); if (returncode == pdPASS) { - locked = true; return HasReturnvaluesIF::RETURN_OK; } else { @@ -41,43 +39,14 @@ ReturnValue_t BinarySemaphoreUsingTask::acquireWithTickTimeout( } ReturnValue_t BinarySemaphoreUsingTask::release() { - if(not locked) { - return SemaphoreIF::SEMAPHORE_NOT_OWNED; - } - BaseType_t returncode = xTaskNotifyGive(handle); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } else { - // This should never happen - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -TaskHandle_t BinarySemaphoreUsingTask::getTaskHandle() { - return handle; -} - -uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter() const { - uint32_t notificationValue; - xTaskNotifyAndQuery(handle, 0, eNoAction, ¬ificationValue); - return notificationValue; -} - - -uint8_t BinarySemaphoreUsingTask::getSemaphoreCounterFromISR( - TaskHandle_t taskHandle) { - uint32_t notificationValue; - BaseType_t higherPriorityTaskWoken; - xTaskNotifyAndQueryFromISR(taskHandle, 0, eNoAction, ¬ificationValue, - &higherPriorityTaskWoken); - if(higherPriorityTaskWoken) { - TaskManagement::requestContextSwitch(CallContext::isr); - } - return notificationValue; + return release(this->handle); } ReturnValue_t BinarySemaphoreUsingTask::release( TaskHandle_t taskHandle) { + if(getSemaphoreCounter(taskHandle) == 1) { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } BaseType_t returncode = xTaskNotifyGive(taskHandle); if (returncode == pdPASS) { return HasReturnvaluesIF::RETURN_OK; @@ -88,14 +57,36 @@ ReturnValue_t BinarySemaphoreUsingTask::release( } } +TaskHandle_t BinarySemaphoreUsingTask::getTaskHandle() { + return handle; +} + +uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter() const { + return getSemaphoreCounter(this->handle); +} + +uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter( + TaskHandle_t taskHandle) { + uint32_t notificationValue; + xTaskNotifyAndQuery(taskHandle, 0, eNoAction, ¬ificationValue); + return notificationValue; +} + // Be careful with the stack size here. This is called from an ISR! ReturnValue_t BinarySemaphoreUsingTask::releaseFromISR( TaskHandle_t taskHandle, BaseType_t * higherPriorityTaskWoken) { - vTaskNotifyGiveFromISR(taskHandle, higherPriorityTaskWoken); - if(*higherPriorityTaskWoken == pdPASS) { - // Request context switch because unblocking the semaphore - // caused a high priority task unblock. - TaskManagement::requestContextSwitch(CallContext::isr); + if(getSemaphoreCounterFromISR(taskHandle) == 1) { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; } + vTaskNotifyGiveFromISR(taskHandle, higherPriorityTaskWoken); return HasReturnvaluesIF::RETURN_OK; } + +uint8_t BinarySemaphoreUsingTask::getSemaphoreCounterFromISR( + TaskHandle_t taskHandle) { + uint32_t notificationValue; + BaseType_t higherPriorityTaskWoken; + xTaskNotifyAndQueryFromISR(taskHandle, 0, eNoAction, ¬ificationValue, + &higherPriorityTaskWoken); + return notificationValue; +} diff --git a/osal/FreeRTOS/BinSemaphUsingTask.h b/osal/FreeRTOS/BinSemaphUsingTask.h index cad42783..31620880 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.h +++ b/osal/FreeRTOS/BinSemaphUsingTask.h @@ -31,6 +31,7 @@ public: SemaphoreIF::NO_TIMEOUT) override; ReturnValue_t release() override; uint8_t getSemaphoreCounter() const override; + static uint8_t getSemaphoreCounter(TaskHandle_t taskHandle); static uint8_t getSemaphoreCounterFromISR(TaskHandle_t taskHandle); /** @@ -59,8 +60,9 @@ public: /** * Wrapper function to give back semaphore from handle when called from an ISR * @param semaphore - * @param higherPriorityTaskWoken This will be set to pdPASS if a task with a higher priority - * was unblocked + * @param higherPriorityTaskWoken This will be set to pdPASS if a task with + * a higher priority was unblocked. A context switch should be requested + * from an ISR if this is the case (see TaskManagement functions) * @return - @c RETURN_OK on success * - @c RETURN_FAILED on failure */ @@ -69,9 +71,6 @@ public: protected: TaskHandle_t handle; - // This boolean is required to track whether the semaphore is locked - // or unlocked. - bool locked; }; #endif /* FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ */ diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index 7d882aff..7b695dee 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -37,7 +37,7 @@ BinarySemaphore& BinarySemaphore::operator =( ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { if(handle == nullptr) { - return SemaphoreIF::SEMAPHORE_NULLPOINTER; + return SemaphoreIF::SEMAPHORE_INVALID; } TickType_t timeout = SemaphoreIF::NO_TIMEOUT; if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { @@ -51,7 +51,7 @@ ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { ReturnValue_t BinarySemaphore::acquireWithTickTimeout(TickType_t timeoutTicks) { if(handle == nullptr) { - return SemaphoreIF::SEMAPHORE_NULLPOINTER; + return SemaphoreIF::SEMAPHORE_INVALID; } BaseType_t returncode = xSemaphoreTake(handle, timeoutTicks); @@ -64,10 +64,14 @@ ReturnValue_t BinarySemaphore::acquireWithTickTimeout(TickType_t timeoutTicks) { } ReturnValue_t BinarySemaphore::release() { - if (handle == nullptr) { - return SemaphoreIF::SEMAPHORE_NULLPOINTER; + return release(handle); +} + +ReturnValue_t BinarySemaphore::release(SemaphoreHandle_t semaphore) { + if (semaphore == nullptr) { + return SemaphoreIF::SEMAPHORE_INVALID; } - BaseType_t returncode = xSemaphoreGive(handle); + BaseType_t returncode = xSemaphoreGive(semaphore); if (returncode == pdPASS) { return HasReturnvaluesIF::RETURN_OK; } @@ -83,33 +87,23 @@ uint8_t BinarySemaphore::getSemaphoreCounter() const { SemaphoreHandle_t BinarySemaphore::getSemaphore() { return handle; } - -ReturnValue_t BinarySemaphore::release(SemaphoreHandle_t semaphore) { - if (semaphore == nullptr) { - return SemaphoreIF::SEMAPHORE_NULLPOINTER; - } - BaseType_t returncode = xSemaphoreGive(semaphore); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } -} + // Be careful with the stack size here. This is called from an ISR! ReturnValue_t BinarySemaphore::releaseFromISR( SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken) { if (semaphore == nullptr) { - return SemaphoreIF::SEMAPHORE_NULLPOINTER; + return SemaphoreIF::SEMAPHORE_INVALID; } BaseType_t returncode = xSemaphoreGiveFromISR(semaphore, higherPriorityTaskWoken); + // This should propably be called at the end of the (calling) ISR + //if(*higherPriorityTaskWoken == pdPASS) { + // Request context switch because unblocking the semaphore + // caused a high priority task unblock. + //TaskManagement::requestContextSwitch(CallContext::isr); + //} if (returncode == pdPASS) { - if(*higherPriorityTaskWoken == pdPASS) { - // Request context switch because unblocking the semaphore - // caused a high priority task unblock. - TaskManagement::requestContextSwitch(CallContext::isr); - } return HasReturnvaluesIF::RETURN_OK; } else { diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.cpp b/osal/FreeRTOS/CountingSemaphUsingTask.cpp index d34c7d6a..d0f63f3f 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.cpp +++ b/osal/FreeRTOS/CountingSemaphUsingTask.cpp @@ -25,16 +25,15 @@ CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(const uint8_t maxCount, "current notification value is not 0. Please ensure the " "notification value is not used for other purposes!" << std::endl; } - while(currentCount != initCount) { + for(int i = 0; i < initCount; i++) { xTaskNotifyGive(handle); - currentCount++; } } CountingSemaphoreUsingTask::~CountingSemaphoreUsingTask() { // Clear notification value on destruction. // If this is not desired, don't call the destructor - // (or implement a boolea which disables the reset) + // (or implement a boolean which disables the reset) xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr); } @@ -55,7 +54,6 @@ ReturnValue_t CountingSemaphoreUsingTask::acquireWithTickTimeout( // Decrement notfication value without resetting it. BaseType_t oldCount = ulTaskNotifyTake(pdFALSE, timeoutTicks); if (getSemaphoreCounter() == oldCount - 1) { - currentCount --; return HasReturnvaluesIF::RETURN_OK; } else { @@ -64,41 +62,10 @@ ReturnValue_t CountingSemaphoreUsingTask::acquireWithTickTimeout( } ReturnValue_t CountingSemaphoreUsingTask::release() { - if(currentCount == maxCount) { + if(getSemaphoreCounter() == maxCount) { return SemaphoreIF::SEMAPHORE_NOT_OWNED; } - BaseType_t returncode = xTaskNotifyGive(handle); - if (returncode == pdPASS) { - currentCount++; - return HasReturnvaluesIF::RETURN_OK; - } - else { - // This should never happen - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -uint8_t CountingSemaphoreUsingTask::getSemaphoreCounter() const { - uint32_t notificationValue = 0; - xTaskNotifyAndQuery(handle, 0, eNoAction, ¬ificationValue); - return notificationValue; -} - -TaskHandle_t CountingSemaphoreUsingTask::getTaskHandle() { - return handle; -} - - -uint8_t CountingSemaphoreUsingTask::getSemaphoreCounterFromISR( - TaskHandle_t task) { - uint32_t notificationValue; - BaseType_t higherPriorityTaskWoken = 0; - xTaskNotifyAndQueryFromISR(task, 0, eNoAction, ¬ificationValue, - &higherPriorityTaskWoken); - if(higherPriorityTaskWoken == pdTRUE) { - TaskManagement::requestContextSwitch(CallContext::isr); - } - return notificationValue; + return release(handle); } ReturnValue_t CountingSemaphoreUsingTask::release( @@ -113,13 +80,31 @@ ReturnValue_t CountingSemaphoreUsingTask::release( } } + +uint8_t CountingSemaphoreUsingTask::getSemaphoreCounter() const { + uint32_t notificationValue = 0; + xTaskNotifyAndQuery(handle, 0, eNoAction, ¬ificationValue); + return notificationValue; +} + +TaskHandle_t CountingSemaphoreUsingTask::getTaskHandle() { + return handle; +} + ReturnValue_t CountingSemaphoreUsingTask::releaseFromISR( TaskHandle_t taskToNotify, BaseType_t* higherPriorityTaskWoken) { vTaskNotifyGiveFromISR(taskToNotify, higherPriorityTaskWoken); - if(*higherPriorityTaskWoken == pdPASS) { - // Request context switch because unblocking the semaphore - // caused a high priority task unblock. - TaskManagement::requestContextSwitch(CallContext::isr); - } return HasReturnvaluesIF::RETURN_OK; } + +uint8_t CountingSemaphoreUsingTask::getSemaphoreCounterFromISR( + TaskHandle_t task, BaseType_t* higherPriorityTaskWoken) { + uint32_t notificationValue; + xTaskNotifyAndQueryFromISR(task, 0, eNoAction, ¬ificationValue, + higherPriorityTaskWoken); + return notificationValue; +} + +uint8_t CountingSemaphoreUsingTask::getMaxCount() const { + return maxCount; +} diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.h b/osal/FreeRTOS/CountingSemaphUsingTask.h index 73d3f987..797e864b 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.h +++ b/osal/FreeRTOS/CountingSemaphUsingTask.h @@ -43,7 +43,16 @@ public: ReturnValue_t release() override; uint8_t getSemaphoreCounter() const override; - static uint8_t getSemaphoreCounterFromISR(TaskHandle_t task); + /** + * Get the semaphore counter from an ISR. + * @param task + * @param higherPriorityTaskWoken This will be set to pdPASS if a task with + * a higher priority was unblocked. A context switch should be requested + * from an ISR if this is the case (see TaskManagement functions) + * @return + */ + static uint8_t getSemaphoreCounterFromISR(TaskHandle_t task, + BaseType_t* higherPriorityTaskWoken); /** * Acquire with a timeout value in ticks @@ -71,6 +80,9 @@ public: /** * Release seamphore of a task from an ISR. * @param taskToNotify + * @param higherPriorityTaskWoken This will be set to pdPASS if a task with + * a higher priority was unblocked. A context switch should be requested + * from an ISR if this is the case (see TaskManagement functions) * @return -@c RETURN_OK on success * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are * already available. @@ -78,10 +90,11 @@ public: static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify, BaseType_t* higherPriorityTaskWoken); + uint8_t getMaxCount() const; + private: TaskHandle_t handle; const uint8_t maxCount; - uint8_t currentCount = 0; }; #endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ */ From 78ae109a08ec58c17b1b966944992da0b74da011 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 13:02:13 +0200 Subject: [PATCH 81/94] removed context switch request (shall be done at end of ISR, so must be performed by caller) --- osal/FreeRTOS/BinSemaphUsingTask.cpp | 9 ++++----- osal/FreeRTOS/BinSemaphUsingTask.h | 3 ++- osal/FreeRTOS/BinarySemaphore.cpp | 9 --------- osal/FreeRTOS/BinarySemaphore.h | 5 +++-- osal/FreeRTOS/MessageQueue.cpp | 2 +- osal/FreeRTOS/MessageQueue.h | 4 ++-- osal/FreeRTOS/TaskManagement.cpp | 4 ++-- osal/FreeRTOS/TaskManagement.h | 6 +++--- 8 files changed, 17 insertions(+), 25 deletions(-) diff --git a/osal/FreeRTOS/BinSemaphUsingTask.cpp b/osal/FreeRTOS/BinSemaphUsingTask.cpp index 51a3c563..8f5fd4d8 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.cpp +++ b/osal/FreeRTOS/BinSemaphUsingTask.cpp @@ -75,7 +75,7 @@ uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter( // Be careful with the stack size here. This is called from an ISR! ReturnValue_t BinarySemaphoreUsingTask::releaseFromISR( TaskHandle_t taskHandle, BaseType_t * higherPriorityTaskWoken) { - if(getSemaphoreCounterFromISR(taskHandle) == 1) { + if(getSemaphoreCounterFromISR(taskHandle, higherPriorityTaskWoken) == 1) { return SemaphoreIF::SEMAPHORE_NOT_OWNED; } vTaskNotifyGiveFromISR(taskHandle, higherPriorityTaskWoken); @@ -83,10 +83,9 @@ ReturnValue_t BinarySemaphoreUsingTask::releaseFromISR( } uint8_t BinarySemaphoreUsingTask::getSemaphoreCounterFromISR( - TaskHandle_t taskHandle) { - uint32_t notificationValue; - BaseType_t higherPriorityTaskWoken; + TaskHandle_t taskHandle, BaseType_t* higherPriorityTaskWoken) { + uint32_t notificationValue = 0; xTaskNotifyAndQueryFromISR(taskHandle, 0, eNoAction, ¬ificationValue, - &higherPriorityTaskWoken); + higherPriorityTaskWoken); return notificationValue; } diff --git a/osal/FreeRTOS/BinSemaphUsingTask.h b/osal/FreeRTOS/BinSemaphUsingTask.h index 31620880..e6cb2a07 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.h +++ b/osal/FreeRTOS/BinSemaphUsingTask.h @@ -32,7 +32,8 @@ public: ReturnValue_t release() override; uint8_t getSemaphoreCounter() const override; static uint8_t getSemaphoreCounter(TaskHandle_t taskHandle); - static uint8_t getSemaphoreCounterFromISR(TaskHandle_t taskHandle); + static uint8_t getSemaphoreCounterFromISR(TaskHandle_t taskHandle, + BaseType_t* higherPriorityTaskWoken); /** * Same as acquire() with timeout in FreeRTOS ticks. diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index 7b695dee..b6687bb7 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -36,9 +36,6 @@ BinarySemaphore& BinarySemaphore::operator =( } ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { - if(handle == nullptr) { - return SemaphoreIF::SEMAPHORE_INVALID; - } TickType_t timeout = SemaphoreIF::NO_TIMEOUT; if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { timeout = SemaphoreIF::MAX_TIMEOUT; @@ -97,12 +94,6 @@ ReturnValue_t BinarySemaphore::releaseFromISR( } BaseType_t returncode = xSemaphoreGiveFromISR(semaphore, higherPriorityTaskWoken); - // This should propably be called at the end of the (calling) ISR - //if(*higherPriorityTaskWoken == pdPASS) { - // Request context switch because unblocking the semaphore - // caused a high priority task unblock. - //TaskManagement::requestContextSwitch(CallContext::isr); - //} if (returncode == pdPASS) { return HasReturnvaluesIF::RETURN_OK; } diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index f3839151..de6092af 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -92,8 +92,9 @@ public: /** * Wrapper function to give back semaphore from handle when called from an ISR * @param semaphore - * @param higherPriorityTaskWoken This will be set to pdPASS if a task with a higher priority - * was unblocked + * @param higherPriorityTaskWoken This will be set to pdPASS if a task with + * a higher priority was unblocked. A context switch from an ISR should + * then be requested (see TaskManagement functions) * @return -@c RETURN_OK on success * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is * already available. diff --git a/osal/FreeRTOS/MessageQueue.cpp b/osal/FreeRTOS/MessageQueue.cpp index 9e4b581b..b56a6252 100644 --- a/osal/FreeRTOS/MessageQueue.cpp +++ b/osal/FreeRTOS/MessageQueue.cpp @@ -124,7 +124,7 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, bool ignoreFault, CallContext callContext) { message->setSender(sentFrom); BaseType_t result; - if(callContext == CallContext::task) { + if(callContext == CallContext::TASK) { result = xQueueSendToBack(reinterpret_cast(sendTo), static_cast(message->getBuffer()), 0); } diff --git a/osal/FreeRTOS/MessageQueue.h b/osal/FreeRTOS/MessageQueue.h index 988733f6..8daab8f6 100644 --- a/osal/FreeRTOS/MessageQueue.h +++ b/osal/FreeRTOS/MessageQueue.h @@ -199,7 +199,7 @@ protected: */ static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, - bool ignoreFault=false, CallContext callContext = CallContext::task); + bool ignoreFault=false, CallContext callContext = CallContext::TASK); static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); @@ -209,7 +209,7 @@ private: MessageQueueId_t defaultDestination = 0; MessageQueueId_t lastPartner = 0; //!< Stores the current system context - CallContext callContext = CallContext::task; + CallContext callContext = CallContext::TASK; }; #endif /* MESSAGEQUEUE_H_ */ diff --git a/osal/FreeRTOS/TaskManagement.cpp b/osal/FreeRTOS/TaskManagement.cpp index 4529b371..7871ab2e 100644 --- a/osal/FreeRTOS/TaskManagement.cpp +++ b/osal/FreeRTOS/TaskManagement.cpp @@ -5,8 +5,8 @@ void TaskManagement::requestContextSwitchFromTask() { } void TaskManagement::requestContextSwitch( - CallContext callContext = CallContext::task) { - if(callContext == CallContext::isr) { + CallContext callContext = CallContext::TASK) { + if(callContext == CallContext::ISR) { // This function depends on the partmacro.h definition for the specific device requestContextSwitchFromISR(); } else { diff --git a/osal/FreeRTOS/TaskManagement.h b/osal/FreeRTOS/TaskManagement.h index b9874db0..39c24377 100644 --- a/osal/FreeRTOS/TaskManagement.h +++ b/osal/FreeRTOS/TaskManagement.h @@ -21,9 +21,9 @@ extern "C" void requestContextSwitchFromISR(); * has different functions for handling semaphores and messages from within * an ISR and task. */ -enum CallContext { - task = 0x00,//!< task_context - isr = 0xFF //!< isr_context +enum class CallContext { + TASK = 0x00,//!< task_context + ISR = 0xFF //!< isr_context }; From 5169c09fd8d56eb041011da9062bb325578a313e Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 13:07:35 +0200 Subject: [PATCH 82/94] improved includes --- osal/FreeRTOS/Clock.cpp | 9 +++++---- osal/FreeRTOS/Timekeeper.cpp | 9 +-------- osal/FreeRTOS/Timekeeper.h | 3 ++- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/osal/FreeRTOS/Clock.cpp b/osal/FreeRTOS/Clock.cpp index 5e597f25..d1c9f97b 100644 --- a/osal/FreeRTOS/Clock.cpp +++ b/osal/FreeRTOS/Clock.cpp @@ -1,13 +1,14 @@ #include #include -#include -#include "Timekeeper.h" +#include extern "C" { -#include -#include +#include +#include } +#include +#include //TODO sanitize input? //TODO much of this code can be reused for tick-only systems diff --git a/osal/FreeRTOS/Timekeeper.cpp b/osal/FreeRTOS/Timekeeper.cpp index 949e1df3..9fd4af62 100644 --- a/osal/FreeRTOS/Timekeeper.cpp +++ b/osal/FreeRTOS/Timekeeper.cpp @@ -1,13 +1,6 @@ -/** - * @file Timekeeper.cpp - * @date - */ - #include -extern "C" { -#include -} +#include "FreeRTOSConfig.h" Timekeeper * Timekeeper::myinstance = nullptr; diff --git a/osal/FreeRTOS/Timekeeper.h b/osal/FreeRTOS/Timekeeper.h index 05f0f701..8709e362 100644 --- a/osal/FreeRTOS/Timekeeper.h +++ b/osal/FreeRTOS/Timekeeper.h @@ -3,7 +3,8 @@ #include extern "C" { -#include +#include +#include } From e7ae35c6592fb101ebe2fd44517a8cfc62b1096d Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 13:09:47 +0200 Subject: [PATCH 83/94] improved structure a bit --- osal/FreeRTOS/Timekeeper.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osal/FreeRTOS/Timekeeper.cpp b/osal/FreeRTOS/Timekeeper.cpp index 9fd4af62..643b2747 100644 --- a/osal/FreeRTOS/Timekeeper.cpp +++ b/osal/FreeRTOS/Timekeeper.cpp @@ -4,7 +4,9 @@ Timekeeper * Timekeeper::myinstance = nullptr; -Timekeeper::Timekeeper() : offset( { 0, 0 }) {} +Timekeeper::Timekeeper() : offset( { 0, 0 } ) {} + +Timekeeper::~Timekeeper() {} const timeval& Timekeeper::getOffset() const { return offset; @@ -21,8 +23,6 @@ void Timekeeper::setOffset(const timeval& offset) { this->offset = offset; } -Timekeeper::~Timekeeper() {} - timeval Timekeeper::ticksToTimeval(TickType_t ticks) { timeval uptime; uptime.tv_sec = ticks / configTICK_RATE_HZ; From d5352a9b87a604cd8535963d2a7fcc8176b2182b Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 13:15:37 +0200 Subject: [PATCH 84/94] actually extern "C" is not needed it is included by freeRTOS --- osal/FreeRTOS/Clock.cpp | 6 ++---- osal/FreeRTOS/Timekeeper.h | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/osal/FreeRTOS/Clock.cpp b/osal/FreeRTOS/Clock.cpp index d1c9f97b..dce20265 100644 --- a/osal/FreeRTOS/Clock.cpp +++ b/osal/FreeRTOS/Clock.cpp @@ -2,10 +2,8 @@ #include #include -extern "C" { #include #include -} #include #include @@ -14,7 +12,7 @@ extern "C" { //TODO much of this code can be reused for tick-only systems uint16_t Clock::leapSeconds = 0; -MutexIF* Clock::timeMutex = NULL; +MutexIF* Clock::timeMutex = nullptr; uint32_t Clock::getTicksPerSecond(void) { return 1000; @@ -131,7 +129,7 @@ ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { //SHOULDDO: works not for dates in the past (might have less leap seconds) - if (timeMutex == NULL) { + if (timeMutex == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } diff --git a/osal/FreeRTOS/Timekeeper.h b/osal/FreeRTOS/Timekeeper.h index 8709e362..7d3ca22b 100644 --- a/osal/FreeRTOS/Timekeeper.h +++ b/osal/FreeRTOS/Timekeeper.h @@ -2,10 +2,9 @@ #define FRAMEWORK_OSAL_FREERTOS_TIMEKEEPER_H_ #include -extern "C" { + #include #include -} /** From 6a3dc94108304d9cf0cdde1cc82ecc6dc62390d8 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 13:18:27 +0200 Subject: [PATCH 85/94] removed extern "C" for freertos includes --- osal/FreeRTOS/BinSemaphUsingTask.h | 2 -- osal/FreeRTOS/BinarySemaphore.h | 2 -- osal/FreeRTOS/CountingSemaphore.cpp | 2 -- osal/FreeRTOS/MessageQueue.cpp | 2 +- osal/FreeRTOS/MessageQueue.h | 7 ------- osal/FreeRTOS/Mutex.cpp | 2 +- osal/FreeRTOS/Mutex.h | 3 --- 7 files changed, 2 insertions(+), 18 deletions(-) diff --git a/osal/FreeRTOS/BinSemaphUsingTask.h b/osal/FreeRTOS/BinSemaphUsingTask.h index e6cb2a07..48c1cd12 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.h +++ b/osal/FreeRTOS/BinSemaphUsingTask.h @@ -4,10 +4,8 @@ #include #include -extern "C" { #include #include -} /** * @brief Binary Semaphore implementation using the task notification value. diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index de6092af..0938dee6 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -4,10 +4,8 @@ #include #include -extern "C" { #include #include -} /** * @brief OS Tool to achieve synchronization of between tasks or between diff --git a/osal/FreeRTOS/CountingSemaphore.cpp b/osal/FreeRTOS/CountingSemaphore.cpp index c838f3e2..957f6a31 100644 --- a/osal/FreeRTOS/CountingSemaphore.cpp +++ b/osal/FreeRTOS/CountingSemaphore.cpp @@ -2,9 +2,7 @@ #include #include -extern "C" { #include -} // Make sure #define configUSE_COUNTING_SEMAPHORES 1 is set in // free FreeRTOSConfig.h file. diff --git a/osal/FreeRTOS/MessageQueue.cpp b/osal/FreeRTOS/MessageQueue.cpp index b56a6252..0a579296 100644 --- a/osal/FreeRTOS/MessageQueue.cpp +++ b/osal/FreeRTOS/MessageQueue.cpp @@ -1,4 +1,4 @@ -#include "MessageQueue.h" +#include #include diff --git a/osal/FreeRTOS/MessageQueue.h b/osal/FreeRTOS/MessageQueue.h index 8daab8f6..81b4c186 100644 --- a/osal/FreeRTOS/MessageQueue.h +++ b/osal/FreeRTOS/MessageQueue.h @@ -6,11 +6,8 @@ #include #include -extern "C" { #include #include -} - // 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 @@ -164,11 +161,7 @@ public: MessageQueueId_t getId() const; /** -<<<<<<< HEAD - * \brief This method is a simple setter for the default destination. -======= * @brief This method is a simple setter for the default destination. ->>>>>>> mueller_BinSempahInterface */ void setDefaultDestination(MessageQueueId_t defaultDestination); /** diff --git a/osal/FreeRTOS/Mutex.cpp b/osal/FreeRTOS/Mutex.cpp index 25513a81..e304d60e 100644 --- a/osal/FreeRTOS/Mutex.cpp +++ b/osal/FreeRTOS/Mutex.cpp @@ -1,4 +1,4 @@ -#include "Mutex.h" +#include #include diff --git a/osal/FreeRTOS/Mutex.h b/osal/FreeRTOS/Mutex.h index ef93fd34..e04cd20d 100644 --- a/osal/FreeRTOS/Mutex.h +++ b/osal/FreeRTOS/Mutex.h @@ -3,11 +3,8 @@ #include -extern "C" { #include #include -} - /** * @brief OS component to implement MUTual EXclusion From f14bacba32e97c7d74e55405d59b9230ec4e362c Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 14:15:45 +0200 Subject: [PATCH 86/94] using nullptr now added new distinction between blocking (MAX_TIMEOUT) and polling (NO_TIMEOUT) --- ipc/MutexIF.h | 2 +- osal/FreeRTOS/Mutex.cpp | 18 +++++++++++------- osal/FreeRTOS/Mutex.h | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/ipc/MutexIF.h b/ipc/MutexIF.h index a4aff1cd..dcb1cf33 100644 --- a/ipc/MutexIF.h +++ b/ipc/MutexIF.h @@ -13,7 +13,7 @@ class MutexIF { public: static const uint32_t NO_TIMEOUT; //!< Needs to be defined in implementation. - + static const uint32_t MAX_TIMEOUT; static const uint8_t INTERFACE_ID = CLASS_ID::MUTEX_IF; /** * The system lacked the necessary resources (other than memory) to initialize another mutex. diff --git a/osal/FreeRTOS/Mutex.cpp b/osal/FreeRTOS/Mutex.cpp index e304d60e..cc2f865f 100644 --- a/osal/FreeRTOS/Mutex.cpp +++ b/osal/FreeRTOS/Mutex.cpp @@ -3,27 +3,31 @@ #include const uint32_t MutexIF::NO_TIMEOUT = 0; +const uint32_t MutexIF::MAX_TIMEOUT = portMAX_DELAY; Mutex::Mutex() { handle = xSemaphoreCreateMutex(); - if(handle == NULL) { - sif::error << "Mutex creation failure" << std::endl; + if(handle == nullptr) { + sif::error << "Mutex: Creation failure" << std::endl; } } Mutex::~Mutex() { - if (handle != 0) { + if (handle != nullptr) { vSemaphoreDelete(handle); } } ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) { - if (handle == 0) { + if (handle == nullptr) { return MutexIF::MUTEX_NOT_FOUND; } - TickType_t timeout = portMAX_DELAY; - if (timeoutMs != NO_TIMEOUT) { + TickType_t timeout = MutexIF::NO_TIMEOUT; + if(timeoutMs == MutexIF::MAX_TIMEOUT) { + timeout = MutexIF::MAX_TIMEOUT; + } + else if(timeoutMs > MutexIF::NO_TIMEOUT){ timeout = pdMS_TO_TICKS(timeoutMs); } @@ -36,7 +40,7 @@ ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) { } ReturnValue_t Mutex::unlockMutex() { - if (handle == 0) { + if (handle == nullptr) { return MutexIF::MUTEX_NOT_FOUND; } BaseType_t returncode = xSemaphoreGive(handle); diff --git a/osal/FreeRTOS/Mutex.h b/osal/FreeRTOS/Mutex.h index e04cd20d..90e82467 100644 --- a/osal/FreeRTOS/Mutex.h +++ b/osal/FreeRTOS/Mutex.h @@ -18,7 +18,7 @@ class Mutex : public MutexIF { public: Mutex(); ~Mutex(); - ReturnValue_t lockMutex(uint32_t timeoutMs) override; + ReturnValue_t lockMutex(uint32_t timeoutMs = MutexIF::MAX_TIMEOUT) override; ReturnValue_t unlockMutex() override; private: SemaphoreHandle_t handle; From b90492562ac44f576ab7c7519826ae272d5be68e Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 16:40:57 +0200 Subject: [PATCH 87/94] added author tag back at class definition --- storagemanager/LocalPool.h | 1 + 1 file changed, 1 insertion(+) diff --git a/storagemanager/LocalPool.h b/storagemanager/LocalPool.h index c155f918..2d61dea5 100644 --- a/storagemanager/LocalPool.h +++ b/storagemanager/LocalPool.h @@ -22,6 +22,7 @@ * 0xFFFF-1 bytes. * It is possible to store empty packets in the pool. * The local pool is NOT thread-safe. + * @author Bastian Baetz */ template From 5cf9e938cccf450c5a4ad5b7fb74f7cc4b3705ff Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 16:45:03 +0200 Subject: [PATCH 88/94] added include protection --- storagemanager/LocalPool.tpp | 4 ++++ storagemanager/PoolManager.tpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/storagemanager/LocalPool.tpp b/storagemanager/LocalPool.tpp index 32724bd8..dd360a0a 100644 --- a/storagemanager/LocalPool.tpp +++ b/storagemanager/LocalPool.tpp @@ -1,6 +1,10 @@ #ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_TPP_ #define FRAMEWORK_STORAGEMANAGER_LOCALPOOL_TPP_ +#ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ +#error Include LocalPool.h instead of LocalPool.tpp!. +#endif + template inline LocalPool::LocalPool(object_id_t setObjectId, const uint16_t element_sizes[NUMBER_OF_POOLS], diff --git a/storagemanager/PoolManager.tpp b/storagemanager/PoolManager.tpp index 854e22da..bdc73ec2 100644 --- a/storagemanager/PoolManager.tpp +++ b/storagemanager/PoolManager.tpp @@ -1,6 +1,10 @@ #ifndef FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ #define FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ +#ifndef FRAMEWORK_STORAGEMANAGER_POOLMANAGER_H_ +#error Include LocalPool.h instead of LocalPool.tpp!. +#endif + template inline PoolManager::PoolManager(object_id_t setObjectId, const uint16_t element_sizes[NUMBER_OF_POOLS], From 3ef939aca8cff90c0ad51418e859eb69a76a655f Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 16:46:26 +0200 Subject: [PATCH 89/94] fixed inclue protection --- storagemanager/LocalPool.tpp | 2 +- storagemanager/PoolManager.tpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/storagemanager/LocalPool.tpp b/storagemanager/LocalPool.tpp index dd360a0a..b7fa0da9 100644 --- a/storagemanager/LocalPool.tpp +++ b/storagemanager/LocalPool.tpp @@ -2,7 +2,7 @@ #define FRAMEWORK_STORAGEMANAGER_LOCALPOOL_TPP_ #ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ -#error Include LocalPool.h instead of LocalPool.tpp!. +#error Include LocalPool.h instead of LocalPool.tpp! #endif template diff --git a/storagemanager/PoolManager.tpp b/storagemanager/PoolManager.tpp index bdc73ec2..97603246 100644 --- a/storagemanager/PoolManager.tpp +++ b/storagemanager/PoolManager.tpp @@ -2,7 +2,7 @@ #define FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ #ifndef FRAMEWORK_STORAGEMANAGER_POOLMANAGER_H_ -#error Include LocalPool.h instead of LocalPool.tpp!. +#error Include LocalPool.h instead of LocalPool.tpp! #endif template From 6b0558d6c71a5b23b2f678d5b18e170cde60e706 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 16:49:11 +0200 Subject: [PATCH 90/94] added author tag back --- storagemanager/PoolManager.h | 1 + 1 file changed, 1 insertion(+) diff --git a/storagemanager/PoolManager.h b/storagemanager/PoolManager.h index 6e353de2..c74e95c0 100644 --- a/storagemanager/PoolManager.h +++ b/storagemanager/PoolManager.h @@ -10,6 +10,7 @@ * a fixed pool size policy for inter-process communication. * @details Uses local pool calls but is thread safe by protecting the call * with a lock. + * @author Bastian Baetz */ template class PoolManager : public LocalPool { From f13eff79c90a174011c6d3b6c617ce25b575cc76 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 16:51:09 +0200 Subject: [PATCH 91/94] another little include guard fix --- storagemanager/LocalPool.tpp | 2 +- storagemanager/PoolManager.tpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/storagemanager/LocalPool.tpp b/storagemanager/LocalPool.tpp index b7fa0da9..764bd7be 100644 --- a/storagemanager/LocalPool.tpp +++ b/storagemanager/LocalPool.tpp @@ -2,7 +2,7 @@ #define FRAMEWORK_STORAGEMANAGER_LOCALPOOL_TPP_ #ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ -#error Include LocalPool.h instead of LocalPool.tpp! +#error Include LocalPool.h before LocalPool.tpp! #endif template diff --git a/storagemanager/PoolManager.tpp b/storagemanager/PoolManager.tpp index 97603246..29b2b82a 100644 --- a/storagemanager/PoolManager.tpp +++ b/storagemanager/PoolManager.tpp @@ -2,7 +2,7 @@ #define FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ #ifndef FRAMEWORK_STORAGEMANAGER_POOLMANAGER_H_ -#error Include LocalPool.h instead of LocalPool.tpp! +#error Include PoolManager.h before PoolManager.tpp! #endif template From 4d4ca2f3bd87efaca572378e107f92dda2c57eb2 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 17:43:37 +0200 Subject: [PATCH 92/94] doc fix for stopwatch --- timemanager/Stopwatch.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/timemanager/Stopwatch.h b/timemanager/Stopwatch.h index c57200b0..71580778 100644 --- a/timemanager/Stopwatch.h +++ b/timemanager/Stopwatch.h @@ -13,7 +13,7 @@ enum class StopwatchDisplayMode { * This class can be used to measure elapsed times. It also displays elapsed * times automatically on destruction if not explicitely deactivated in the * constructor. The default time format is the elapsed time in miliseconds - * as a float. + * in seconds as a double. * @author R. Mueller */ class Stopwatch { @@ -41,6 +41,10 @@ public: * @return elapsed time in milliseconds (rounded) */ millis_t stop(); + /** + * Calculates the elapsed time since start and returns it + * @return elapsed time in seconds (double precision) + */ seconds_t stopSeconds(); /** From 914bf8b9fc1afff3cf98675b4a98707099cb4021 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 17:45:53 +0200 Subject: [PATCH 93/94] seconds_t is double now --- timemanager/Clock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/timemanager/Clock.h b/timemanager/Clock.h index fcfacbc0..19991b81 100644 --- a/timemanager/Clock.h +++ b/timemanager/Clock.h @@ -9,7 +9,7 @@ #include typedef uint32_t millis_t; -typedef float seconds_t; +typedef double seconds_t; class Clock { public: From 7a22d12d0f1328ff55e3e2826e58000e191ef643 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 17:48:24 +0200 Subject: [PATCH 94/94] removed extern "C", not needed --- osal/linux/Clock.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/osal/linux/Clock.cpp b/osal/linux/Clock.cpp index b3e5c84b..630b2cf4 100644 --- a/osal/linux/Clock.cpp +++ b/osal/linux/Clock.cpp @@ -1,13 +1,11 @@ #include #include -extern "C" { #include #include #include #include #include -} //#include uint16_t Clock::leapSeconds = 0;