├── .codedocs ├── .gitignore ├── CallBack.cpp ├── CallBack.h ├── Doxycode ├── Doxyfile ├── EventCPP.h ├── FreeRTOScpp.h ├── FreeRTOScpp.md ├── LICENSE ├── Lock.cpp ├── Lock.h ├── MessageBufferCPP.h ├── MutexCPP.h ├── QueueCPP.h ├── README.md ├── ReadWrite.cpp ├── ReadWrite.h ├── SemaphoreCPP.h ├── StreamBufferCPP.h ├── TaskCPP.h ├── TaskCpp.cpp └── TimerCPP.h /.codedocs: -------------------------------------------------------------------------------- 1 | # Example .codedocs Configuration File 2 | # 3 | # Rename this example to '.codedocs' and put it in the root directory of your 4 | # repository. This file is optional, documentation will still be generated 5 | # without it using sensible defaults. 6 | 7 | #--------------------------------------------------------------------------- 8 | # CodeDocs Configuration 9 | #--------------------------------------------------------------------------- 10 | 11 | # Include the Doxygen configuration from another file. 12 | # The file must be a relative path with respect to the root of the repository. 13 | 14 | DOXYFILE = Doxycode 15 | 16 | # Specify external repository to link documentation with. 17 | # This is similar to Doxygen's TAGFILES option, but will automatically link to 18 | # tags of other repositories already using CodeDocs. List each repository to 19 | # link with by giving its location in the form of owner/repository. 20 | # For example: 21 | # TAGLINKS = doxygen/doxygen CodeDocs/osg 22 | # Note: these repositories must already be built on CodeDocs. 23 | 24 | TAGLINKS = 25 | 26 | #--------------------------------------------------------------------------- 27 | # Doxygen Configuration 28 | #--------------------------------------------------------------------------- 29 | 30 | # Doxygen configuration may also be placed in this file. 31 | # Currently, the following Doxygen configuration options are available. Refer 32 | # to http://doxygen.org/manual/config.html for detailed explanation of the 33 | # options. To request support for more options, contact support@codedocs.xyz. 34 | # 35 | # ABBREVIATE_BRIEF = 36 | # ALIASES = 37 | # ALPHABETICAL_INDEX = 38 | # ALWAYS_DETAILED_SEC = 39 | # CASE_SENSE_NAMES = 40 | # CLASS_DIAGRAMS = 41 | # DISABLE_INDEX = 42 | # DISTRIBUTE_GROUP_DOC = 43 | # EXAMPLE_PATH = 44 | # EXCLUDE = 45 | # EXCLUDE_PATTERNS = 46 | # EXCLUDE_SYMBOLS = 47 | # EXTENSION_MAPPING = 48 | # EXTRACT_LOCAL_CLASSES = 49 | # FILE_PATTERNS = 50 | # GENERATE_TAGFILE = 51 | # GENERATE_TREEVIEW = 52 | # HIDE_COMPOUND_REFERENCE = 53 | # HIDE_SCOPE_NAMES = 54 | # HIDE_UNDOC_CLASSES = 55 | # HIDE_UNDOC_MEMBERS = 56 | # HTML_TIMESTAMP = 57 | # INLINE_GROUPED_CLASSES = 58 | # INPUT_ENCODING = 59 | # INTERNAL_DOCS = 60 | # OPTIMIZE_OUTPUT_FOR_C = 61 | # PROJECT_BRIEF = 62 | # PROJECT_NAME = 63 | # PROJECT_NUMBER = 64 | # SHORT_NAMES = 65 | # SHOW_FILES = 66 | # SHOW_INCLUDE_FILES = 67 | # SHOW_NAMESPACES = 68 | # SORT_BRIEF_DOCS = 69 | # SORT_BY_SCOPE_NAME = 70 | # SORT_MEMBER_DOCS = 71 | # STRICT_PROTO_MATCHING = 72 | # TYPEDEF_HIDES_STRUCT = 73 | # USE_MDFILE_AS_MAINPAGE = 74 | # VERBATIM_HEADERS = 75 | # -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Compiled Dynamic libraries 8 | *.so 9 | *.dylib 10 | *.dll 11 | 12 | # Compiled Static libraries 13 | *.lai 14 | *.la 15 | *.a 16 | *.lib 17 | 18 | # Executables 19 | *.exe 20 | *.out 21 | *.app 22 | 23 | # Misc 24 | .DS_Store 25 | ._* 26 | doxygen_log.txt 27 | 28 | # Directories 29 | docs/ 30 | .svn/ 31 | .idea/ -------------------------------------------------------------------------------- /CallBack.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Callback.cpp 3 | * @brief FreeRTOS Call back wrapper 4 | * 5 | * This file provides the C Trampoline function for the Callback Wrappers 6 | * 7 | * @copyright (c) 2018-2024 Richard Damon 8 | * @author Richard Damon 9 | * @parblock 10 | * MIT License: 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy 13 | * of this software and associated documentation files (the "Software"), to deal 14 | * in the Software without restriction, including without limitation the rights 15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | * copies of the Software, and to permit persons to whom the Software is 17 | * furnished to do so, subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be included in 20 | * all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | * THE SOFTWARE. 29 | * 30 | * It is requested (but not required by license) that any bugs found or 31 | * improvements made be shared, preferably to the author. 32 | * @endparblock 33 | * 34 | * @ingroup FreeRTOSCpp 35 | */ 36 | 37 | #include 38 | 39 | using namespace FreeRTOScpp; 40 | 41 | extern "C" { 42 | void voidCallbackU32(void* cb, uint32_t parm) { 43 | CallBack* callback = static_cast* >(cb); 44 | callback->callback(parm); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /CallBack.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Callback.h 3 | * 4 | * @brief FreeRTOS CallBack Wrapper 5 | * 6 | * This file provides a template to generate wrappers around member function 7 | * calls with parameters, including one special one for use with the FreeRTOS 8 | * Pend / pendFromISR functions which includes the C trampoline function 9 | * 10 | * @copyright (c) 2018-2024 Richard Damon 11 | * @author Richard Damon 12 | * @parblock 13 | * MIT License: 14 | * 15 | * Permission is hereby granted, free of charge, to any person obtaining a copy 16 | * of this software and associated documentation files (the "Software"), to deal 17 | * in the Software without restriction, including without limitation the rights 18 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | * copies of the Software, and to permit persons to whom the Software is 20 | * furnished to do so, subject to the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be included in 23 | * all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 31 | * THE SOFTWARE. 32 | * 33 | * It is requested (but not required by license) that any bugs found or 34 | * improvements made be shared, preferably to the author. 35 | * @endparblock 36 | * 37 | * @ingroup FreeRTOSCpp 38 | */ 39 | 40 | #ifndef FREERTOSPP_CALLBACK_H 41 | #define FREERTOSPP_CALLBACK_H 42 | 43 | #include 44 | #include 45 | #include 46 | 47 | extern "C" { 48 | /** 49 | * @brief Define a "C" Callback trampline suitable for Timer Callbacks. 50 | * 51 | * This is a "C" API function that takes a void* and a uint32_t points, 52 | * like a FreeRTOS Timer callback that makes that FreeRTOS callback 53 | * link to our CallBack templates using the "C" Callbacks void* parameter. 54 | * This allows a CallBack to be used for a timer 55 | * 56 | * @param cb The Callback Object to use 57 | * @param parm The Parameter to send to the Callback 58 | */ 59 | extern void voidCallbackU32(void* cb, uint32_t parm); 60 | } 61 | 62 | #if FREERTOSCPP_USE_NAMESPACE 63 | namespace FreeRTOScpp { 64 | #endif 65 | 66 | /** 67 | * @brief Base callback with two parameters 68 | * 69 | * This is an abstract base class, where the derived class should define the callBack function. 70 | * 71 | * @tparam Tr The return type for the callback function 72 | * @tparam Tp1 The first parameter type, if void, there are no parameters 73 | * @tparam Tp2 The second parameter type, if void, only one parameter (unless Tp1 is void) 74 | */ 75 | template 76 | class CallBack { 77 | public: 78 | CallBack() {} 79 | virtual ~CallBack() {} 80 | 81 | virtual Tr callback(Tp1, Tp2) = 0; 82 | }; 83 | 84 | /** 85 | * Specialization of CallBack with only one parameter 86 | */ 87 | template 88 | class CallBack { 89 | public: 90 | CallBack() {} 91 | virtual ~CallBack() {} 92 | 93 | virtual Tr callback(Tp) = 0; 94 | }; 95 | 96 | /** 97 | * Specialization of CallBack with no parameters 98 | */ 99 | template 100 | class CallBack { 101 | public: 102 | CallBack() {} 103 | virtual ~CallBack() {} 104 | 105 | virtual Tr callback() = 0; 106 | }; 107 | 108 | /** 109 | * Specialization for One parameter of uint32_t, as that can be pended by FreeRTOS 110 | * 111 | * Add the pend operation (and pendFromISR) 112 | */ 113 | template<> 114 | class CallBack { 115 | public: 116 | CallBack() {} 117 | virtual ~CallBack() {} 118 | 119 | virtual void callback(uint32_t) = 0; 120 | #if INCLUDE_xTimerPendFunctionCall 121 | void pend(uint32_t parm, TickType_t ticks = portMAX_DELAY) { 122 | xTimerPendFunctionCall(&voidCallbackU32, this, parm, ticks); 123 | } 124 | #if FREERTOSCPP_USE_CHRONO 125 | void pend(uint32_t parm, Time_ms ms) { 126 | xTimerPendFunctionCall(&voidCallbackU32, this, parm, ms2ticks(ms)); 127 | } 128 | #endif 129 | 130 | void pendFromISR(uint32_t parm, BaseType_t* wasWoken) { 131 | xTimerPendFunctionCallFromISR(&voidCallbackU32, this, parm, wasWoken); 132 | } 133 | #endif 134 | }; 135 | 136 | /** 137 | * Derived Callback to call to a function 138 | * @tparam Tr 139 | * @tparam Tp1 140 | * @tparam Tp2 141 | */ 142 | template 143 | class FunctionCallback : public CallBack { 144 | public: 145 | FunctionCallback(Tr (*fun)(Tp1, Tp2)) : m_fun(fun) {} 146 | virtual ~FunctionCallback() {}; 147 | 148 | virtual Tr callback(Tp1 parm1, Tp2 parm2) { return (*m_fun)(parm1, parm2); } 149 | 150 | /// @brief Change the Memberfunction for the Callback 151 | /// @param fun 152 | void setFun(Tr (*fun)(Tp1, Tp2)) { m_fun = fun; } 153 | protected: 154 | Tr (*m_fun)(Tp1, Tp2); 155 | }; 156 | 157 | template 158 | class FunctionCallback : public CallBack { 159 | public: 160 | FunctionCallback(Tr (*fun)(Tp)) : m_fun(fun) {} 161 | virtual ~FunctionCallback() {}; 162 | 163 | virtual Tr callback(Tp parm) { return m_fun(parm); } 164 | void setFun(Tr (*fun)(Tp)) { m_fun = fun; } 165 | protected: 166 | Tr (*m_fun)(Tp); 167 | }; 168 | 169 | template 170 | class FunctionCallback : public CallBack { 171 | public: 172 | FunctionCallback(Tr (*fun)()) : m_fun(fun) {} 173 | virtual ~FunctionCallback() {}; 174 | 175 | virtual Tr callback() { return m_fun(); } 176 | void setFun(Tr *fun()) { m_fun = fun; } 177 | protected: 178 | Tr (*m_fun)(); 179 | 180 | }; 181 | 182 | template 183 | class MemberFunctionCallback : public CallBack { 184 | public: 185 | MemberFunctionCallback(Tc* obj, Tr (Tc::*fun)(Tp1, Tp2)) : m_obj(obj), m_fun(fun) {} 186 | virtual ~MemberFunctionCallback() {}; 187 | 188 | virtual Tr callback(Tp1 parm1, Tp2 parm2) { return (m_obj->*m_fun)(parm1, parm2); } 189 | 190 | /// @brief Change the Object for the Callback 191 | /// @param obj the new object 192 | void setObj(Tc* obj) { m_obj = obj;} 193 | /// @brief Change the Memberfunction for the Callback 194 | /// @param fun 195 | void setFun(Tr (Tc::*fun)(Tp1, Tp2)) { m_fun = fun; } 196 | protected: 197 | Tc* m_obj; 198 | Tr (Tc::*m_fun)(Tp1, Tp2); 199 | }; 200 | 201 | template 202 | class MemberFunctionCallback : public CallBack { 203 | public: 204 | MemberFunctionCallback(Tc* obj, Tr (Tc::*fun)(Tp)) : m_obj(obj), m_fun(fun) {} 205 | virtual ~MemberFunctionCallback() {}; 206 | 207 | virtual Tr callback(Tp parm) { return (m_obj->*m_fun)(parm); } 208 | void setObj(Tc* obj) { m_obj = obj;} 209 | void setFun(Tr (Tc::*fun)(Tp)) { m_fun = fun; } 210 | protected: 211 | Tc* m_obj; 212 | Tr (Tc::*m_fun)(Tp); 213 | }; 214 | 215 | template 216 | class MemberFunctionCallback : public CallBack { 217 | public: 218 | MemberFunctionCallback(Tc* obj, Tr (Tc::*fun)()) : m_obj(obj), m_fun(fun) {} 219 | virtual ~MemberFunctionCallback() {}; 220 | 221 | virtual Tr callback() { return (m_obj->*m_fun)(); } 222 | void setObj(Tc* obj) { m_obj = obj;} 223 | void setFun(Tr Tc::*fun()) { m_fun = fun; } 224 | protected: 225 | Tc* m_obj; 226 | Tr (Tc::*m_fun)(); 227 | 228 | }; 229 | 230 | #if FREERTOSCPP_USE_NAMESPACE 231 | } // namespace FreeRTOScpp 232 | #endif 233 | 234 | 235 | #endif /* FREERTOS_FREERTOSPP_CALLBACK_H_ */ 236 | -------------------------------------------------------------------------------- /EventCPP.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file EventCPP.h 3 | * @brief FreeRTOS Event Group Wrapper 4 | * 5 | * This file contains a set of lightweight wrappers for event groups using FreeRTOS 6 | * 7 | * @copyright (c) 2018-2024 Richard Damon 8 | * @author Richard Damon 9 | * @parblock 10 | * MIT License: 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy 13 | * of this software and associated documentation files (the "Software"), to deal 14 | * in the Software without restriction, including without limitation the rights 15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | * copies of the Software, and to permit persons to whom the Software is 17 | * furnished to do so, subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be included in 20 | * all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | * THE SOFTWARE. 29 | * 30 | * It is requested (but not required by license) that any bugs found or 31 | * improvements made be shared, preferably to the author. 32 | * @endparblock 33 | * 34 | * @ingroup FreeRTOSCpp 35 | */ 36 | 37 | #ifndef EVENTCPP_H 38 | #define EVENTCPP_H 39 | 40 | #include "FreeRTOScpp.h" 41 | #include "event_groups.h" 42 | 43 | /** 44 | * @def EVENT_BITS 45 | * Number of Bits usable as Event Bits 46 | * 47 | * @ingroup FreeRTOSCpp 48 | * 49 | * @def EVENT_MASK 50 | * Mask of bits usable as Event Bits 51 | * @ingroup FreeRTOSCpp 52 | */ 53 | 54 | #if ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_16_BITS ) 55 | #define EVENT_BITS 8 56 | #define EVENT_MASK 0x00FFU 57 | #elif ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_32_BITS ) 58 | #define EVENT_BITS 24 59 | #define EVENT_MASK 0x00FFFFFFUL 60 | #elif ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_64_BITS ) 61 | #define EVENT_BITS 56 62 | #define EVENT_MASK 0x00FFFFFFFFFFFFFFULL 63 | #endif /* if ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_16_BITS ) */ 64 | 65 | #if FREERTOSCPP_USE_NAMESPACE 66 | namespace FreeRTOScpp { 67 | #endif 68 | 69 | class EventGroup { 70 | public: 71 | EventGroup() { 72 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 73 | eventHandle = xEventGroupCreateStatic(&eventBuffer); 74 | #else 75 | eventHandle = xEventGroupCreate(); 76 | #endif 77 | } 78 | 79 | ~EventGroup() { 80 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 81 | #else 82 | vEventGroupDelete(eventHandle); 83 | #endif 84 | } 85 | 86 | /** 87 | * Get Event Bits 88 | * 89 | */ 90 | EventBits_t get() { 91 | return xEventGroupGetBits(eventHandle); 92 | } 93 | 94 | EventBits_t get_ISR() { 95 | return xEventGroupGetBitsFromISR(eventHandle); 96 | } 97 | 98 | /** 99 | * Set Event Bits 100 | * 101 | * Set Event bits and activate all tasks waiting for those bits. 102 | * 103 | * @param bits The Event Bits to Set. 104 | */ 105 | EventBits_t set(EventBits_t bits) { 106 | return xEventGroupSetBits(eventHandle, bits); 107 | } 108 | 109 | EventBits_t set_ISR(EventBits_t bits, portBASE_TYPE& waswoken) { 110 | return xEventGroupSetBitsFromISR(eventHandle, bits, &waswoken); 111 | } 112 | 113 | /** 114 | * Clear Event Bits 115 | * 116 | * @param bits The Event Bits to Set. 117 | */ 118 | EventBits_t clear(EventBits_t bits) { 119 | return xEventGroupClearBits(eventHandle, bits); 120 | } 121 | 122 | EventBits_t clear_ISR(EventBits_t bits) { 123 | return xEventGroupClearBitsFromISR(eventHandle, bits); 124 | } 125 | 126 | /** 127 | * Event Group Sync 128 | * 129 | * Sets the set bits than wait for all of the wait bits, and then clear all those bits. 130 | * 131 | * @returns the value of the event group befor clearing the bits. 132 | */ 133 | EventBits_t sync(EventBits_t set, EventBits_t wait, TickType_t ticks = portMAX_DELAY){ 134 | return xEventGroupSync(eventHandle, set, wait, ticks); 135 | } 136 | 137 | #if FREERTOSCPP_USE_CHRONO 138 | /** 139 | * Event Group Sync 140 | * 141 | * Sets the set bits than wait for all of the wait bits, and then clear all those bits. 142 | * 143 | * @returns the value of the event group befor clearing the bits. 144 | */ 145 | EventBits_t sync(EventBits_t set, EventBits_t wait, Time_ms ms){ 146 | return xEventGroupSync(eventHandle, set, wait, ms2ticks(ms)); 147 | } 148 | #endif 149 | 150 | /** 151 | * Wait for Event 152 | * 153 | * @param waitBits The bit(s) to wait for 154 | * @param clear If true, then the bits are cleared after the wait. 155 | * @param all If true, then wait for ALL the bits to be true, else for ANY of the bits 156 | * @param ticks How long to wait for the bits to be set 157 | * @returns The value of the event bits (before clearing) at the end of the wait. 158 | */ 159 | EventBits_t wait(EventBits_t waitBits, bool clear = true, bool all = false, TickType_t ticks = portMAX_DELAY) { 160 | return xEventGroupWaitBits(eventHandle, waitBits, clear, all, ticks); 161 | } 162 | #if FREERTOSCPP_USE_CHRONO 163 | /** 164 | * Wait for Event 165 | * 166 | * @param waitBits The bit(s) to wait for 167 | * @param clear If true, then the bits are cleared after the wait. 168 | * @param all If true, then wait for ALL the bits to be true, else for ANY of the bits 169 | * @param ticks How long to wait for the bits to be set 170 | * @returns The value of the event bits (before clearing) at the end of the wait. 171 | */ 172 | EventBits_t wait(EventBits_t waitBits, bool clear, bool all, Time_ms ms) { 173 | return xEventGroupWaitBits(eventHandle, waitBits, clear, all, ms2ticks(ms)); 174 | } 175 | #endif 176 | 177 | protected: 178 | EventGroupHandle_t eventHandle; 179 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 180 | StaticEventGroup_t eventBuffer; 181 | #endif 182 | 183 | }; 184 | 185 | #if FREERTOSCPP_USE_NAMESPACE 186 | } // namespace FreeRTOScpp 187 | #endif 188 | 189 | 190 | #endif 191 | -------------------------------------------------------------------------------- /FreeRTOScpp.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file FreeRTOScpp.h 3 | * @brief FreeRTOS Wrapper 4 | * 5 | * This file contains a set of lightweight wrappers for tasks using FreeRTOS 6 | * 7 | * @copyright (c) 2007-2024 Richard Damon 8 | * @author Richard Damon 9 | * @parblock 10 | * MIT License: 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy 13 | * of this software and associated documentation files (the "Software"), to deal 14 | * in the Software without restriction, including without limitation the rights 15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | * copies of the Software, and to permit persons to whom the Software is 17 | * furnished to do so, subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be included in 20 | * all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | * THE SOFTWARE. 29 | * 30 | * It is requested (but not required by license) that any bugs found or 31 | * improvements made be shared, preferably to the author. 32 | * @endparblock 33 | * 34 | * @ingroup FreeRTOSCpp 35 | */ 36 | 37 | #ifndef FREERTOSPP_FREERTOSCPP_H_ 38 | #define FREERTOSPP_FREERTOSCPP_H_ 39 | 40 | #include "FreeRTOS.h" 41 | #include "task.h" // For Version Numbers 42 | 43 | /** 44 | * @def FREERTOSCPP_USE_CHRONO 45 | * Enable the use of C++ chrono time values. 46 | * 47 | * @ingroup FreeRTOSCpp 48 | * 49 | * @def FREERTOS_USE_NAMESPACE 50 | * If non-zero, put FreeRTOScpp library into namespace FreeRTOScpp. 51 | * If 2, adds a using namespace FreeRTOScpp, so code doesn't need to use that namespace unless conflicts arise. 52 | * @ingroup FreeRTOSCpp 53 | */ 54 | 55 | #if DOXYGEN 56 | #define FREERTOSCPP_USE_CHRONO 1 57 | #define FREERTOS_USE_NAMESPACE 2 58 | #endif 59 | 60 | #define FREERTOS_VERSION_ALL (tskKERNEL_VERSION_MAJOR * 1'000'000 + tskKERNEL_VERSION_MINOR * 1000 + tskKERNEL_VERSION_BUILD) 61 | 62 | #ifndef FREERTOSCPP_USE_CHRONO 63 | #define FREERTOSCPP_USE_CHRONO 1 // Define to 1 to add C++ chrono time versions 64 | #endif 65 | 66 | #ifndef FREERTOSCPP_USE_NAMESPACE 67 | #define FREERTOSCPP_USE_NAMESPACE 2 // 0 = No Namespace, 1 = In namespace FreeRTOScpp, 2 = In namespace FreeRTOScpp and then use the namespace 68 | #endif 69 | 70 | #if FREERTOSCPP_USE_CHRONO 71 | #include 72 | #endif 73 | 74 | namespace FreeRTOScpp { 75 | 76 | #if FREERTOSCPP_USE_CHRONO 77 | // Code to use std::chrono::durations optionally for times 78 | 79 | typedef std::chrono::milliseconds Time_ms; 80 | 81 | inline constexpr TickType_t ms2ticks(Time_ms ms) { 82 | return pdMS_TO_TICKS(ms.count()); 83 | } 84 | #endif 85 | 86 | } // namespace FreeRTOScpp 87 | #if FREERTOSCPP_USE_NAMESPACE == 2 88 | using namespace FreeRTOScpp; 89 | #endif 90 | 91 | #endif /* FREERTOSPP_FREERTOSCPP_H_ */ 92 | -------------------------------------------------------------------------------- /FreeRTOScpp.md: -------------------------------------------------------------------------------- 1 | @page FreeRTOScpp FreeRTOS C++ Wrappers 2 | 3 | FreeRTOScpp is a package that provides a light C++ wrapper for FreeRTOS (). 4 | 5 | It provides wrappers for the Task, Queue, Semaphore, and Mutex (including RecursiveMutex). 6 | 7 | I find the big advantage is that these allow me to declare these items as (part of) 8 | global objects, and then the items are automatically created and configured, without 9 | needing to change the main() function. 10 | 11 | They also provide member function style access for most of the basic operations 12 | on the items. 13 | 14 | See @ref FreeRTOSCpp 15 | 16 | @defgroup FreeRTOSCpp FreeRTOS C++ Wrapper 17 | @ingroup Library 18 | See @ref FreeRTOScpp 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2007-2015 Richard Damon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Lock.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Lock.cpp 3 | * @brief FreeRTOS Lock wrapper 4 | * 5 | * @copyright (c) 2018-2024 Richard Damon 6 | * @author Richard Damon 7 | * @parblock 8 | * MIT License: 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | * 28 | * It is requested (but not required by license) that any bugs found or 29 | * improvements made be shared, preferably to the author. 30 | * @endparblock 31 | * 32 | * @ingroup FreeRTOSCpp 33 | */ 34 | 35 | #include 36 | 37 | using namespace FreeRTOScpp; 38 | 39 | /** 40 | * Constructor 41 | * 42 | * This is the most generic constructor, and the one that will be used if no parameters beyond the 43 | * lockable object are given. The alternate constructor only take the time to wait, and assumes the 44 | * second parameter is true 45 | * 46 | * If wait is specified (or some code might abort the wait) then the code should check with 47 | * a call to locked() to confirm the lock has been taken. 48 | * 49 | * @param mylockable The Lockable object we will be using 50 | * @param mylocked Should we start by taking the lock 51 | * @param wait How long to wait to take the lock 52 | */ 53 | Lock::Lock(Lockable& mylockable, bool mylocked, TickType_t wait) : 54 | lockable(mylockable), 55 | lockCnt(0) 56 | { 57 | if(mylocked) lock(wait); 58 | } 59 | 60 | #if FREERTOSCPP_USE_CHRONO 61 | /** 62 | * Constructor 63 | * 64 | * Version to specifiy the time to wait to get the lock as a Chrono in milliseconds 65 | * 66 | * Code will need to check that the lock was gotten with a call to locked() 67 | * 68 | * @param mylockable The Lockable object we will be using 69 | * @param wait_ms How long to wait to take the lock in millisecons 70 | */ 71 | Lock::Lock(Lockable& myLockable, Time_ms wait_ms) : 72 | lockable(myLockable), 73 | lockCnt(0) 74 | { 75 | lock(wait_ms); 76 | } 77 | #endif 78 | 79 | /** 80 | * Destructor 81 | */ 82 | Lock::~Lock() { 83 | // on destruct, remove all locks. 84 | if(lockCnt > 0) { 85 | lockable.give(); 86 | } 87 | lockCnt = 0; 88 | } 89 | 90 | /** 91 | * Try to take to lock 92 | * 93 | * Note, lock allows for nested calls, which need to be unlocked as many times 94 | * as taken, even if the lockable isn't recursive. 95 | * 96 | * @param wait How long to wait in Ticks 97 | * @return true if lock has been taken 98 | */ 99 | bool Lock::lock(TickType_t wait) { 100 | if(lockCnt > 0) { 101 | lockCnt++; 102 | return true; 103 | } 104 | if(lockable.take(wait)) { 105 | lockCnt++; 106 | return true; 107 | } 108 | return false; 109 | } 110 | 111 | /** 112 | * Release a lock 113 | */ 114 | void Lock::unlock() { 115 | if(lockCnt > 0) { // ignore extra unlocks. 116 | lockCnt--; 117 | if(lockCnt == 0) { 118 | lockable.give(); 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Lock.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Lock.h 3 | * @brief FreeRTOS Lock wrapper 4 | * 5 | * A Generic Locking interface for Lockable objects. 6 | * 7 | * @copyright (c) 2018-2024 Richard Damon 8 | * @author Richard Damon 9 | * @parblock 10 | * MIT License: 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy 13 | * of this software and associated documentation files (the "Software"), to deal 14 | * in the Software without restriction, including without limitation the rights 15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | * copies of the Software, and to permit persons to whom the Software is 17 | * furnished to do so, subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be included in 20 | * all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | * THE SOFTWARE. 29 | * 30 | * It is requested (but not required by license) that any bugs found or 31 | * improvements made be shared, preferably to the author. 32 | * @endparblock 33 | * 34 | * @ingroup FreeRTOSCpp 35 | */ 36 | 37 | #ifndef FREERTOSPP_LOCK_H_ 38 | #define FREERTOSPP_LOCK_H_ 39 | 40 | #include "FreeRTOScpp.h" 41 | 42 | #if FREERTOSCPP_USE_NAMESPACE 43 | namespace FreeRTOScpp { 44 | #endif 45 | 46 | /** 47 | * A Base class to provide block based locking capability. 48 | * 49 | * Any object that supports "Locking" should be derived from Lockable (like a Semaphore or Mutex) 50 | * 51 | * Such objects need to provide an interface consisting of 52 | * + virtual bool take(TickType_t wait) 53 | * + virtual bool give(); 54 | * 55 | * @ingroup FreeRTOSCpp 56 | */ 57 | 58 | class Lockable { 59 | public: 60 | Lockable() {} 61 | virtual ~Lockable() {} 62 | 63 | virtual bool take(TickType_t wait = portMAX_DELAY) = 0; 64 | #if FREERTOSCPP_USE_CHRONO 65 | bool take(Time_ms ms) { return take(ms2ticks(ms)); } 66 | #endif 67 | virtual bool give() = 0; 68 | private: 69 | #if __cplusplus < 201101L 70 | Lockable(Lockable const&); ///< We are not copyable. 71 | void operator =(Lockable const&); ///< We are not assignable. 72 | #else 73 | Lockable(Lockable const&) = delete; ///< We are not copyable. 74 | void operator =(Lockable const&) = delete; ///< We are not assignable. 75 | #endif // __cplusplus 76 | }; 77 | 78 | /** 79 | * Class to hold a block based lock. (auto unlocks on in its destructor) 80 | * 81 | * Typical calling sequences: 82 | * 83 | * @code 84 | * // Somewhere global 85 | * Mutex mutex 86 | * @endcode 87 | * then, in a block 88 | * @code 89 | * { 90 | * Lock lock(mutex); // Mutex is taken here 91 | * ... 92 | * } // and released here 93 | * @endcode 94 | * or 95 | * @code 96 | * 97 | * { 98 | * Lock lokc(mutex, false); // don't take it yet 99 | * ... 100 | * if (lock.lock(5)) { // but take it here, with a maximum timeout 101 | * ... 102 | * lock.unlock(); // and possible release it 103 | * } 104 | * 105 | * } // will be released here if taken and not released 106 | * @endcode 107 | * or 108 | * @code 109 | * { 110 | * Lock lock(mute, 5); // Try to take the semaphore with a timeout 111 | * if (lock.locked()) { 112 | * // Semaphore was locked, so we could use it 113 | * } else { 114 | * // Error handling because we couldn't take the semaphore. 115 | * } 116 | * } // Mutex will be released here if not otherwise release 117 | * @endcode 118 | * 119 | * @ingroup FreeRTOSCpp 120 | */ 121 | class Lock { 122 | public: 123 | Lock(Lockable& mylockable, bool mylocked = true, TickType_t wait = portMAX_DELAY); 124 | /** 125 | * Constructor with assumed locking by specifying lock time 126 | * @param mylockable The Lockabe object to use 127 | * @param wait The time it Ticks to wait to get the lock. 128 | */ 129 | Lock(Lockable& mylockable, TickType_t wait) : Lock(mylockable, true, wait) {} 130 | #if FREERTOSCPP_USE_CHRONO 131 | Lock(Lockable& mylockable, Time_ms wait); 132 | #endif 133 | virtual ~Lock(); 134 | 135 | bool lock(TickType_t wait = portMAX_DELAY); 136 | #if FREERTOSCPP_USE_CHRONO 137 | bool lock(Time_ms ms) { return lock(ms2ticks(ms)); } 138 | #endif 139 | void unlock(); 140 | /** 141 | * Do we have the lock? 142 | * @return True if we have the lock. 143 | */ 144 | bool locked() const { return lockCnt > 0; } 145 | private: 146 | Lockable& lockable; ///< The Lockage object we are connected to 147 | int lockCnt; ///< The number of locks we hold on lockable. 148 | 149 | #if __cplusplus < 201101L 150 | Lock(Lock const&); ///< We are not copyable. 151 | void operator =(Lock const&); ///< We are not assignable. 152 | #else 153 | Lock(Lock const&) = delete; ///< We are not copyable. 154 | void operator =(Lock const&) = delete; ///< We are not assignable. 155 | #endif // __cplusplus 156 | }; 157 | 158 | #if FREERTOSCPP_USE_NAMESPACE 159 | } // namespace FreeRTOScpp 160 | #endif 161 | #endif /* FREERTOSPP_LOCK_H_ */ 162 | -------------------------------------------------------------------------------- /MessageBufferCPP.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MessageBufferCPP.h 3 | * @brief FreeRTOS MessageBuffer wrapper 4 | * 5 | * Wrapper for FreeRTOS MessageBuffers 6 | * 7 | * @copyright (c) 2024 Richard Damon 8 | * @author Richard Damon 9 | * @parblock 10 | * MIT License: 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy 13 | * of this software and associated documentation files (the "Software"), to deal 14 | * in the Software without restriction, including without limitation the rights 15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | * copies of the Software, and to permit persons to whom the Software is 17 | * furnished to do so, subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be included in 20 | * all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | * THE SOFTWARE. 29 | * 30 | * It is requested (but not required by license) that any bugs found or 31 | * improvements made be shared, preferably to the author. 32 | * @endparblock 33 | * 34 | * @ingroup FreeRTOSCpp 35 | */ 36 | 37 | #ifndef MESSAGEBUFFER_CPP_H 38 | #define MESSAGEBUFFER_CPP_H 39 | 40 | #include "FreeRTOScpp.h" 41 | 42 | #include "message_buffer.h" 43 | 44 | #if FREERTOSCPP_USE_NAMESPACE 45 | namespace FreeRTOScpp { 46 | #endif 47 | 48 | /** 49 | * Base Wrapper Class for MessageBuffer 50 | * 51 | * Base Class does all the operations, there is then a derived class to build the buffer, 52 | * or the base class can be a wrapper around an elsewhere created handle. 53 | */ 54 | class MessageBufferBase { 55 | public: 56 | MessageBufferBase(MessageBufferHandle_t mbHandle) : msgHandle(mbHandle) {} 57 | virtual ~MessageBufferBase() { } 58 | 59 | size_t send(const void* data, size_t len, TickType_t delay = portMAX_DELAY) 60 | {return xMessageBufferSend(msgHandle, data, len, delay);} 61 | #if FREERTOSCPP_USE_CHRONO 62 | size_t send(const void* data, size_t len, Time_ms delay) 63 | {return xMessageBufferSend(msgHandle, data, len, ms2ticks(delay));} 64 | #endif 65 | size_t send_ISR(const void* data, size_t len, BaseType_t &wasWoken) 66 | {return xMessageBufferSendFromISR(msgHandle, data, len, &wasWoken);} 67 | 68 | size_t read(void* data, size_t len, TickType_t delay = portMAX_DELAY) 69 | {return xMessageBufferReceive(msgHandle, data, len, delay);} 70 | #if FREERTOSCPP_USE_CHRONO 71 | size_t read(void* data, size_t len, Time_ms delay) 72 | {return xMessageBufferReceive(msgHandle, data, len, ms2ticks(delay));} 73 | #endif 74 | size_t read_ISR(void* data, size_t len, BaseType_t &wasWoken) 75 | {return xMessageBufferReceiveFromISR(msgHandle, data, len, &wasWoken);} 76 | 77 | // Message Buffers do not provide "Bytes Available" 78 | 79 | /// @brief Get the amount of available space open in the MessageBuffer 80 | /// @return The number of bytes that can be sent before the buffer is full 81 | size_t available() const { return xMessageBufferSpacesAvailable(msgHandle);} 82 | 83 | bool isEmpty() const { return xMessageBufferIsEmpty(msgHandle);} 84 | 85 | bool isFull() const { return xMessageBufferIsFull(msgHandle);} 86 | 87 | /// @brief Resets the buffer to empty 88 | /// @return True if done, stream can not be reset if a task is waiting on the MessageBuffer. 89 | bool reset() { return xMessageBufferReset(msgHandle);} 90 | 91 | MessageBufferHandle_t msgHandle; 92 | }; 93 | 94 | /** 95 | * Template to implement a Message Buffer of a given size. 96 | * 97 | * MessageBuffer will be created statically if possible. 98 | * 99 | * @tparam size The number of bytes to store in the buffer, 0 = dynamically created 100 | */ 101 | 102 | template 107 | class MessageBuffer : public MessageBufferBase { 108 | public: 109 | MessageBuffer() : 110 | MessageBufferBase( 111 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 112 | xMessageBufferCreateStatic(size, storage, msgBuff) 113 | #else 114 | xMessageBufferCreate(size) 115 | #endif 116 | ) {} 117 | 118 | virtual ~MessageBuffer() { vMessageBufferDelete(msgHandle);} 119 | 120 | #if configUSE_SB_COMPLETED_CALLBACK 121 | MessageBuffer(StreamBufferCallbackFunction_t sendCallback, StreamBufferCallbackFunction_t recvCallback) : 122 | MessageBufferBase( 123 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 124 | xMessageBufferCreateStaticWithCallback(size, storage, msgBuff, sendCallback, recvCallback) 125 | #else 126 | xMessageBufferCreateWithCallback(size, sendCallback. recvCallBack) 127 | #endif 128 | ) 129 | {} 130 | #endif //configUSE_SB_COMPLETED_CALLBACK 131 | 132 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 133 | uint8_t storage[size+1]; 134 | StaticMessageBuffer_t msgBuff; 135 | #endif 136 | }; 137 | 138 | #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) 139 | 140 | template <> 141 | class MessageBuffer<0> : public MessageBufferBase { 142 | public: 143 | MessageBuffer(size_t size) : 144 | MessageBufferBase(xMessageBufferCreate(size)) 145 | {} 146 | virtual ~MessageBuffer() { vMessageBufferDelete(msgHandle);} 147 | 148 | #if configUSE_SB_COMPLETED_CALLBACK 149 | MessageBuffer(size_t size, StreamBufferCallbackFunction_t sendCallback, StreamBufferCallbackFunction_t recvCallback) : 150 | MessageBufferBase(xMessageBufferCreateWithCallback(size, sendCallback, recvCallback)) 151 | {} 152 | #endif // configUSE_SB_COMPLETED_CALLBACK 153 | }; 154 | #endif 155 | 156 | #if FREERTOSCPP_USE_NAMESPACE 157 | } 158 | #endif 159 | 160 | #endif -------------------------------------------------------------------------------- /MutexCPP.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MutexCPP.h 3 | * @brief FreeRTOS Mutex Wrapper 4 | * 5 | * This file contains a set of lightweight wrappers for mutexes using FreeRTOS 6 | * 7 | * @copyright (c) 2007-2024 Richard Damon 8 | * @author Richard Damon 9 | * @parblock 10 | * MIT License: 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy 13 | * of this software and associated documentation files (the "Software"), to deal 14 | * in the Software without restriction, including without limitation the rights 15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | * copies of the Software, and to permit persons to whom the Software is 17 | * furnished to do so, subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be included in 20 | * all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | * THE SOFTWARE. 29 | * 30 | * It is requested (but not required by license) that any bugs found or 31 | * improvements made be shared, preferably to the author. 32 | * @endparblock 33 | * 34 | * @ingroup FreeRTOSCpp 35 | */ 36 | 37 | #ifndef MUTEXCPP_H 38 | #define MUTEXCPP_H 39 | 40 | #include "FreeRTOScpp.h" 41 | 42 | #include "Lock.h" 43 | #include "semphr.h" 44 | 45 | #if FREERTOSCPP_USE_NAMESPACE 46 | namespace FreeRTOScpp { 47 | #endif 48 | 49 | /** 50 | * @brief Mutex Wrapper. 51 | * 52 | * A Mutex is a basic synchronization primitive allowing mutual exclusion to be 53 | * handled which also implements priority inheritance. Note, the basic mutex is 54 | * NOT recursive, ie if a Task has taken the Mutex, it must not try to take it 55 | * again before giving it. If you need this, use a RecurviseMutex. 56 | * 57 | * The usage of a Mutex is similar to a semaphore, but the task that takes the 58 | * Mutex is also supposed to be the Task that eventually gives it back. It also 59 | * doesn't normally make sense for an ISR to use a Mutex, so no _ISR routines 60 | * have been made available. 61 | * 62 | * Example Usage: 63 | * @code 64 | * RecursiveMutex mutex("MyMutex"); 65 | * 66 | * // In some other task 67 | * mutex.take(); 68 | * ... // some code that needs mutual exclusion 69 | * mutex.give(); 70 | * @endcode 71 | * 72 | * @ingroup FreeRTOSCpp 73 | */ 74 | 75 | class Mutex : public Lockable { 76 | public: 77 | /** 78 | * @brief Constructor. 79 | * @param name Name to give mutex, used for Debug Registry if setup 80 | */ 81 | Mutex(char const* name) { 82 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 83 | mutexHandle = xSemaphoreCreateMutexStatic(&mutexBuffer); 84 | #else 85 | mutexHandle = xSemaphoreCreateMutex(); 86 | #endif 87 | #if configQUEUE_REGISTRY_SIZE > 0 88 | vQueueAddToRegistry(mutexHandle, name); 89 | #endif 90 | } 91 | /** 92 | * @brief Destructor. 93 | * 94 | * Deletes the semaphore. 95 | */ 96 | ~Mutex() { 97 | vSemaphoreDelete(mutexHandle); 98 | } 99 | 100 | bool take(TickType_t wait = portMAX_DELAY) override { 101 | return xSemaphoreTake(mutexHandle, wait); 102 | } 103 | #if FREERTOSCPP_USE_CHRONO 104 | bool take(Time_ms wait) { 105 | return xSemaphoreTake(mutexHandle, ms2ticks(wait)); 106 | } 107 | #endif 108 | 109 | bool give() override { 110 | return xSemaphoreGive(mutexHandle); 111 | } 112 | private: 113 | SemaphoreHandle_t mutexHandle; 114 | #if __cplusplus < 201101L 115 | Mutex(Mutex const&); ///< We are not copyable. 116 | void operator =(Mutex const&); ///< We are not assignable. 117 | #else 118 | Mutex(Mutex const&) = delete; ///< We are not copyable. 119 | void operator =(Mutex const&) = delete; ///< We are not assignable. 120 | #endif // __cplusplus 121 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 122 | StaticSemaphore_t mutexBuffer; 123 | #endif 124 | 125 | }; 126 | 127 | #if configUSE_RECURSIVE_MUTEXES > 0 128 | /** 129 | * @brief Recursive Mutex Wrapper. 130 | * 131 | * A RecursiveMutex adds the ability to nest takes, so that if you have taken the 132 | * RecursiveMutex and take it again, this works and requires you to give the 133 | * RecursiveMutex back as many times as it was taken before it is released. 134 | * 135 | * One very common application for this is for messages to the user on a console. 136 | * Generally, you don't want pieces of a message interrupted by pieces of other 137 | * messages, so message output routines use a mutex on the console port. 138 | * These routines often use lower level routines that also want to make sure their 139 | * output isn't interspersed, so each level takes the RecursiveMutex at their start 140 | * and releases it at the end. Being a RecursiveMutex this works. 141 | * 142 | * Example Usage: 143 | * @code 144 | * RecursiveMutex mutex("MyMutex"); 145 | * 146 | * // In some other task 147 | * mutex.take(); 148 | * ... 149 | * // possible in a recursive call or call to lower level routine. 150 | * mutex.take(); 151 | * ... 152 | * mutex.give(); 153 | * ... 154 | * mutex.give(); 155 | * 156 | * @endcode 157 | * @ingroup FreeRTOSCpp 158 | */ 159 | 160 | class RecursiveMutex : public Lockable{ 161 | public: 162 | RecursiveMutex(char const* name = nullptr) { 163 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 164 | mutexHandle = xSemaphoreCreateRecursiveMutexStatic(&mutexBuffer); 165 | #else 166 | mutexHandle = xSemaphoreCreateRecursiveMutex(); 167 | #endif 168 | #if configQUEUE_REGISTRY_SIZE > 0 169 | if(name) 170 | vQueueAddToRegistry(mutexHandle, name); 171 | #endif 172 | } 173 | ~RecursiveMutex() { 174 | vSemaphoreDelete(mutexHandle); 175 | } 176 | 177 | bool take(TickType_t wait = portMAX_DELAY) override { 178 | return xSemaphoreTakeRecursive(mutexHandle, wait); 179 | } 180 | bool give() override { 181 | return xSemaphoreGiveRecursive(mutexHandle); 182 | } 183 | 184 | private: 185 | SemaphoreHandle_t mutexHandle; 186 | #if __cplusplus < 201101L 187 | RecursiveMutex(RecursiveMutex const&); ///< We are not copyable. 188 | void operator =(RecursiveMutex const&); ///< We are not assignable. 189 | #else 190 | RecursiveMutex(RecursiveMutex const&) = delete; ///< We are not copyable. 191 | void operator =(RecursiveMutex const&) = delete; ///< We are not assignable. 192 | #endif // __cplusplus 193 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 194 | StaticSemaphore_t mutexBuffer; 195 | #endif 196 | }; 197 | #endif // configUSE_RECURSIVE_MUTEXES 198 | 199 | #if FREERTOSCPP_USE_NAMESPACE 200 | } // namespace FreeRTOScpp 201 | #endif 202 | 203 | #endif // MUTEXCPP_H 204 | -------------------------------------------------------------------------------- /QueueCPP.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file QueueCPP.h 3 | * @brief FreeRTOS Queue Wrapper 4 | * 5 | * This file contains a set of lightweight wrappers for queues using FreeRTOS 6 | * 7 | * @copyright (c) 2007-2024 Richard Damon 8 | * @author Richard Damon 9 | * @parblock 10 | * MIT License: 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy 13 | * of this software and associated documentation files (the "Software"), to deal 14 | * in the Software without restriction, including without limitation the rights 15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | * copies of the Software, and to permit persons to whom the Software is 17 | * furnished to do so, subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be included in 20 | * all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | * THE SOFTWARE. 29 | * 30 | * It is requested (but not required by license) that any bugs found or 31 | * improvements made be shared, preferably to the author. 32 | * @endparblock 33 | * 34 | * @ingroup FreeRTOSCpp 35 | */ 36 | #ifndef QUEUECPP_H 37 | #define QUEUECPP_H 38 | 39 | #include "FreeRTOScpp.h" 40 | #include "queue.h" 41 | 42 | #if FREERTOSCPP_USE_NAMESPACE 43 | namespace FreeRTOScpp { 44 | #endif 45 | 46 | //#include 47 | /** 48 | * @brief Base Queue Wrapper 49 | * 50 | * This Base Class provides the Type Independent functionality for a Queue 51 | * @ingroup FreeRTOSCpp 52 | */ 53 | 54 | class QueueBase { 55 | protected: 56 | /** 57 | * @brief Constructor 58 | * 59 | * Effectively Abstract class so protected base. 60 | * @param handle_ The queueHandle for the queue/ 61 | */ 62 | QueueBase(QueueHandle_t handle_) : queueHandle(handle_) {}; 63 | public: 64 | /** 65 | * @brief Destructor. 66 | */ 67 | virtual ~QueueBase() { 68 | vQueueDelete(queueHandle); 69 | } 70 | 71 | /** 72 | * @brief Get number of items in the Queue. 73 | * @return The number of item in the Queue. 74 | */ 75 | unsigned waiting() const { 76 | return uxQueueMessagesWaiting(queueHandle); 77 | } 78 | 79 | /** 80 | * @brief Return number of spaces available in Queue 81 | * @return the number of spaces available in the Queue. 82 | */ 83 | unsigned available() const { 84 | return uxQueueSpacesAvailable(queueHandle); 85 | } 86 | 87 | /** 88 | * @brief Reset the Queue. 89 | * Resets the Queue to an empty state. 90 | */ 91 | void reset() { 92 | xQueueReset(queueHandle); 93 | } 94 | 95 | /** 96 | * @brief Check if Queue is Full. 97 | * @return True if Queue is Full. 98 | */ 99 | bool full() { 100 | return 0 == uxQueueSpacesAvailable(queueHandle); 101 | } 102 | 103 | /** 104 | * @brief Check if Queue is Empty 105 | * @return True if Queue is Empty. 106 | */ 107 | bool empty() { 108 | return uxQueueMessagesWaiting(queueHandle) == 0; 109 | } 110 | 111 | /** 112 | * @brief Is Queue Full. 113 | * Note: Interrupt service routines should only call _ISR routines. 114 | * @return True if Queue is Full. 115 | */ 116 | bool full_ISR() { 117 | return xQueueIsQueueFullFromISR(queueHandle); 118 | } 119 | 120 | /** 121 | * @brief Is Queue Empty. 122 | * Note: Interrupt service routines should only call _ISR routines. 123 | * @return True if Queue is Empty. 124 | */ 125 | bool empty_ISR() { 126 | return xQueueIsQueueEmptyFromISR(queueHandle); 127 | } 128 | 129 | /** 130 | * @brief Get number of message waiting. 131 | * Note: Interrupt service routines should only call _ISR routines. 132 | * @return The number of messages waiting. 133 | */ 134 | unsigned waiting_ISR() { 135 | return uxQueueMessagesWaitingFromISR(queueHandle); 136 | } 137 | 138 | protected: 139 | QueueHandle_t queueHandle; 140 | private: 141 | 142 | #if __cplusplus < 201101L 143 | QueueBase(QueueBase const&); ///< We are not copyable. 144 | void operator =(QueueBase const&); ///< We are not assignable. 145 | #else 146 | QueueBase(QueueBase const&) = delete; ///< We are not copyable. 147 | void operator =(QueueBase const&) = delete; ///< We are not assignable. 148 | #endif // __cplusplus 149 | 150 | }; 151 | 152 | /** 153 | * @brief Typed Queue Wrapper 154 | * 155 | * This Base Class provides the Type Dependent functionality for a Queue 156 | * @ingroup FreeRTOSCpp 157 | */ 158 | 159 | template class QueueTypeBase : public QueueBase { 160 | protected: 161 | QueueTypeBase(QueueHandle_t handle_) : QueueBase(handle_) {} 162 | 163 | public: 164 | /** 165 | * @brief Push an item onto the Queue. 166 | * Puts an item onto the Queue so it will be the next item to remove. 167 | * @param item The item to put on the Queue. 168 | * @param time How long to wait for room if Queue is full. 169 | * @return True if successful 170 | */ 171 | bool push(T const& item, TickType_t time = portMAX_DELAY){ 172 | return xQueueSendToFront(queueHandle, &item, time); 173 | } 174 | #if FREERTOSCPP_USE_CHRONO 175 | /** 176 | * @brief Push an item onto the Queue. 177 | * Puts an item onto the Queue so it will be the next item to remove. 178 | * @param item The item to put on the Queue. 179 | * @param time How long to wait for room if Queue is full. 180 | * @return True if successful 181 | */ 182 | bool push(T const& item, Time_ms time){ 183 | return xQueueSendToFront(queueHandle, &item, ms2ticks(time)); 184 | } 185 | #endif 186 | /** 187 | * @brief add an item at end of the Queue. 188 | * Puts an item onto the Queue so it will be the last item to remove. 189 | * @param item The item to put on the Queue. 190 | * @param time How long to wait for room if Queue is full. 191 | * @return True if successful 192 | */ 193 | bool add(T const& item, TickType_t time = portMAX_DELAY){ 194 | return xQueueSendToBack(queueHandle, &item, time); 195 | } 196 | #if FREERTOSCPP_USE_CHRONO 197 | /** 198 | * @brief add an item at end of the Queue. 199 | * Puts an item onto the Queue so it will be the last item to remove. 200 | * @param item The item to put on the Queue. 201 | * @param time How long to wait for room if Queue is full. 202 | * @return True if successful 203 | */ 204 | bool add(T const& item, Time_ms time){ 205 | return xQueueSendToBack(queueHandle, &item, ms2ticks(time)); 206 | } 207 | #endif 208 | /** 209 | * @brief Get an item from the Queue. 210 | * Gets the first item from the Queue 211 | * @param var Variable to place the item 212 | * @param time How long to wait for an item to be available. 213 | * @return True if an item returned. 214 | */ 215 | bool pop(T& var, TickType_t time = portMAX_DELAY) { 216 | return xQueueReceive(queueHandle, &var, time); 217 | } 218 | #if FREERTOSCPP_USE_CHRONO 219 | /** 220 | * @brief Get an item from the Queue. 221 | * Gets the first item from the Queue 222 | * @param var Variable to place the item 223 | * @param time How long to wait for an item to be available. 224 | * @return True if an item returned. 225 | */ 226 | bool pop(T& var, Time_ms time) { 227 | return xQueueReceive(queueHandle, &var, ms2ticks(time)); 228 | } 229 | #endif 230 | 231 | /** 232 | * @brief Look at the first item in the Queue. 233 | * Gets the first item from the Queue leaving it there. 234 | * @param var Variable to place the item 235 | * @param time How long to wait for an item to be available. 236 | * @return True if an item returned. 237 | */ 238 | bool peek(T& var, TickType_t time = 0) { 239 | return xQueuePeek(queueHandle, &var, time); 240 | } 241 | #if FREERTOSCPP_USE_CHRONO 242 | /** 243 | * @brief Look at the first item in the Queue. 244 | * Gets the first item from the Queue leaving it there. 245 | * @param var Variable to place the item 246 | * @param time How long to wait for an item to be available. 247 | * @return True if an item returned. 248 | */ 249 | bool peek(T& var, Time_ms time) { 250 | return xQueuePeek(queueHandle, &var, ms2ticks(time)); 251 | } 252 | #endif 253 | 254 | /** 255 | * @brief Push an item onto the Queue. 256 | * Puts an item onto the Queue so it will be the next item to remove. 257 | * 258 | * Note: Interrupt service routines should only call _ISR routines. 259 | * @param item The item to put on the Queue. 260 | * @param waswoken Flag variable to determine if context switch is needed. 261 | * @return True if successful 262 | */ 263 | bool push_ISR(T const& item, portBASE_TYPE& waswoken){ 264 | return xQueueSendToFrontFromISR(queueHandle, &item, &waswoken); 265 | } 266 | 267 | /** 268 | * @brief add an item at end of the Queue. 269 | * Puts an item onto the Queue so it will be the last item to remove. 270 | * 271 | * Note: Interrupt service routines should only call _ISR routines. 272 | * @param item The item to put on the Queue. 273 | * @param waswoken Flag variable to determine if context switch is needed. 274 | * @return True if successful 275 | */ 276 | bool add_ISR(T const& item, portBASE_TYPE& waswoken){ 277 | return xQueueSendToBackFromISR(queueHandle, &item, &waswoken); 278 | } 279 | 280 | /** 281 | * @brief Get an item from the Queue. 282 | * Gets the first item from the Queue 283 | * 284 | * Note: Interrupt service routines should only call _ISR routines. 285 | * @param var Variable to place the item 286 | * @param waswoken Flag variable to determine if context switch is needed. 287 | * @return True if an item returned. 288 | */ 289 | bool pop_ISR(T& var, portBASE_TYPE& waswoken) { 290 | return xQueueReceiveFromISR(queueHandle, &var, &waswoken); 291 | } 292 | 293 | /** 294 | * @brief Look at the first item in the Queue. 295 | * Gets the first item from the Queue leaving it there. 296 | * 297 | * Note: Interrupt service routines should only call _ISR routines. 298 | * @param var Variable to place the item 299 | * @param waswoken Flag variable to determine if context switch is needed. 300 | * @return True if an item returned. 301 | */ 302 | bool peek_ISR(T& var, portBASE_TYPE& waswoken) { 303 | return xQueuePeekFromISR(queueHandle, &var); 304 | } 305 | }; 306 | 307 | /** 308 | * @brief Queue Wrapper. 309 | * 310 | * Note, is a template on the type of object to place on the queue, 311 | * which makes the Queue more typesafe. 312 | * 313 | * @tparam T The type of object to be placed on the queue. 314 | * Note also, this type needs to be trivially copyable, and preferably a POD 315 | * as the FreeRTOS queue code will copy it with memcpy(). 316 | * @tparam queuelength The number of elements to reserve space for in the queue. 317 | * If 0 (which is the default value) then length will be provided to the constructor dynamically. 318 | * 319 | * @todo add Overwrite operation 320 | * @todo add QueueSet Functionality 321 | * @ingroup FreeRTOSCpp 322 | */ 323 | 324 | template class Queue : public QueueTypeBase { 329 | // static_assert(::std::is_pod, "Queues only work with PODs"); ///@todo need to get later version of C++ compile working 330 | public: 331 | /** 332 | * @brief Constructor. 333 | * @param name The name to register the Queue with. 334 | */ 335 | Queue(char const* name = 0) : 336 | QueueTypeBase( 337 | 338 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 339 | xQueueCreateStatic(queueLength, sizeof(T), reinterpret_cast(&queueStore), &queueBuff) 340 | #else 341 | xQueueCreate(queueLength, sizeof(T)) 342 | #endif 343 | ) 344 | { 345 | #if configQUEUE_REGISTRY_SIZE > 0 346 | if(name) 347 | vQueueAddToRegistry(this->queueHandle, name); 348 | #endif 349 | 350 | }; 351 | private: 352 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 353 | StaticQueue_t queueBuff; 354 | T queueStore[queueLength]; 355 | #endif 356 | }; 357 | 358 | #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) 359 | 360 | template class Queue : public QueueTypeBase { 361 | // static_assert(::std::is_pod, "Queues only work with PODs"); ///@todo need to get later version of C++ compile working 362 | public: 363 | /** 364 | * @brief Constructor. 365 | * @param length How many object to make room for in the Queue. 366 | * @param name The name to register the Queue with. 367 | */ 368 | Queue(unsigned portBASE_TYPE length, char const* name = 0) : 369 | QueueTypeBase(xQueueCreate(length, sizeof(T))) 370 | { 371 | #if configQUEUE_REGISTRY_SIZE > 0 372 | if(name) 373 | vQueueAddToRegistry(this->queueHandle, name); 374 | #endif 375 | 376 | }; 377 | 378 | }; 379 | #endif 380 | 381 | #if FREERTOSCPP_USE_NAMESPACE 382 | } // namespace FreeRTOScpp 383 | #endif 384 | 385 | #endif 386 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | FreeRTOScpp FreeRTOS C++ Wrappers 2 | --- 3 | 4 | FreeRTOScpp is a package that provides a light C++ wrapper for FreeRTOS (). 5 | 6 | It provides wrappers for the Task, Queue, Semaphore, and Mutex (including RecursiveMutex). 7 | 8 | I find the big advantage is that these allow me to declare these items as (part of) 9 | global objects, and then the items are automatically created and configured, without 10 | needing to change the main() function. 11 | 12 | They also provide member function style access for most of the basic operations 13 | on the items. 14 | -------------------------------------------------------------------------------- /ReadWrite.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ReadWrite.cpp 3 | * @brief FreeRTOS Read/Write Lock Wrapper 4 | * 5 | * This file contains a set of lightweight wrappers for mutexes using FreeRTOS 6 | * 7 | * @copyright (c) 2007-2024 Richard Damon 8 | * @author Richard Damon 9 | * @parblock 10 | * MIT License: 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy 13 | * of this software and associated documentation files (the "Software"), to deal 14 | * in the Software without restriction, including without limitation the rights 15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | * copies of the Software, and to permit persons to whom the Software is 17 | * furnished to do so, subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be included in 20 | * all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | * THE SOFTWARE. 29 | * 30 | * It is requested (but not required by license) that any bugs found or 31 | * improvements made be shared, preferably to the author. 32 | * @endparblock 33 | * 34 | * @ingroup FreeRTOSCpp 35 | */ 36 | 37 | #include 38 | 39 | #if FREERTOSCPP_USE_NAMESPACE 40 | namespace FreeRTOScpp { 41 | #endif 42 | 43 | /* 44 | Different events we can be waiting for. 45 | Right now minimal, might be able to expand bits so less tasks get woken prematurely 46 | */ 47 | constexpr unsigned read_bit = 1 << 0; 48 | constexpr unsigned write_bit = 1 << 1; 49 | 50 | bool Reader::take(TickType_t wait) { 51 | return static_cast(this)->readLock(wait); 52 | } 53 | 54 | bool Reader::give() { 55 | return static_cast(this)->readUnlock(); 56 | } 57 | 58 | bool Writer::take(TickType_t wait) { 59 | return static_cast(this)->writeLock(wait); 60 | } 61 | 62 | bool Writer::give() { 63 | return static_cast(this)->writeUnlock(); 64 | } 65 | 66 | ReadWriteLock::ReadWriteLock() { 67 | } 68 | 69 | ReadWriteLock::~ReadWriteLock() { 70 | } 71 | 72 | 73 | bool ReadWriteLock::readLock(TickType_t wait) { 74 | TickType_t start = xTaskGetTickCount(); 75 | while(1) { 76 | taskENTER_CRITICAL(); 77 | if(readCount >= 0 && (int)uxTaskPriorityGet(nullptr) > writeReq) { 78 | // Lock is granted, record that. 79 | readCount++; 80 | taskEXIT_CRITICAL(); 81 | return true; 82 | } 83 | taskEXIT_CRITICAL(); 84 | TickType_t now = xTaskGetTickCount(); 85 | if(now-start >= wait) { 86 | // Timed out. 87 | return false; 88 | } 89 | event.wait(read_bit, true, true, 1); 90 | } 91 | } 92 | 93 | 94 | bool ReadWriteLock::reservedLock(TickType_t wait) { 95 | TickType_t start = xTaskGetTickCount(); 96 | TaskHandle_t task = xTaskGetCurrentTaskHandle(); 97 | while(1) { 98 | taskENTER_CRITICAL(); 99 | if(readCount >= 0 && reserved == nullptr && (int)uxTaskPriorityGet(nullptr) > writeReq) { 100 | // Lock is granted, record that, reserve our ability to promote 101 | readCount++; 102 | reserved = task; 103 | taskEXIT_CRITICAL(); 104 | return true; 105 | } 106 | taskEXIT_CRITICAL(); 107 | TickType_t now = xTaskGetTickCount(); 108 | if(now-start >= wait) { 109 | // Timed out. 110 | return false; 111 | } 112 | event.wait(read_bit, true, true, 1); 113 | } 114 | } 115 | 116 | bool ReadWriteLock::requestReserved() { 117 | TaskHandle_t task = xTaskGetCurrentTaskHandle(); 118 | bool flag = false; 119 | taskENTER_CRITICAL(); 120 | if( readCount > 0 && reserved == nullptr) { 121 | reserved = task; 122 | flag = true; 123 | } 124 | taskEXIT_CRITICAL(); 125 | return flag; 126 | } 127 | 128 | bool ReadWriteLock::releaseReserved() { 129 | // Don't need a critical, as no one with change it to us 130 | if(xTaskGetCurrentTaskHandle() == reserved) { 131 | reserved = nullptr; 132 | // Signal read event as another task may be waiting on it. This might be able to be a different bit. 133 | event.set(read_bit); 134 | return true; 135 | } 136 | return false; 137 | } 138 | 139 | bool ReadWriteLock::readUnlock() { 140 | bool ret = true; 141 | // IF we had the reservation, clear it. 142 | if(xTaskGetCurrentTaskHandle() == reserved) { 143 | reserved = nullptr; 144 | // Signal read event as another task may be waiting on it. This might be able to be a different bit. 145 | event.set(read_bit); 146 | } 147 | taskENTER_CRITICAL(); 148 | if (readCount > 0) { 149 | readCount--; 150 | } else { 151 | // something is wrong with the unlock, as we aren't locked. 152 | ret = false; 153 | } 154 | if (readCount == 0) { 155 | reserved = nullptr; // just for safety. 156 | } 157 | taskEXIT_CRITICAL(); 158 | // Can be outside critical as false positive doesn't really hurt anything here. 159 | if (readCount == 0) { 160 | event.set(write_bit); 161 | } 162 | return ret; 163 | } 164 | 165 | bool ReadWriteLock::writeLock(TickType_t wait) { 166 | TaskHandle_t task = xTaskGetCurrentTaskHandle(); 167 | TickType_t start = xTaskGetTickCount(); 168 | int priority = uxTaskPriorityGet(nullptr); 169 | while(1) { 170 | taskENTER_CRITICAL(); 171 | if (0 <= readCount && readCount <= (reserved == task)) { 172 | readCount = -1; 173 | writeReq = -1; 174 | taskEXIT_CRITICAL(); 175 | return true; 176 | } 177 | taskEXIT_CRITICAL(); 178 | 179 | TickType_t now = xTaskGetTickCount(); 180 | if(now-start >= wait) { 181 | // clear writeReq if it might have been us. 182 | 183 | taskENTER_CRITICAL(); 184 | if (writeReq == priority) { 185 | writeReq = -1; 186 | taskEXIT_CRITICAL(); 187 | // We may have been blocking a reader, or removed another writers request. 188 | event.set(read_bit|write_bit); 189 | } else { 190 | taskEXIT_CRITICAL(); 191 | } 192 | return false; 193 | } 194 | 195 | taskENTER_CRITICAL(); 196 | // Update request priority if we are higher 197 | if (writeReq < priority) { 198 | writeReq = priority; 199 | } 200 | taskEXIT_CRITICAL(); 201 | 202 | event.wait(write_bit, true, true, 1); 203 | } 204 | } 205 | 206 | bool ReadWriteLock::writeUnlock() { 207 | // Assume we had the write lock until proven otherwise 208 | // no one else touches things if readCount is -1 209 | if (readCount >= 0) return false; // bad call 210 | if (reserved == xTaskGetCurrentTaskHandle()) { 211 | // We were reserved, convert the write lock to our previous reserved lock 212 | readCount = 1; 213 | } else { 214 | readCount = 0; 215 | } 216 | // Let other readers in, and notify writers so they can add their requests 217 | event.set(read_bit|write_bit); 218 | return true; 219 | } 220 | 221 | #if FREERTOSCPP_USE_NAMESPACE 222 | } 223 | #endif 224 | -------------------------------------------------------------------------------- /ReadWrite.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ReadWrite.h 3 | * @brief FreeRTOS Read/Write Lock Wrapper 4 | * 5 | * This file contains a set of lightweight wrappers for mutexes using FreeRTOS 6 | * 7 | * @warning This is a fairly new module, and may not be fully tested 8 | * 9 | * @copyright (c) 2007-2024 Richard Damon 10 | * @author Richard Damon 11 | * @parblock 12 | * MIT License: 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining a copy 15 | * of this software and associated documentation files (the "Software"), to deal 16 | * in the Software without restriction, including without limitation the rights 17 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | * copies of the Software, and to permit persons to whom the Software is 19 | * furnished to do so, subject to the following conditions: 20 | * 21 | * The above copyright notice and this permission notice shall be included in 22 | * all copies or substantial portions of the Software. 23 | * 24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 30 | * THE SOFTWARE. 31 | * 32 | * It is requested (but not required by license) that any bugs found or 33 | * improvements made be shared, preferably to the author. 34 | * @endparblock 35 | * 36 | * @ingroup FreeRTOSCpp 37 | */ 38 | 39 | #ifndef READWRITE_H 40 | #define READWRITE_H 41 | 42 | #include "EventCpp.h" 43 | #include "TaskCPP.h" 44 | #include "Lock.h" 45 | 46 | #if FREERTOSCPP_USE_NAMESPACE 47 | namespace FreeRTOScpp { 48 | #endif 49 | 50 | class ReadWriteLock; 51 | 52 | /** 53 | * Read-Write Lock Read Side Lockability Base 54 | * 55 | * Base class to provide Read side Lockability 56 | */ 57 | class Reader : public Lockable { 58 | friend class ReadWriteLock; 59 | private: 60 | Reader() {} 61 | public: 62 | bool take(TickType_t wait) override; 63 | bool give() override; 64 | }; 65 | 66 | /** 67 | * Read-Write Write Side Lockability Base 68 | */ 69 | class Writer : public Lockable { 70 | friend class ReadWriteLock; 71 | private: 72 | Writer() {} 73 | public: 74 | bool take(TickType_t wait) override; 75 | bool give() override; 76 | 77 | }; 78 | 79 | 80 | /** 81 | * Read/Write Lock control 82 | * 83 | * States: 84 | * + Free: readCount == 0 85 | * + Read: readCount > 0, reserved == 0 86 | * + Reserved: readCount > 0, reserved != 0 87 | * + Write: readCount == -1, reserved == 0 88 | * + Upgraded: readCount == -1, reserved != 0 89 | * 90 | * @dot 91 | digraph states { 92 | compound=true; 93 | rankdir="LR"; 94 | subgraph cluster_0 { 95 | Free; 96 | } 97 | 98 | subgraph cluster_1 { 99 | Read; 100 | Reserved; 101 | label="Read"; 102 | 103 | } 104 | 105 | subgraph cluster_2 { 106 | Write; 107 | Upgraded; 108 | label="Write"; 109 | } 110 | 111 | Free:w -> Read [color=green, label="readLock"]; 112 | Read -> Free:sw [color=red, label="readUnlock"]; 113 | Free:ne -> Reserved:se [color=green, label="reserveLock"]; 114 | Read:e -> Reserved:w [color=green, label="reserveRequest"]; 115 | Reserved:nw -> Read:ne [color=red, label="reserveRelease"]; 116 | Reserved:sw -> Free:nw [color=red, label="readUnlock"]; 117 | Free:e -> Write [color=green, label="writeLock"]; 118 | Reserved:e -> Upgraded:w [color=green, label="writeLock"]; 119 | Write -> Free:se [color=red, label="writeUnlock"]; 120 | Upgraded:nw -> Reserved:ne [color=red, label="writeUnlock"]; 121 | } 122 | * @enddot 123 | * @warning This is a fairly new module, and may not be fully tested 124 | */ 125 | class ReadWriteLock : public Reader, public Writer { 126 | public: 127 | ReadWriteLock(); 128 | ~ReadWriteLock(); 129 | 130 | /** 131 | * Get Read Lockable 132 | * 133 | * @returns a lockable object for using with Read Locks. 134 | */ 135 | Reader& rlock() { return *this; } 136 | /** 137 | * Get Write Lockable 138 | * 139 | * @returns a lockable object for using with Write Locks 140 | */ 141 | Writer& wlock() { return *this; } 142 | 143 | /** 144 | * ReadLock 145 | * 146 | * Get a read lock. 147 | * @param wait The maximum number of ticks to wait to get the lock 148 | * @returns true if the read lock has been granted 149 | * 150 | * Algorithm: 151 | * 152 | * + Loop 153 | * + If readCount >=0 and our priority > writeReq 154 | * + Increment readCount 155 | * + return true 156 | * + if Time has expired: 157 | * + return false 158 | * + else wait a tick for read_bit event. 159 | */ 160 | bool readLock(TickType_t wait = portMAX_DELAY); 161 | /** 162 | * Get an upgradable Read Lock 163 | * 164 | * like readLock, but add reserved == nullptr to the conditions. 165 | * On success will set reserved to our task handle. 166 | * 167 | * Only one task can reserve this, as if two are in this state they will deadlock when 168 | * they both try to upgrade 169 | */ 170 | bool reservedLock(TickType_t wait = portMAX_DELAY); 171 | /** 172 | * Task with a Read Lock request upgrade to a reserved lock. 173 | * If no reservation current, will be granted, if reservation present, will be rejected. 174 | * 175 | * Does not check if this task has a read lock, but that is assumed. 176 | */ 177 | bool requestReserved(); 178 | /** 179 | * If we have a reserved lock, down grade to just a read lock 180 | */ 181 | bool releaseReserved(); 182 | /** 183 | * Remove our lock. If we reserved the upgrade, release that. 184 | */ 185 | bool readUnlock(); 186 | 187 | /** 188 | * Take the write lock, requires readCount to be 0, or 1 if we reserved the upgrade. 189 | */ 190 | bool writeLock(TickType_t wait = portMAX_DELAY); 191 | /** 192 | * Release the write lock. If we upgraded go back to a reserved lock which will need to be unlocked. 193 | */ 194 | bool writeUnlock(); 195 | 196 | #if FREERTOSCPP_USE_CHRONO 197 | bool readLock(Time_ms delay_ms) { return readLock(ms2ticks(delay_ms)); } 198 | bool reservedLock(Time_ms delay_ms) { return reservedLock(ms2ticks(delay_ms)); } 199 | bool writeLock(Time_ms delay_ms) { return writeLock(ms2ticks(delay_ms)); } 200 | #endif 201 | protected: 202 | EventGroup event; 203 | /** 204 | * Count of Read Locks 205 | * 206 | * If 0, then lock is free 207 | * if >0, lock is in read mode and is the count of the number of read locks granted 208 | * if <0, loci is in write mode. 209 | */ 210 | int readCount = 0; 211 | /** 212 | * Reserved Lock indicator 213 | * 214 | * If nullptr, then no reservedLock are currently in existence, so a reservedLock can be granted 215 | * 216 | * Else, TaskHandle of the task that has reserved the right to upgrade to a write lock. 217 | */ 218 | TaskHandle_t reserved = nullptr; 219 | /** 220 | * Write Request Pending Priority. 221 | * 222 | * If in Read mode, and a task with priority below writeReq 223 | */ 224 | int writeReq = -1; 225 | }; 226 | 227 | #if FREERTOSCPP_USE_NAMESPACE 228 | } 229 | #endif 230 | 231 | #endif 232 | -------------------------------------------------------------------------------- /SemaphoreCPP.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file SemaphoreCPP.h 3 | * @brief FreeRTOS Semaphore Wrapper 4 | * 5 | * This file contains a set of lightweight wrappers for semaphores using FreeRTOS 6 | * 7 | * @copyright (c) 2007-2024 Richard Damon 8 | * @author Richard Damon 9 | * @parblock 10 | * MIT License: 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy 13 | * of this software and associated documentation files (the "Software"), to deal 14 | * in the Software without restriction, including without limitation the rights 15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | * copies of the Software, and to permit persons to whom the Software is 17 | * furnished to do so, subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be included in 20 | * all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | * THE SOFTWARE. 29 | * 30 | * It is requested (but not required by license) that any bugs found or 31 | * improvements made be shared, preferably to the author. 32 | * @endparblock 33 | * 34 | * @todo Add Counting Semaphores 35 | * @ingroup FreeRTOSCpp 36 | */ 37 | 38 | #ifndef SEMAPHORE_CPP_H 39 | #define SEMAPHORE_CPP_H 40 | 41 | #include "FreeRTOScpp.h" 42 | #include "Lock.h" 43 | #include "FreeRTOS.h" 44 | #include "semphr.h" 45 | 46 | #if FREERTOSCPP_USE_NAMESPACE 47 | namespace FreeRTOScpp { 48 | #endif 49 | 50 | 51 | /** 52 | * @brief Binary Semaphore Wrapper. 53 | * 54 | * Example Usage: 55 | * @code 56 | * Semaphore sema("MySema"); 57 | * 58 | * // In some task 59 | * sema.give(); 60 | * 61 | * // In some other task 62 | * sema.take(); 63 | * 64 | * // In some ISR 65 | * 66 | * portBASE_TYPE woken = 0; 67 | * ... 68 | * sema.give_ISR(woken); 69 | * ... 70 | * portYIELD_FROM_ISR(woken); 71 | * return; 72 | * 73 | * @endcode 74 | * @ingroup FreeRTOSCpp 75 | */ 76 | 77 | class BinarySemaphore : public Lockable { 78 | public: 79 | /** 80 | * @brief Constructor. 81 | * @param name Name to give semaphore, used for Debug Registry if setup 82 | */ 83 | BinarySemaphore(char const* name = nullptr) { 84 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 85 | sema = xSemaphoreCreateBinaryStatic(&semaBuffer); 86 | #else 87 | sema = xSemaphoreCreateBinary(); 88 | #endif 89 | #if configQUEUE_REGISTRY_SIZE > 0 90 | if(name) 91 | vQueueAddToRegistry(sema, name); 92 | #endif 93 | } 94 | /** 95 | * @brief Destructor. 96 | * 97 | * Delete the semaphore. 98 | */ 99 | ~BinarySemaphore() { 100 | vQueueDelete(sema); 101 | } 102 | /** 103 | * @brief Give the Semaphore. 104 | */ 105 | bool give() override { 106 | return xSemaphoreGive(sema); 107 | } 108 | 109 | /** 110 | * @brief Take the semaphore. 111 | * 112 | * @param delay The number of ticks to wait for the semaphore 113 | */ 114 | bool take(TickType_t delay = portMAX_DELAY) override { 115 | return xSemaphoreTake(sema, delay); 116 | } 117 | bool take_ISR(portBASE_TYPE& waswoken) { 118 | return xSemaphoreTakeFromISR(sema, &waswoken); 119 | } 120 | 121 | #if FREERTOSCPP_USE_CHRONO 122 | /** 123 | * @brief Take the semaphore. 124 | * 125 | * @param delay The number of ticks to wait for the semaphore 126 | */ 127 | bool take(Time_ms delay){ 128 | return xSemaphoreTake(sema, ms2ticks(delay)); 129 | } 130 | #endif 131 | /** 132 | * @brief Give the Semaphore inside an ISR 133 | * 134 | * @param waswoken The flag variable used to indicate if we need to run the 135 | * scheduler when we exit the ISR. 136 | */ 137 | bool give_ISR(portBASE_TYPE& waswoken) { 138 | return xSemaphoreGiveFromISR(sema, &waswoken); 139 | } 140 | private: 141 | SemaphoreHandle_t sema; 142 | 143 | #if __cplusplus < 201101L 144 | Semaphore(Semaphore const&); ///< We are not copyable. 145 | void operator =(Semaphore const&); ///< We are not assignable. 146 | #else 147 | BinarySemaphore(BinarySemaphore const&) = delete; ///< We are not copyable. 148 | void operator =(BinarySemaphore const&) = delete; ///< We are not assignable. 149 | #endif // __cplusplus 150 | 151 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 152 | StaticSemaphore_t semaBuffer; 153 | #endif 154 | 155 | }; 156 | 157 | typedef BinarySemaphore Semaphore [[deprecated("Rename to BinarySemaphore")]]; 158 | #if FREERTOSCPP_USE_NAMESPACE 159 | } // namespace FreeRTOScpp 160 | #endif 161 | 162 | 163 | #endif 164 | -------------------------------------------------------------------------------- /StreamBufferCPP.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file StreamBufferCPP.h 3 | * @brief FreeRTOS Streambuffer wrapper 4 | * 5 | * @copyright (c) 2024 Richard Damon 6 | * @author Richard Damon 7 | * @parblock 8 | * MIT License: 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | * 28 | * It is requested (but not required by license) that any bugs found or 29 | * improvements made be shared, preferably to the author. 30 | * @endparblock 31 | * 32 | * @ingroup FreeRTOSCpp 33 | */ 34 | 35 | #ifndef STREAMBUFFER_CPP_H 36 | #define STREAMBUFFER_CPP_H 37 | 38 | #include "FreeRTOScpp.h" 39 | 40 | #include "stream_buffer.h" 41 | 42 | #if FREERTOSCPP_USE_NAMESPACE 43 | namespace FreeRTOScpp { 44 | #endif 45 | 46 | /** 47 | * @brief Base class for the Various Stream Buffers 48 | * 49 | * This class provides all the generic operations. 50 | * 51 | * The derived class will create the buffer, or can be created as a wrapper from an existing streambuffer. 52 | */ 53 | class StreamBufferBase { 54 | public: 55 | StreamBufferBase(StreamBufferHandle_t sbHandle) : streamHandle(sbHandle) {} 56 | virtual ~StreamBufferBase() { } 57 | 58 | size_t send(const void* data, size_t len, TickType_t delay = portMAX_DELAY) 59 | {return xStreamBufferSend(streamHandle, data, len, delay);} 60 | #if FREERTOSCPP_USE_CHRONO 61 | size_t send(const void* data, size_t len, Time_ms delay) 62 | {return xStreamBufferSend(streamHandle, data, len, ms2ticks(delay));} 63 | #endif 64 | size_t send_ISR(const void* data, size_t len, BaseType_t &wasWoken) 65 | {return xStreamBufferSendFromISR(streamHandle, data, len, &wasWoken);} 66 | 67 | size_t read(void* data, size_t len, TickType_t delay = portMAX_DELAY) 68 | {return xStreamBufferReceive(streamHandle, data, len, delay);} 69 | #if FREERTOSCPP_USE_CHRONO 70 | size_t read(void* data, size_t len, Time_ms delay) 71 | {return xStreamBufferReceive(streamHandle, data, len, ms2ticks(delay));} 72 | #endif 73 | size_t read_ISR(void* data, size_t len, BaseType_t &wasWoken) 74 | {return xStreamBufferReceiveFromISR(streamHandle, data, len, &wasWoken);} 75 | 76 | /// @brief Get number of bytes of data available in the StreamBuffer 77 | /// @return The number of bytes that can be read 78 | size_t waiting() const { return xStreamBufferBytesAvailable(streamHandle);} 79 | 80 | /// @brief Get the amount of available space open in the StreamBuffer 81 | /// @return The number of bytes that can be sent before the buffer is full 82 | size_t available() const { return xStreamBufferSpacesAvailable(streamHandle);} 83 | 84 | bool isEmpty() const { return xStreamBufferIsEmpty(streamHandle);} 85 | 86 | bool isFull() const { return xStreamBufferIsFull(streamHandle);} 87 | 88 | /// @brief Resets the buffer to empty 89 | /// @return True if done, stream can not be reset if a task is waiting on the StreamBuffer. 90 | bool reset() { return xStreamBufferReset(streamHandle);} 91 | 92 | /// @brief Sets the Trigger Level for the StreamBuffer 93 | /// @param trigger the Trigger Level 94 | /// @return If trigger level was set (false means trigger bigger than the buffer size) 95 | bool trigger(size_t trigger) { return xStreamBufferSetTriggerLevel(streamHandle, trigger);} 96 | 97 | StreamBufferHandle_t streamHandle; 98 | }; 99 | 100 | /** 101 | * StreamBuffer wrapper 102 | * 103 | * @tparam size The size of the stream buffer, 0 for dynamically created 104 | */ 105 | template 110 | class StreamBuffer : public StreamBufferBase { 111 | public: 112 | StreamBuffer(size_t trigger = 1) : 113 | StreamBufferBase( 114 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 115 | xStreamBufferCreateStatic(size, trigger, storage, streamBuff) 116 | #else 117 | xStreamBufferCreate(size, trigger) 118 | #endif 119 | ) {} 120 | virtual ~StreamBuffer() { vStreamBufferDelete(streamHandle);} 121 | 122 | #if configUSE_SB_COMPLETED_CALLBACK 123 | StreamBuffer(size_t trigger, StreamBufferCallbackFunction_t sendCallback, StreamBufferCallbackFunction_t recvCallback) : 124 | StreamBufferBase( 125 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 126 | xStreamBufferCreateStaticWithCallback(size, trigger, storage, streamBuff, sendCallback, recvCallback) 127 | #else 128 | xStreamBufferCreateWithCallback(size, trigger, sendCallback. recvCallBack) 129 | #endif 130 | ) 131 | {} 132 | #endif //configUSE_SB_COMPLETED_CALLBACK 133 | 134 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 135 | uint8_t storage[size+1]; 136 | StaticStreamBuffer_t streamBuff; 137 | #endif 138 | }; 139 | 140 | #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) 141 | 142 | /** 143 | * Dynamically created StreamBuffer 144 | */ 145 | template <> 146 | class StreamBuffer<0> : public StreamBufferBase { 147 | public: 148 | StreamBuffer(size_t size, size_t trigger=1) : 149 | StreamBufferBase(xStreamBufferCreate(size, trigger)) 150 | {} 151 | #if configUSE_SB_COMPLETED_CALLBACK 152 | StreamBuffer(size_t size, size_t trigger, StreamBufferCallbackFunction_t sendCallback, StreamBufferCallbackFunction_t recvCallback) : 153 | StreamBufferBase(xStreamBufferCreateWithCallback(size, trigger, sendCallback, recvCallback)) 154 | {} 155 | #endif // configUSE_SB_COMPLETED_CALLBACK 156 | }; 157 | #endif 158 | 159 | #if FREERTOS_VERSION_ALL >= 11'001'000 160 | // Version 11.1.0 added StraamBatchBuffer Varient 161 | 162 | /** 163 | * BatchingBuffer variant wrapper 164 | * 165 | * Batching buffers are like normal streambuffers but don't return partial buffer 166 | * until the timeout period has expired even if some data is available. 167 | */ 168 | template 173 | class BatchingBuffer : public StreamBufferBase { 174 | public: 175 | BatchingBuffer(size_t trigger = 1) : 176 | StreamBufferBase( 177 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 178 | xStreamBatchingBufferCreateStatic(size, trigger, storage, streamBuff) 179 | #else 180 | xStreamBatchingBufferCreate(size, trigger) 181 | #endif 182 | ) {} 183 | virtual ~BatchBuffer() { vStreamBufferDelete(streamHandle);} 184 | #if configUSE_SB_COMPLETED_CALLBACK 185 | BatchingBuffer(size_t trigger, StreamBufferCallbackFunction_t sendCallback, StreamBufferCallbackFunction_t recvCallback) : 186 | StreamBufferBase( 187 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 188 | xStreamBatchingBufferCreateStaticWithCallback(size, trigger, storage, streamBuff, sendCallback, recvCallback) 189 | #else 190 | xStreamBatchingBufferCreateWithCallback(size, trigger, sendCallback. recvCallBack) 191 | #endif 192 | ) 193 | {} 194 | #endif //configUSE_SB_COMPLETED_CALLBACK 195 | 196 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 197 | uint8_t storage[size+1]; 198 | StaticStreamBuffer_t streamBuff; 199 | #endif 200 | }; 201 | 202 | #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) 203 | /** 204 | * Dynamically Created BatchingBuffer wrapper. 205 | */ 206 | 207 | template <> 208 | class BatchingBuffer<0> : public StreamBufferBase { 209 | public: 210 | BatchingBuffer(size_t size, size_t trigger=1) : 211 | StreamBufferBase(xStreamBatchingBufferCreate(size, trigger)) 212 | {} 213 | virtual ~BatchingBuffer() { vStreamBufferDelete(streamHandle);} 214 | #if configUSE_SB_COMPLETED_CALLBACK 215 | BatchingBuffer(size_t size, size_t trigger, StreamBufferCallbackFunction_t sendCallback, StreamBufferCallbackFunction_t recvCallback) : 216 | StreamBatchingBufferBase(xStreamBufferCreateWithCallback(size, trigger, sendCallback, recvCallback)) 217 | {} 218 | #endif // configUSE_SB_COMPLETED_CALLBACK 219 | }; 220 | #endif 221 | #endif 222 | 223 | #if FREERTOSCPP_USE_NAMESPACE 224 | } 225 | #endif 226 | 227 | #endif -------------------------------------------------------------------------------- /TaskCPP.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file TaskCPP.h 3 | * @brief FreeRTOS Task Wrapper 4 | * 5 | * This file contains a set of lightweight wrappers for tasks using FreeRTOS 6 | * 7 | * @copyright (c) 2007-2024 Richard Damon 8 | * @author Richard Damon 9 | * @parblock 10 | * MIT License: 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy 13 | * of this software and associated documentation files (the "Software"), to deal 14 | * in the Software without restriction, including without limitation the rights 15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | * copies of the Software, and to permit persons to whom the Software is 17 | * furnished to do so, subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be included in 20 | * all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | * THE SOFTWARE. 29 | * 30 | * It is requested (but not required by license) that any bugs found or 31 | * improvements made be shared, preferably to the author. 32 | * @endparblock 33 | * 34 | * @ingroup FreeRTOSCpp 35 | * 36 | * Tasks are built with a selction of options: 37 | * 38 | * Task Function Type: 39 | * + Simple void fun(void* parm); 40 | * + task memberfuncion of a derived class 41 | * 42 | * TasK Allocation: 43 | * + Static (specified by a template parameter) 44 | * + Dynamic (specified by that template parameter being 0) 45 | * + Static with suppied stack 46 | * 47 | * @todo Look at options to create "restricted" tasks with xTaskCreateRestricted 48 | * Basically needs another parrallel construciton of this tree. 49 | */ 50 | 51 | #ifndef TaskCPP_H 52 | #define TaskCPP_H 53 | 54 | #include "FreeRTOScpp.h" 55 | 56 | extern "C" { 57 | extern void taskcpp_task_thunk(void*); 58 | } 59 | 60 | #if FREERTOSCPP_USE_NAMESPACE 61 | namespace FreeRTOScpp { 62 | #endif 63 | 64 | 65 | /** 66 | * @brief Names for Base set of Priorities. 67 | * 68 | * Assigns used based names to priority levels, optimized for configMAX_PRIORITIES = 6 for maximal distinctions 69 | * with reasonable collapsing for smaller values. If configMAX_PRIORITIES is >6 then some values won't have names here, but 70 | * values could be created and cast to the enum type. 71 | * 72 | * | configMAX_PRIORITIES: | 1 | 2 | 3 | 4 | 5 | 6 | N>6 | Use | 73 | * | --------------------: | - | - | - | - | - | - | :-: | :------------------------------------------------- | 74 | * | TaskPrio_Idle | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Non-Real Time operations, Tasks that don't block | 75 | * | TaskPrio_Low | 0 | 1 | 1 | 1 | 1 | 1 | 1 | Non-Critical operations | 76 | * | TaskPrio_HMI | 0 | 1 | 1 | 1 | 1 | 2 | 2 | Normal User Interface | 77 | * | TaskPrio_Mid | 0 | 1 | 1 | 2 | 2 | 3 | N/2 | Semi-Critical, Deadlines, not much processing | 78 | * | TaskPrio_High | 0 | 1 | 2 | 3 | 3 | 4 | N-2 | Urgent, Short Deadlines, not much processing | 79 | * | TaskPrio_Highest | 0 | 1 | 2 | 3 | 4 | 5 | N-1 | Critical, do NOW, must be quick (Used by FreeRTOS) | 80 | * 81 | * @ingroup FreeRTOSCpp 82 | */ 83 | enum TaskPriority { 84 | TaskPrio_Idle = 0, ///< Non-Real Time operations. tasks that don't block 85 | TaskPrio_Low = ((configMAX_PRIORITIES)>1), ///< Non-Critical operations 86 | TaskPrio_HMI = (TaskPrio_Low + ((configMAX_PRIORITIES)>5)), ///< Normal User Interface Level 87 | TaskPrio_Mid = ((configMAX_PRIORITIES)/2), ///< Semi-Critical, have deadlines, not a lot of processing 88 | TaskPrio_High = ((configMAX_PRIORITIES)-1-((configMAX_PRIORITIES)>4)), ///< Urgent tasks, short deadlines, not much processing 89 | TaskPrio_Highest = ((configMAX_PRIORITIES)-1) ///< Critical Tasks, Do NOW, must be quick (Used by FreeRTOS) 90 | }; 91 | 92 | /** 93 | * Allow adjment to Task Priority. 94 | * 95 | * Mostly for configMAX_PRIORITIES > 6 96 | */ 97 | constexpr TaskPriority operator+(TaskPriority p, int offset) { 98 | configASSERT((static_cast(p) + offset) >= 0); 99 | configASSERT((static_cast(p) + offset) < configMAX_PRIORITIES); 100 | return static_cast(static_cast(p) + offset); 101 | } 102 | 103 | /** 104 | * Allow adjment to Task Priority. 105 | * 106 | * Mostly for configMAX_PRIORITIES > 6 107 | */ 108 | constexpr TaskPriority operator-(TaskPriority p, int offset) { 109 | configASSERT((static_cast(p) - offset) >= 0); 110 | configASSERT((static_cast(p) - offset) < configMAX_PRIORITIES); 111 | return static_cast(static_cast(p) - offset); 112 | } 113 | 114 | /** 115 | * @brief Lowest Level Wrapper. 116 | * Create the specified task with a provided task function. 117 | * 118 | * If the TaskBase object is destroyed, the FreeRTOS Task will be deleted (if deletion has been enabled) 119 | * @ingroup FreeRTOSCpp 120 | * @todo Fully implement task manipulation functions 121 | * 122 | * @ingroup FreeRTOSCpp 123 | */ 124 | 125 | class TaskBase { 126 | protected: 127 | /** 128 | * @brief Default Constructor: Needs a subclass to fill in the handle later, so protected. 129 | */ 130 | 131 | TaskBase() : taskHandle(nullptr) {} 132 | 133 | public: 134 | /** 135 | * @brief Constructor 136 | * 137 | */ 138 | TaskBase(TaskHandle_t handle) : taskHandle(handle) { 139 | 140 | } 141 | 142 | /** 143 | * @brief Destructor. 144 | * 145 | * If deletion is enabled, delete the task. 146 | */ 147 | virtual ~TaskBase() { 148 | #if INCLUDE_vTaskDelete 149 | if(taskHandle){ 150 | vTaskDelete(taskHandle); 151 | } 152 | #endif 153 | return; 154 | } 155 | /** 156 | * @brief Get Task Handle. 157 | * @return the task handle. 158 | */ 159 | TaskHandle_t getTaskHandle() const { return taskHandle; } 160 | /** 161 | * @brief Delay for a period of time 162 | * @param time the number of ticks to delay 163 | * 164 | * This is a static member function as it affects the CALLING task, not the task it might be called on 165 | */ 166 | static void delay(TickType_t time) { vTaskDelay(time); } 167 | #if FREERTOSCPP_USE_CHRONO 168 | /** 169 | * @brief Delay for a period of time, specified in milliseconds 170 | * @param ms The number of milliseconds to delay 171 | * 172 | * This is a static member function as it affects the CALLING task, not the task it might be called on 173 | */ 174 | static void delay(Time_ms ms) { vTaskDelay(ms2ticks(ms)); } 175 | #endif 176 | 177 | #if INCLUDE_xTaskDelayUntil 178 | /** 179 | * @brief Delay a periodic task 180 | * @param prev The time the last unblock was scheduled to happen 181 | * @param time The time in ticks to unblock next. If all calls use the same value, this will cause the task to run at 182 | * the given period with long term stablity. 183 | * @returns true if delay happend (false if fallen behind and no delay occured) 184 | * 185 | * Delays the task until the time mark prev + time. 186 | * 187 | * @code 188 | * TickType_t last = xTaskGetTickCount() 189 | * while(1) { 190 | * // Wait for the next cycle 191 | * bool delayed = delayUntil(last, 5); 192 | * // Do the work for the cycle 193 | * // if delayed is false, we have fallen behind, so delay didn't actually delay any time 194 | * // so possibly skip some processing 195 | * } 196 | * @endcode 197 | */ 198 | static bool delayUntil(TickType_t& prev, TickType_t time) { return xTaskDelayUntil(&prev, time);} 199 | #if FREERTOSCPP_USE_CHRONO 200 | /** 201 | * @brief Delay a periodic task 202 | * @param prev The time the last unblock was scheduled to happen 203 | * @param ms The time in milli-seconds to unblock next. If all calls use the same value, this will cause the task to run at 204 | * the given period with long term stablity. 205 | * @returns true if delay happend (false if fallen behind and no delay occured) 206 | * 207 | * Delays the task until the time mark prev + ms. 208 | * 209 | * @code 210 | * TickType_t last = xTaskGetTickCount() 211 | * while(1) { 212 | * // Wait for the next cycle 213 | * bool delayed = delayUntil(last, 100_ms); 214 | * // Do the work for the cycle 215 | * // if delayed is false, we have fallen behind, so delay didn't actually delay any time 216 | * // so possibly skip some processing 217 | * } 218 | * @endcode 219 | */ 220 | static bool delayUntil(TickType_t& prev, Time_ms ms) { return xTaskDelayUntil(&prev, ms2ticks(ms)); } 221 | #endif 222 | #elif INCLUDE_vTaskDelayUntil 223 | /** 224 | * @brief Delay a periodic task 225 | * @param prev The time the last unblock was scheduled to happen 226 | * @param time The time in ticks to unblock next. If all calls use the same value, this will cause the task to run at 227 | * the given period with long term stablity. 228 | * 229 | * Delays the task until the time mark prev + time. 230 | * 231 | * @code 232 | * TickType_t last = xTaskGetTickCount() 233 | * while(1) { 234 | * // Wait for the next cycle 235 | * delayUntil(last, 5); 236 | * // Do the work for the cycle 237 | * } 238 | * @endcode 239 | */ 240 | static void delayUntil(TickType_t& prev, TickType_t time) { vTaskDelay(&prev, time); } 241 | #if FREERTOSCPP_USE_CHRONO 242 | /** 243 | * @brief Delay a periodic task 244 | * @param prev The time the last unblock was scheduled to happen 245 | * @param ms The time in milli-seconds to unblock next. If all calls use the same value, this will cause the task to run at 246 | * the given period with long term stablity. 247 | * 248 | * Delays the task until the time mark prev + ms. 249 | * 250 | * @code 251 | * TickType_t last = xTaskGetTickCount() 252 | * while(1) { 253 | * // Wait for the next cycle 254 | * delayUntil(last, 5); 255 | * // Do the work for the cycle 256 | * } 257 | * @endcode 258 | */ 259 | static void delayUntil(TickType_t& prev, Time_ms ms) { vTaskDelay(&prev, ms2ticks(ms)); } 260 | #endif 261 | #endif 262 | 263 | #if INCLUDE_xTaskAbortDelay 264 | /** 265 | * @brief Abort the Delay of a Task. 266 | * @returns true if the task was blocking. 267 | */ 268 | bool abortDelay() { return xTaskAbortDelay(taskHandle); } 269 | #endif 270 | 271 | #if INCLUDE_uxTaskPriorityGet 272 | /** 273 | * @brief Get Task priority 274 | * 275 | * Only available if INCLUDE_vTaskPriorityGet == 1 276 | * @return The priority of the Task. 277 | */ 278 | TaskPriority priority() const { return static_cast(uxTaskPriorityGet(taskHandle)); } 279 | #endif 280 | 281 | #if INCLUDE_vTaskPrioritySet 282 | /** 283 | * @brief Set Task priority 284 | * 285 | * Only available if INCLUDE_vTaskPrioritySet == 1 286 | * @param priority_ The TaskPriority to give the Task. 287 | */ 288 | void priority(TaskPriority priority_) { vTaskPrioritySet(taskHandle, priority_); } 289 | #endif 290 | 291 | #if INCLUDE_vTaskSuspend 292 | /** 293 | * @brief Suspend the Task. 294 | * 295 | * Only available if INCLUDE_vTaskSuspend == 1 296 | */ 297 | void suspend() { vTaskSuspend(taskHandle); } 298 | 299 | /** 300 | * @brief Resume the Task. 301 | * 302 | * Only available if INCLUDE_vTaskSuspend == 1 303 | */ 304 | void resume() { vTaskResume(taskHandle); } 305 | # endif 306 | 307 | # if INCLUDE_xTaskResumeFromISR 308 | /** 309 | * @brief Resume task from ISR. 310 | * 311 | * Note: Only functions with _ISR should be used inside Interupt service routines. 312 | * 313 | * Only available if INCLUDE_vTaskSuspend == 1 and INCLUDE_vTaskResumeFromISR == 1 314 | * @returns True if ISR should request a context switch. 315 | */ 316 | bool resume_ISR() { return xTaskResumeFromISR(taskHandle); } 317 | #endif 318 | 319 | /** 320 | * @brief Notify a Task. 321 | * 322 | * Generic Task Notification operation 323 | */ 324 | bool notify(uint32_t value, eNotifyAction act) 325 | { return xTaskNotify(taskHandle, value, act); } 326 | bool notify_ISR(uint32_t value, eNotifyAction act, portBASE_TYPE& waswoken) 327 | { return xTaskNotifyFromISR(taskHandle, value, act, &waswoken);} 328 | bool notify_query(uint32_t value, eNotifyAction act, uint32_t &old) 329 | {return xTaskNotifyAndQuery(taskHandle, value, act, &old); } 330 | bool notify_query_ISR(uint32_t value, eNotifyAction act, uint32_t &old, portBASE_TYPE& waswoken) 331 | {return xTaskNotifyAndQueryFromISR(taskHandle, value, act, &old, &waswoken); } 332 | #if FREERTOS_VERSION_ALL >= 10'004'000 333 | bool notifyIndex(UBaseType_t idx, uint32_t value, eNotifyAction act) 334 | { return xTaskNotifyIndexed(taskHandle, idx, value, act); } 335 | bool notifyIndex_ISR(UBaseType_t idx, uint32_t value, eNotifyAction act, portBASE_TYPE& waswoken) 336 | { return xTaskNotifyIndexedFromISR(taskHandle, idx, value, act, &waswoken);} 337 | bool notifyIndex_query(UBaseType_t idx, uint32_t value, eNotifyAction act, uint32_t &old) 338 | {return xTaskNotifyAndQueryIndexed(taskHandle, idx, value, act, &old); } 339 | bool notifyIndex_query_ISR(UBaseType_t idx, uint32_t value, eNotifyAction act, uint32_t &old, portBASE_TYPE& waswoken) 340 | {return xTaskNotifyAndQueryIndexedFromISR(taskHandle, idx, value, act, &old, &waswoken); } 341 | #endif 342 | 343 | #if FREERTOS_VERSION_ALL >= 10'003'000 344 | bool notifyStateClear() { return xTaskNotifyStateClear(taskHandle); } 345 | uint32_t notifyValueClear(uint32_t bits) { return ulTaskNotifyValueClear(taskHandle, bits); } 346 | #if FREERTOS_VERSION_ALL >= 10'004'000 347 | bool notifyStateClearIndex(UBaseType_t idx) { return xTaskNotifyStateClearIndexed(taskHandle, idx); } 348 | uint32_t notifyValueClearIndex(UBaseType_t idx, uint32_t bits) { return ulTaskNotifyValueClearIndexed(taskHandle, idx, bits); } 349 | #endif 350 | #endif 351 | /** 352 | * @brief Notify a Task as a semaphore 353 | * 354 | * Sends a notification to a task using a semaphore based protocol. Generally the task should we using 355 | * the take() function to receive the notification. 356 | */ 357 | bool give() { return xTaskNotifyGive(taskHandle); } 358 | void give_ISR(portBASE_TYPE& waswoken) 359 | { vTaskNotifyGiveFromISR(taskHandle, &waswoken); } 360 | 361 | #if FREERTOS_VERSION_ALL >= 10'004'000 362 | bool giveIndex(UBaseType_t idx) { return xTaskNotifyGiveIndexed(taskHandle, idx); } 363 | void giveIndex_ISR(UBaseType_t idx, portBASE_TYPE& waswoken) 364 | { vTaskNotifyGiveIndexedFromISR(taskHandle, idx, &waswoken); } 365 | #endif 366 | // Static as always affect the current (calling) task 367 | /** 368 | * @brief Wait for task notification. 369 | */ 370 | static uint32_t wait(uint32_t clearEnter, uint32_t clearExit = 0xFFFFFFFF, uint32_t* value = nullptr, TickType_t ticks = portMAX_DELAY) 371 | { return xTaskNotifyWait(clearEnter, clearExit, value, ticks); } 372 | #if FREERTOSCPP_USE_CHRONO 373 | static uint32_t wait(uint32_t clearEnter, uint32_t clearExit, uint32_t* value, Time_ms ms) 374 | { return xTaskNotifyWait(clearEnter, clearExit, value, ms2ticks(ms)); } 375 | #endif 376 | #if FREERTOS_VERSION_ALL >= 10'004'000 377 | static uint32_t waitIndex(UBaseType_t idx, uint32_t clearEnter, uint32_t clearExit = 0xFFFFFFFF, uint32_t* value = nullptr, TickType_t ticks = portMAX_DELAY) 378 | { return xTaskNotifyWaitIndexed(idx, clearEnter, clearExit, value, ticks); } 379 | #if FREERTOSCPP_USE_CHRONO 380 | static uint32_t waitIndex(UBaseType_t idx, uint32_t clearEnter, uint32_t clearExit, uint32_t* value, Time_ms ms) 381 | { return xTaskNotifyWaitIndexed(idx, clearEnter, clearExit, value, ms2ticks(ms)); } 382 | #endif // FREERTOSCPP_USE_CHRONO 383 | #endif // FREERTOS_VERSION_ALL >= 10'004'000 384 | 385 | /** 386 | * @brief Wait for a task Give notification 387 | * 388 | * Specialized wait() designed to work with the give()/give_ISR() notifications. 389 | * 390 | * @param clear Flag to indicate if the action on succesful take is to clear (True) or decrement (False) the notification value. 391 | * Effectively decides between a binary (True) or counting (False) semaphore behavior. 392 | * 393 | * @param ticks The time to wait for the semaphore. 394 | * 395 | * @returns Returns the notification word (prior to being adjusted for the take() ), Will be zero if 396 | * the take() timed out. 397 | */ 398 | static uint32_t take(bool clear = true, TickType_t ticks = portMAX_DELAY) 399 | { return ulTaskNotifyTake(clear, ticks); } 400 | #if FREERTOSCPP_USE_CHRONO 401 | /** 402 | * @brief Wait for a task Give notification 403 | * 404 | * Specialized wait() designed to work with the give()/give_ISR() notifications. 405 | * 406 | * @param clear Flag to indicate if the action on successful take is to clear (True) or decrement (False) the notification value. 407 | * Effectively decides between a binary (True) or counting (False) semaphore behavior. 408 | * 409 | * @param ticks The time to wait for the semaphore. 410 | * 411 | * @returns Returns the notification word (prior to being adjusted for the take() ), Will be zero if 412 | * the take() timed out. 413 | */ 414 | static uint32_t take(bool clear, Time_ms ticks) 415 | { return ulTaskNotifyTake(clear, ms2ticks(ticks)); } 416 | #endif 417 | protected: 418 | TaskHandle_t taskHandle; ///< Handle for the task we are managing. 419 | 420 | private: 421 | #if __cplusplus < 201101L 422 | TaskBase(TaskBase const&); ///< We are not copyable. 423 | void operator =(TaskBase const&); ///< We are not assignable. 424 | #else 425 | TaskBase(TaskBase const&) = delete; ///< We are not copyable. 426 | void operator =(TaskBase const&) = delete; ///< We are not assignable. 427 | #endif // __cplusplus 428 | 429 | }; 430 | 431 | /** 432 | * @brief Statically Created Task Wrapper. 433 | * Create the specified task with a provided task function. 434 | * 435 | * @tparam stackDepth Size of the stack to give to the task 436 | * 437 | * If the Task object is destroyed, the class will be deleted (if deletion has been enabled) 438 | * @ingroup FreeRTOSCpp 439 | */ 440 | 441 | template class TaskS : public TaskBase { 446 | public: 447 | /** 448 | * @brief Constructor. 449 | * 450 | * @param name The name of the task. 451 | * @param taskfun The function implementing the task, should have type void (*taskfun)(void *) 452 | * @param priority_ The priority of the task. Use the TaskPriority enum values or a related value converted to a TaskPriority 453 | * @param myParm the parameter passed to taskFun. Defaults to NULL. 454 | * 455 | * Upon construction the task will be created. 456 | * 457 | */ 458 | TaskS(char const*name, void (*taskfun)(void *), TaskPriority priority_, void * myParm = 0) : 459 | TaskBase() { 460 | 461 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 462 | taskHandle = xTaskCreateStatic(taskfun, name, stackDepth, myParm, priority_, stack, &tcb); 463 | #else 464 | xTaskCreate(taskfun, name, stackSize, myParm, priority_, &taskHandle); 465 | #endif 466 | } 467 | 468 | private: 469 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 470 | StaticTask_t tcb; 471 | StackType_t stack[stackDepth]; 472 | #endif 473 | }; 474 | 475 | 476 | /** 477 | * @brief Dynamically Created Task Wrapper 478 | */ 479 | #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) 480 | 481 | template<> class TaskS<0> : public TaskBase { 482 | public: 483 | /** 484 | * @brief Constructor. 485 | * 486 | * @param name The name of the task. 487 | * @param taskfun The function implementing the task, should have type void (*taskfun)(void *) 488 | * @param priority_ The priority of the task. Use the TaskPriority enum values or a related value converted to a TaskPriority 489 | * @param stackSize Size of the stack to give to the task 490 | * @param myParm the parameter passed to taskFun. Defaults to NULL. 491 | * 492 | * Upon construction the task will be created. 493 | * 494 | */ 495 | TaskS(char const*name, void (*taskfun)(void *), TaskPriority priority_, 496 | unsigned portSHORT stackSize, void * myParm = nullptr) : 497 | TaskBase() { 498 | xTaskCreate(taskfun, name, stackSize, myParm, priority_, &taskHandle); 499 | } 500 | }; 501 | 502 | typedef TaskS<0> Task; 503 | #endif 504 | 505 | /** 506 | * @brief Base Class for all Class based tasks. 507 | */ 508 | class TaskClassBase { 509 | public: 510 | TaskClassBase() {} 511 | ~TaskClassBase() {} 512 | /** 513 | * @brief task function. 514 | * The member function task needs to 515 | */ 516 | virtual void task() = 0; 517 | 518 | }; 519 | 520 | /** 521 | * @brief Make a class based task. 522 | * Derive from TaskClass and the 'task()' member function will get called as the task based on the class. 523 | * 524 | * @tparam stackDepth Size of the stack to give to the task 525 | * 526 | * If task() returns the task will be deleted if deletion has been enabled. 527 | * @ingroup FreeRTOSCpp 528 | */ 529 | 530 | template class TaskClassS : public TaskClassBase, public TaskS { 531 | public: 532 | /** 533 | * @brief Constructor 534 | * 535 | * @param name The name of the task. 536 | * @param priority_ The priority of the task. Use the TaskPriority enum values or a related value converted to a TaskPriority 537 | * @param stackDepth_ How many words of stack to allocate to the task. Only used if the template parameter stackDepth is 0 538 | * 539 | * API CHANGE! 540 | * If at constrtuction time, the scheduler is not running, we can release the task. If the scheduler is running, because 541 | * the task may startup before we finish constructing the task, the most derived constructor will need to give the task. 542 | * 543 | * Change from previous API to support SMP mode where the previous trick won't work anymore. 544 | */ 545 | TaskClassS(char const*name, TaskPriority priority_, unsigned portSHORT stackDepth_=0) : 546 | TaskS(name, &taskcpp_task_thunk, priority_, static_cast(this)) 547 | { 548 | (void) stackDepth_; 549 | // API CHANGE: We give if Scheduer not running, otherwise final constructor needs to give. 550 | if(xTaskGetSchedulerState() != taskSCHEDULER_RUNNING) { 551 | this->TaskBase::give(); 552 | } 553 | } 554 | 555 | virtual ~TaskClassS() {} 556 | 557 | /** 558 | * @brief task function. 559 | * The member function task needs to 560 | */ 561 | void task() override = 0; 562 | 563 | }; 564 | 565 | 566 | #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) 567 | template<> class TaskClassS<0> : public TaskClassBase, public TaskS<0> { 568 | public: 569 | /** 570 | * @brief Constructor 571 | * 572 | * @param name The name of the task. 573 | * @param priority_ The priority of the task. Use the TaskPriority enum values or a related value converted to a TaskPriority 574 | * @param stackDepth_ How many words of stack to allocate to the task. Only used if the template parameter stackDepth is 0 575 | * 576 | * API CHANGE! 577 | * If at constrtuction time, the scheduler is not running, we can release the task. If the scheduler is running, because 578 | * the task may startup before we finish constructing the task, the most derived constructor will need to give the task. 579 | * 580 | * Change from previous API to support SMP mode where the previous trick won't work anymore. 581 | */ 582 | TaskClassS(char const*name, TaskPriority priority_, unsigned portSHORT stackDepth_) : 583 | TaskS<0>(name, &taskcpp_task_thunk, priority_, stackDepth_, static_cast(this)) 584 | { 585 | // API CHANGE: We give if Scheduer not running, otherwise final constructor needs to give. 586 | if(xTaskGetSchedulerState() != taskSCHEDULER_RUNNING) { 587 | this->TaskBase::give(); 588 | } 589 | } 590 | 591 | virtual ~TaskClassS() {} 592 | 593 | /** 594 | * @brief task function. 595 | * The member function task needs to 596 | */ 597 | void task() override = 0; 598 | 599 | }; 600 | 601 | typedef TaskClassS<0> TaskClass; 602 | #endif 603 | 604 | #if FREERTOSCPP_USE_NAMESPACE 605 | } // namespace FreeRTOScpp 606 | #endif 607 | 608 | #endif 609 | -------------------------------------------------------------------------------- /TaskCpp.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file TaskCpp.cpp 3 | * @brief FreeRTOS Task Wrapper 4 | * 5 | * @copyright (c) 2018-2024 Richard Damon 6 | * @author Richard Damon 7 | * @parblock 8 | * MIT License: 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | * 28 | * It is requested (but not required by license) that any bugs found or 29 | * improvements made be shared, preferably to the author. 30 | * @endparblock 31 | * 32 | * @ingroup FreeRTOSCpp 33 | */ 34 | 35 | 36 | #include "TaskCpp.h" 37 | 38 | #if FREERTOSCPP_USE_NAMESPACE 39 | using namespace FreeRTOScpp; 40 | #endif 41 | 42 | extern "C" { 43 | 44 | /** 45 | * Thunk for FreeRTOS to C++ Task Wrapper 46 | */ 47 | void taskcpp_task_thunk(void* parm) { 48 | TaskClassBase *myClass = static_cast(parm); 49 | TaskBase::take(); 50 | myClass->task(); 51 | #if INCLUDE_vTaskDelete 52 | vTaskDelete(nullptr); 53 | #else 54 | while(1) { 55 | vTaskDelay(portMAX_DELAY); 56 | } 57 | #endif 58 | } 59 | } // extern "C" 60 | -------------------------------------------------------------------------------- /TimerCPP.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file TimerCPP.h 3 | * @brief FreeRTOS Timer Wrapper 4 | * 5 | * This file contains a set of lightweight wrappers for tasks using FreeRTOS 6 | * 7 | * @copyright (c) 2016-2024 Richard Damon 8 | * @author Richard Damon 9 | * @parblock 10 | * MIT License: 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy 13 | * of this software and associated documentation files (the "Software"), to deal 14 | * in the Software without restriction, including without limitation the rights 15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | * copies of the Software, and to permit persons to whom the Software is 17 | * furnished to do so, subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be included in 20 | * all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | * THE SOFTWARE. 29 | * 30 | * It is requested (but not required by license) that any bugs found or 31 | * improvements made be shared, preferably to the author. 32 | * @endparblock 33 | * 34 | * @ingroup FreeRTOSCpp 35 | * 36 | */ 37 | 38 | #ifndef FREERTOS_FREERTOSPP_TIMERCPP_H 39 | #define FREERTOS_FREERTOSPP_TIMERCPP_H 40 | 41 | #include "FreeRTOScpp.h" 42 | #include "FreeRTOS.h" 43 | #include "timers.h" 44 | 45 | #if FREERTOSCPP_USE_NAMESPACE 46 | namespace FreeRTOScpp { 47 | #endif 48 | 49 | /** 50 | * @ingroup FreeRTOSCpp 51 | */ 52 | class Timer { 53 | public: 54 | Timer(char const* name_, void(*func)(TimerHandle_t handle), TickType_t period_, bool reload, bool start_) : 55 | timerHandle( 56 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 57 | xTimerCreateStatic(name_, period_, reload, this, func, &timerBuffer) 58 | #else 59 | xTimerCreate(name_, period_, reload, this, func) 60 | #endif 61 | ) 62 | { 63 | if(start_) start(); 64 | } 65 | 66 | #if FREERTOSCPP_USE_CHRONO 67 | Timer(char const* name_, void(*func)(TimerHandle_t handle), Time_ms period_, bool reload, bool start_) : 68 | timerHandle( 69 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 70 | xTimerCreateStatic(name_, ms2ticks(period_), reload, this, func, &timerBuffer) 71 | #else 72 | xTimerCreate(name_, ms2ticks(period_), reload, this, func) 73 | #endif 74 | ) 75 | { 76 | if(start_) start(); 77 | } 78 | #endif // FREERTOSCPP_USE_CHRONO 79 | 80 | virtual ~Timer() {xTimerDelete(timerHandle, portMAX_DELAY); } 81 | 82 | bool active() { return xTimerIsTimerActive(timerHandle); } 83 | TickType_t expiryTime() { return xTimerGetExpiryTime(timerHandle); } // TODO Time_ms versions? 84 | const char* name() { return pcTimerGetName(timerHandle); } 85 | TickType_t period() { return xTimerGetPeriod(timerHandle); } 86 | bool period(TickType_t period_, TickType_t wait = portMAX_DELAY) { configASSERT(period_ > 0); return xTimerChangePeriod(timerHandle, period_, wait);} 87 | #if FREERTOSCPP_USE_CHRONO 88 | bool period(Time_ms period_, TickType_t wait = portMAX_DELAY) { configASSERT(ms2ticks(period_) > 0); return xTimerChangePeriod(timerHandle, ms2ticks(period_), wait);} 89 | bool period(Time_ms period_, Time_ms wait) { configASSERT(ms2ticks(period_) > 0); return xTimerChangePeriod(timerHandle, ms2ticks(period_), ms2ticks(wait));} 90 | #endif 91 | bool periodISR(TickType_t period_, portBASE_TYPE& waswoken) { configASSERT(period_ > 0); return xTimerChangePeriodFromISR(timerHandle, period_, &waswoken); } 92 | #if FREERTOSCPP_USE_CHRONO 93 | bool periodISR(Time_ms period_, portBASE_TYPE& waswoken) { configASSERT(ms2ticks(period_) > 0); return xTimerChangePeriodFromISR(timerHandle, ms2ticks(period_), &waswoken); } 94 | #endif 95 | bool reset(TickType_t wait = portMAX_DELAY) { return xTimerReset(timerHandle, wait); } 96 | #if FREERTOSCPP_USE_CHRONO 97 | bool reset(Time_ms wait) { return xTimerReset(timerHandle, ms2ticks(wait)); } 98 | #endif 99 | bool resetISR(portBASE_TYPE& waswoken) { return xTimerResetFromISR(timerHandle, &waswoken); } 100 | 101 | bool start(TickType_t wait = portMAX_DELAY) { return xTimerStart(timerHandle, wait); } 102 | #if FREERTOSCPP_USE_CHRONO 103 | bool start(Time_ms wait) { return xTimerStart(timerHandle, ms2ticks(wait)); } 104 | #endif 105 | bool startISR(portBASE_TYPE& waswoken) { return xTimerStartFromISR(timerHandle, &waswoken); } 106 | 107 | bool stop(TickType_t wait = portMAX_DELAY) { return xTimerStop(timerHandle, wait); } 108 | #if FREERTOSCPP_USE_CHRONO 109 | bool stop(Time_ms wait) { return xTimerStop(timerHandle, ms2ticks(wait)); } 110 | #endif 111 | bool stopISR(portBASE_TYPE& waswoken) { return xTimerStopFromISR(timerHandle, &waswoken); } 112 | 113 | #if FREERTOS_VERSION >= 10'002'000 114 | void reload(bool reload) { vTimerSetReloadMode( timerHandle, reload); } 115 | #endif 116 | 117 | protected: 118 | TimerHandle_t timerHandle; 119 | 120 | private: 121 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 122 | StaticTimer_t timerBuffer; 123 | #endif 124 | }; 125 | 126 | class TimerClass : public Timer { 127 | public: 128 | TimerClass(char const* name_, TickType_t period_, bool reload) : 129 | Timer(name_, &timerClassCallback, period_, reload, false) // Do not start in Timer, our parents constructor needs to do it. 130 | {} 131 | 132 | virtual void timer() = 0; // Function called on timer activation 133 | private: 134 | static void timerClassCallback(TimerHandle_t timerHandle) { 135 | TimerClass* me = static_cast(pvTimerGetTimerID(timerHandle)); 136 | me->timer(); 137 | } 138 | }; 139 | 140 | /** 141 | * @ingroup FreeRTOSCpp 142 | */ 143 | template class TimerMember : public TimerClass { 144 | public: 145 | TimerMember(char const* name_, T* obj_, void (T::*func_)(), TickType_t period_, UBaseType_t reload) : 146 | TimerClass(name_, period_, reload), 147 | obj(obj_), 148 | func(func_) 149 | {} 150 | virtual void timer() { (obj->*func)();} 151 | private: 152 | T* obj; 153 | void (T::*func)(); 154 | }; 155 | 156 | #if FREERTOSCPP_USE_NAMESPACE 157 | } // namespace FreeRTOScpp 158 | #endif 159 | 160 | 161 | #endif /* FREERTOS_FREERTOSPP_TIMERCPP_H_ */ 162 | --------------------------------------------------------------------------------