Meco Man 4 лет назад
Родитель
Сommit
0de4de3d4e
74 измененных файлов с 9788 добавлено и 0 удалено
  1. 130 0
      addons/README.md
  2. 119 0
      addons/c++/ccondition_variable.cpp
  3. 149 0
      addons/c++/cevent_groups.cpp
  4. 207 0
      addons/c++/cmem_pool.cpp
  5. 127 0
      addons/c++/cmutex.cpp
  6. 213 0
      addons/c++/cqueue.cpp
  7. 226 0
      addons/c++/cread_write_lock.cpp
  8. 144 0
      addons/c++/csemaphore.cpp
  9. 128 0
      addons/c++/ctasklet.cpp
  10. 272 0
      addons/c++/cthread.cpp
  11. 108 0
      addons/c++/ctickhook.cpp
  12. 169 0
      addons/c++/ctimer.cpp
  13. 207 0
      addons/c++/cworkqueue.cpp
  14. 139 0
      addons/c++/include/condition_variable.hpp
  15. 144 0
      addons/c++/include/critical.hpp
  16. 307 0
      addons/c++/include/event_groups.hpp
  17. 292 0
      addons/c++/include/mem_pool.hpp
  18. 305 0
      addons/c++/include/mutex.hpp
  19. 351 0
      addons/c++/include/queue.hpp
  20. 285 0
      addons/c++/include/read_write_lock.hpp
  21. 238 0
      addons/c++/include/semaphore.hpp
  22. 214 0
      addons/c++/include/tasklet.hpp
  23. 462 0
      addons/c++/include/thread.hpp
  24. 158 0
      addons/c++/include/tickhook.hpp
  25. 113 0
      addons/c++/include/ticks.hpp
  26. 292 0
      addons/c++/include/timer.hpp
  27. 54 0
      addons/c++/include/version.hpp
  28. 247 0
      addons/c++/include/workqueue.hpp
  29. 313 0
      addons/c/UnitTests/Dlist/main.c
  30. 183 0
      addons/c/UnitTests/Queue/main.c
  31. 314 0
      addons/c/UnitTests/Slist/main.c
  32. 176 0
      addons/c/UnitTests/Stack/main.c
  33. 131 0
      addons/c/dlist.c
  34. 213 0
      addons/c/include/dlist.h
  35. 139 0
      addons/c/include/mem_pool.h
  36. 81 0
      addons/c/include/queue_simple.h
  37. 116 0
      addons/c/include/read_write_lock.h
  38. 200 0
      addons/c/include/slist.h
  39. 106 0
      addons/c/include/stack_simple.h
  40. 53 0
      addons/c/include/version.h
  41. 122 0
      addons/c/include/workqueue.h
  42. 113 0
      addons/c/include/zero_copy_queue.h
  43. 360 0
      addons/c/mem_pool.c
  44. 83 0
      addons/c/queue_simple.c
  45. 459 0
      addons/c/read_write_lock.c
  46. 209 0
      addons/c/slist.c
  47. 84 0
      addons/c/stack_simple.c
  48. 384 0
      addons/c/workqueue.c
  49. 146 0
      addons/c/zero_copy_queue.c
  50. 0 0
      changelog.md
  51. 0 0
      kernel/event_groups.c
  52. 0 0
      kernel/fmq.c
  53. 0 0
      kernel/heap.c
  54. 0 0
      kernel/include/FreeRTOS.h
  55. 0 0
      kernel/include/StackMacros.h
  56. 0 0
      kernel/include/croutine.h
  57. 0 0
      kernel/include/deprecated_definitions.h
  58. 0 0
      kernel/include/event_groups.h
  59. 0 0
      kernel/include/list.h
  60. 0 0
      kernel/include/mpu_wrappers.h
  61. 0 0
      kernel/include/portable.h
  62. 0 0
      kernel/include/portmacro.h
  63. 0 0
      kernel/include/projdefs.h
  64. 0 0
      kernel/include/queue.h
  65. 0 0
      kernel/include/semphr.h
  66. 0 0
      kernel/include/task.h
  67. 0 0
      kernel/include/timers.h
  68. 0 0
      kernel/list.c
  69. 0 0
      kernel/port.c
  70. 0 0
      kernel/port_tick.c
  71. 0 0
      kernel/queue.c
  72. 0 0
      kernel/tasks.c
  73. 0 0
      kernel/timers.c
  74. 3 0
      readme.md

+ 130 - 0
addons/README.md

@@ -0,0 +1,130 @@
+# freertos-addons
+
+After working with FreeRTOS for over 8 years now, I've decided to start adding features and implementations that I wish would have been there at the beginning. 
+
+## Current Features
++ C++ Wrappers [![Coverity Scan Build Status](https://scan.coverity.com/projects/9669/badge.svg)](https://scan.coverity.com/projects/michaelbecker-freertos-addons)
+  - A collection of C++ wrappers encapsulating FreeRTOS functionality, allowing you to write your RTOS application in C++ while still using FreeRTOS. This wrapper layer does all the integration work for you.
+  - This library is for you if you are planning on using C++ and FreeRTOS in your project but don't want to spend the time integrating the two.
+  - Everything was tested successfully using FreeRTOS versions 8.2.3, 9.0.0, and 10.0.0.
+  - There are numerous demo / unit test projects using these wrappers and various features they provide. Last count we are at 48 Demo projects showing how you might use the C++ Wrapper library.
+  - Licensing now follows the [MIT Open Source License](https://opensource.org/licenses/MIT), the same as [FreeRTOS](https://www.freertos.org/a00114.html) starting from version 10.0.0.
+  - [Project web page](http://michaelbecker.github.io/freertos-addons/)
+  - [Full cross-referenced documentation](http://michaelbecker.github.io/freertos-addons/cppdocs/html/index.html). Documents were auto-generated and cross-referenced using Doxygen.
+
+
++ C Add-on Wrappers
+  - A collection of C Add-on functionality for FreeRTOS. Right now these consist of:
+  - Memory Pools: Fixed size memory allocation buffers. Using these elminates the possibility of memory fragmentation. There is overhead associated with these, so it's better if you are maximizing the size of each allocation.
+  - Reader / Writer Locks: These allow multiple threads to simultaneously access a shared resource all as readers. If something needs to change, then a Writer lock needs to be taken which will allow a singe thread to modify the shared resource.
+  - Workqueues: These allow you to queue "work" (i.e. a function) to a different thread. Useful if you have a lot of "one off" things that need to be done in different threads but they happen very asynchronous.
+  - Licensing now follows the [MIT Open Source License](https://opensource.org/licenses/MIT), the same as [FreeRTOS](https://www.freertos.org/a00114.html) starting from version 10.0.0.
+  - There are numerous demo / unit test projects using these wrappers and various features they provide. Last count we are at 10 Demo projects showing how you might use the C libraries.
+  - In addition, to support these there are implementations of standard optimized compter science singly linked lists, doubly linked circular lists, queues, and stacks.
+  - [Full cross-referenced documentation](http://michaelbecker.github.io/freertos-addons/cdocs/html/index.html). Documents were auto-generated and cross-referenced using Doxygen.
+
+
++ Updated Linux port
+  - Licensing is GPLv2, because this is a derivative work.
+  - An update of the Linux / POSIX port of FreeRTOS, for testing and debugging on a Linux PC.
+  - This update was tested successfully with FreeRTOS 8.2.3, 9.0.0, and 10.0.0 
+  - Two Ubuntu workstations were also used, running 18.04, 16.04 and 14.04, 64-bit multicore machines. 
+  - This revised Posix port I renamed to Linux port, since I ended up using a few Linux specific APIs in it.
+  - Thanks to William Davy who wrote the original Posix FreeRTOS port. He did amazing work simulating a real-time system under Linux.
+
+
+## Overall Releases
+
+### Version 1.6.0
++ https://github.com/michaelbecker/freertos-addons/releases/tag/v1.6.0
++ C++ Wrappers 1.6.0:
+  - Merged in Event Groups work from Danilo Pucci Smokovitz (dnlps@hotmail.com)
+  - Updated license to MIT.
+  - Updated doxygen documentation.
++ C Add-ons 1.1.0:
+  - Fixed bugs in Memory Pools.
+  - Added initial implementation of Zero Copy queues.
+  - Updated license to MIT.
+  - Updated doxygen documentation.
++ Linux Port
+  - Merged in some of the work done by KKoovalsky to handle cleanup better. This does not solve all issues. See https://github.com/michaelbecker/freertos-addons/issues/14 for details.
+
+### Version 1.5.1
++ https://github.com/michaelbecker/freertos-addons/releases/tag/v1.5.1
++ C++ Wrappers 1.5.0:
+  - Added alignment requirements to memory pools.
+  - Updated doxygen documentation.
++ C Add-ons 1.0.1:
+  - Added static allocated fixed size memory pools.
+  - Updated doxygen documentation.
+
+### Version 1.5.0
++ Starting to independently version the overall project vs the unique packages within it.
++ https://github.com/michaelbecker/freertos-addons/releases/tag/v1.5.0
++ Added new major feature, C Add-ons. This is version 1.0.0 of the C Add-ons.
++ C Add-ons include:
+  - Fixed size memory pools
+  - Read / Write locks
+  - Work queues
+
+### Version 1.4.0
++ https://github.com/michaelbecker/freertos-addons/releases/tag/v1.4.0
++ Added new feature, fixed size memory pools and associated unit tests.
+
+### Version 1.3.2
++ https://github.com/michaelbecker/freertos-addons/releases/tag/v1.3.2
++ Bug fixes to 1.3.1 regarding the critical section wrapper. Code prior to this version in critical.hpp will not compile successfully. 
++ Added a Demo project using straight C and the updated Linux simulator only.
+
+### Version 1.3.1
++ https://github.com/michaelbecker/freertos-addons/releases/tag/v1.3.1
++ Bug fixes to 1.3.0, related to defining vTaskDelete to 0, as well as needing to make the Timer class's dtor virtual. Many thanks to Ewout Boks from the HAN technical college, Arnhem, the Netherlands for finding these.
+
+### Version 1.3.0
++ https://github.com/michaelbecker/freertos-addons/releases/tag/v1.3.0
++ Added preprocessor variable "CPP_FREERTOS_NO_CPP_STRINGS". If you do not want to use C++ strings, simply define this in your makefile or project. Note that if you define this, you must also define "CPP_FREERTOS_NO_EXCEPTIONS". Some classes throw exceptions if they cannot be constructed, and the exceptions they throw depend of C++ strings.
++ Added an implementation of condition variables. These are not enabled by default. To use, define "CPP_FREERTOS_CONDITION_VARIABLES". Also include the files condition_variable.hpp and ccondition_variable.cpp in your project.
+
+### Version 1.2.0
++ https://github.com/michaelbecker/freertos-addons/releases/tag/v1.2.0
++ Adding preprocessor flag to exclude exceptions for smaller footprint and C++ compilers that do not support them.
++ Updated license to one similar to FreeRTOS version. What does that mean for you? It means you are free to use FreeRTOS C++ Wrappers in your commercial product without making your product open source.
+
+### Version 1.1.0
++ https://github.com/michaelbecker/freertos-addons/releases/tag/v1.1.0
++ Adding object oriented work queues.
++ Coverity scan analysis performed, with bug fixes.
+  - See: https://scan.coverity.com/projects/michaelbecker-freertos-addons
+
+### Version 1.0.2
++ https://github.com/michaelbecker/freertos-addons/releases/tag/v1.0.2
++ Fixed a major bug in Thread creation.
+  - See: https://www.linkedin.com/pulse/apples-kumquats-perils-multi-threaded-polymorphism-michael-becker
+
+### Version 1.0.1
++ https://github.com/michaelbecker/freertos-addons/releases/tag/v1.0.1
++ Changed license from GPLv3 to GPLv2 (or later) to accomodate FreeRTOS's modified GPLv2 license.
++ See https://www.gnu.org/licenses/gpl-faq.html#AllCompatibility for more information.
+
+### Version 1.0.0
++ https://github.com/michaelbecker/freertos-addons/releases/tag/v1.0.0
++ Initial release.
+
+## TODO
+
+This is my todo list for this project. If there's something you'd like to see done sooner, feel free to make a request.
+
+### FreeRTOS Features Not Yet Implemented
++ events
++ MPU restricted threads
++ eTaskGetState
++ uxTaskGetNumberOfTasks
++ uxTaskGetStackHighWaterMark
++ Thread Local Storage
+
+### New Value Added
++ In Timers, add OnStop / OnStart / mutex sync with these methods?
++ Priority queues
++ Tick Hooks - option to round robin hooks, one per tick
+
+

+ 119 - 0
addons/c++/ccondition_variable.cpp

@@ -0,0 +1,119 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+
+
+#include "condition_variable.hpp"
+#include "thread.hpp"
+
+
+#ifdef CPP_FREERTOS_CONDITION_VARIABLES
+
+
+using namespace cpp_freertos;
+
+
+ConditionVariable::ConditionVariable()
+    : Lock(), WaitList()
+{
+}
+
+
+void ConditionVariable::AddToWaitList(Thread *thread)
+{
+    //
+    //  Lock the internal condition variable state
+    //
+    Lock.Lock();
+
+    //
+    //  Add the thread to the condition variable wait list.
+    //
+    WaitList.push_back(thread);
+
+    //
+    //  Drop the internal condition variable lock.
+    //
+    Lock.Unlock();
+}
+
+
+void ConditionVariable::Signal()
+{
+    //
+    //  Lock the internal condition variable state
+    //
+    Lock.Lock();
+
+    if ( !WaitList.empty() ) {
+
+        Thread *thr = WaitList.front();
+        WaitList.pop_front();
+        thr->Signal();
+    }
+
+    //
+    //  Drop the internal condition variable lock.
+    //
+    Lock.Unlock();
+}
+
+
+void ConditionVariable::Broadcast()
+{
+    //
+    //  Lock the internal condition variable state
+    //
+    Lock.Lock();
+
+    while ( !WaitList.empty() ) {
+
+        Thread *thr = WaitList.front();
+        WaitList.pop_front();
+        thr->Signal();
+    }
+
+    //
+    //  Drop the internal condition variable lock.
+    //
+    Lock.Unlock();
+}
+
+#endif
+

+ 149 - 0
addons/c++/cevent_groups.cpp

@@ -0,0 +1,149 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Danilo Pucci Smokovitz (dnlps@hotmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+#include "event_groups.hpp"
+
+
+using namespace cpp_freertos;
+
+
+EventGroup::EventGroup()
+{
+    handle = xEventGroupCreate();
+
+    if (handle == NULL) {
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+        throw EventGroupCreateException();
+#else
+        configASSERT(!"EventGroup Constructor Failed");
+#endif
+    }
+
+}
+
+
+#if( configSUPPORT_STATIC_ALLOCATION == 1 )
+
+EventGroup::EventGroup(StaticEventGroup_t *pxEventGroupBuffer)
+{
+    handle = xEventGroupCreateStatic(pxEventGroupBuffer);
+
+    if (handle == NULL) {
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+        throw EventGroupCreateException();
+#else
+        configASSERT(!"EventGroup Constructor Failed");
+#endif
+    }
+}
+
+#endif /* configSUPPORT_STATIC_ALLOCATION */
+
+
+EventGroup::~EventGroup()
+{
+    vEventGroupDelete(handle);
+}
+
+
+EventBits_t EventGroup::Sync(   const EventBits_t uxBitsToSet,
+                                const EventBits_t uxBitsToWaitFor,
+                                TickType_t xTicksToWait)
+{
+
+    return xEventGroupSync( handle,
+                            uxBitsToSet,
+                            uxBitsToWaitFor,
+                            xTicksToWait);
+
+}
+
+
+EventBits_t EventGroup::WaitBits(   const EventBits_t uxBitsToWaitFor,
+                                    bool xClearOnExit,
+                                    bool xWaitForAllBits,
+                                    TickType_t xTicksToWait)
+{
+
+    return xEventGroupWaitBits( handle,
+                                uxBitsToWaitFor,
+                                xClearOnExit ? pdTRUE : pdFALSE,
+                                xWaitForAllBits ? pdTRUE : pdFALSE,
+                                xTicksToWait);
+}
+
+
+EventBits_t EventGroup::ClearBits(const EventBits_t uxBitsToClear)
+{
+    return xEventGroupClearBits(handle, uxBitsToClear);
+}
+
+
+BaseType_t EventGroup::ClearBitsFromISR(const EventBits_t uxBitsToClear)
+{
+    return xEventGroupClearBitsFromISR(handle, uxBitsToClear);
+}
+
+
+EventBits_t EventGroup::GetBits()
+{
+    return xEventGroupGetBits(handle);
+}
+
+
+EventBits_t EventGroup::GetBitsFromISR()
+{
+    return xEventGroupGetBitsFromISR(handle);
+}
+
+
+EventBits_t EventGroup::SetBits(const EventBits_t uxBitsToSet)
+{
+    return xEventGroupSetBits(handle, uxBitsToSet);
+}
+
+
+#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )
+
+BaseType_t EventGroup::SetBitsFromISR(const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken)
+{
+    return xEventGroupSetBitsFromISR(handle, uxBitsToSet, pxHigherPriorityTaskWoken);
+}
+
+#endif
+
+

+ 207 - 0
addons/c++/cmem_pool.cpp

@@ -0,0 +1,207 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+
+
+#include <stdlib.h>
+#include "mem_pool.hpp"
+
+
+using namespace cpp_freertos;
+
+
+void MemoryPool::CalculateValidAlignment()
+{
+    /**
+     *  Guarantee that the alignment is the size of a pointer.
+     */
+    if (Alignment < (int)sizeof(unsigned char *)) {
+        Alignment = (int)sizeof(unsigned char *);
+    }
+
+    int alignmentBit = 0x1;
+    int i;
+
+    for (i = 0; i < 31; i++) {
+        if (Alignment == alignmentBit) {
+            break;
+        }
+        alignmentBit <<= 1;
+    }
+
+    if (i >= 31) {
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+        throw MemoryPoolBadAlignmentException();
+#else
+        configASSERT(!"MemoryPool Bad Alignment");
+#endif
+    }
+}
+
+
+void MemoryPool::CalculateItemSize()
+{
+    if (ItemSize <= Alignment) {
+
+        ItemSize = Alignment;
+    }
+    else {
+
+        int alignmentCount = ItemSize / Alignment;
+        if (ItemSize % Alignment != 0) {
+            alignmentCount++;
+        }
+
+        ItemSize = alignmentCount * Alignment;
+    }
+}
+
+
+MemoryPool::MemoryPool( int itemSize,
+                        int itemCount,
+                        int alignment)
+    : ItemSize(itemSize),
+      Alignment(alignment)
+{
+    CalculateValidAlignment();
+
+    CalculateItemSize();
+
+    unsigned char *address = (unsigned char *)malloc(ItemSize * itemCount);
+
+    if (address == NULL) {
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+        throw MemoryPoolMallocException();
+#else
+        configASSERT(!"MemoryPool malloc Failed");
+#endif
+    }
+
+    for (int i = 0; i < itemCount; i++) {
+        FreeItems.push_back(address);
+        address += ItemSize;
+    }
+
+    Lock = new MutexStandard();
+}
+
+
+MemoryPool::MemoryPool( int itemSize,
+                        void *preallocatedMemory,
+                        int preallocatedMemorySize,
+                        int alignment)
+    : ItemSize(itemSize),
+      Alignment(alignment)
+{
+    CalculateValidAlignment();
+
+    CalculateItemSize();
+
+    unsigned char *address = (unsigned char *)preallocatedMemory;
+
+    while (preallocatedMemorySize >= ItemSize) {
+
+        FreeItems.push_back(address);
+        address += ItemSize;
+        preallocatedMemorySize -= ItemSize;
+    }
+
+    Lock = new MutexStandard();
+}
+
+
+void *MemoryPool::Allocate()
+{
+    LockGuard guard(*Lock);
+
+    if (FreeItems.empty())
+        return NULL;
+
+    void *item = FreeItems.front();
+    FreeItems.pop_front();
+
+    return item;
+}
+
+
+void MemoryPool::Free(void *item)
+{
+    LockGuard guard(*Lock);
+    FreeItems.push_back(item);
+}
+
+
+void MemoryPool::AddMemory(int itemCount)
+{
+    unsigned char *address = (unsigned char *)malloc(ItemSize * itemCount);
+
+    if (address == NULL) {
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+        throw MemoryPoolMallocException();
+#else
+        configASSERT(!"MemoryPool AddMemory Failed");
+#endif
+    }
+
+    for (int i = 0; i < itemCount; i++) {
+
+        LockGuard guard(*Lock);
+
+        FreeItems.push_back(address);
+        address += ItemSize;
+    }
+}
+
+
+void MemoryPool::AddMemory( void *preallocatedMemory,
+                            int preallocatedMemorySize)
+{
+    unsigned char *address = (unsigned char *)preallocatedMemory;
+
+    while (preallocatedMemorySize >= ItemSize) {
+
+        LockGuard guard(*Lock);
+
+        FreeItems.push_back(address);
+        address += ItemSize;
+        preallocatedMemorySize -= ItemSize;
+    }
+}
+
+

+ 127 - 0
addons/c++/cmutex.cpp

@@ -0,0 +1,127 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#include "mutex.hpp"
+
+
+using namespace cpp_freertos;
+
+
+Mutex::Mutex()
+{
+}
+
+
+Mutex::~Mutex()
+{
+    vSemaphoreDelete(handle);
+}
+
+
+MutexStandard::MutexStandard()
+{
+    handle = xSemaphoreCreateMutex();
+
+    if (handle == NULL) {
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+        throw MutexCreateException();
+#else
+        configASSERT(!"Mutex Constructor Failed");
+#endif
+    }
+}
+
+
+bool MutexStandard::Lock(TickType_t Timeout)
+{
+    BaseType_t success = xSemaphoreTake(handle, Timeout);
+    return success == pdTRUE ? true : false;
+}
+
+
+bool MutexStandard::Unlock()
+{
+    BaseType_t success = xSemaphoreGive(handle);
+    return success == pdTRUE ? true : false;
+}
+
+
+#if (configUSE_RECURSIVE_MUTEXES == 1)
+
+MutexRecursive::MutexRecursive()
+{
+    handle = xSemaphoreCreateRecursiveMutex();
+
+    if (handle == NULL) {
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+        throw MutexCreateException();
+#else
+        configASSERT(!"Mutex Constructor Failed");
+#endif
+    }
+}
+
+
+bool MutexRecursive::Lock(TickType_t Timeout)
+{
+    BaseType_t success = xSemaphoreTakeRecursive(handle, Timeout);
+    return success == pdTRUE ? true : false;
+}
+
+
+bool MutexRecursive::Unlock()
+{
+    BaseType_t success = xSemaphoreGiveRecursive(handle);
+    return success == pdTRUE ? true : false;
+}
+
+#endif
+
+
+LockGuard::LockGuard(Mutex& m)
+    : mutex(m)
+{
+    mutex.Lock();
+}
+
+
+LockGuard::~LockGuard()
+{
+    mutex.Unlock();
+}

+ 213 - 0
addons/c++/cqueue.cpp

@@ -0,0 +1,213 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#include "queue.hpp"
+
+
+using namespace cpp_freertos;
+
+
+Queue::Queue(UBaseType_t maxItems, UBaseType_t itemSize)
+{
+    handle = xQueueCreate(maxItems, itemSize);
+
+    if (handle == NULL) {
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+        throw QueueCreateException();
+#else
+        configASSERT(!"Queue Constructor Failed");
+#endif
+    }
+}
+
+
+Queue::~Queue()
+{
+    vQueueDelete(handle);
+}
+
+
+bool Queue::Enqueue(void *item)
+{
+    BaseType_t success;
+
+    success = xQueueSendToBack(handle, item, portMAX_DELAY);
+
+    return success == pdTRUE ? true : false;
+}
+
+
+bool Queue::Enqueue(void *item, TickType_t Timeout)
+{
+    BaseType_t success;
+
+    success = xQueueSendToBack(handle, item, Timeout);
+
+    return success == pdTRUE ? true : false;
+}
+
+
+bool Queue::Dequeue(void *item, TickType_t Timeout)
+{
+    BaseType_t success;
+
+    success = xQueueReceive(handle, item, Timeout);
+
+    return success == pdTRUE ? true : false;
+}
+
+
+bool Queue::Peek(void *item, TickType_t Timeout)
+{
+    BaseType_t success;
+
+    success = xQueuePeek(handle, item, Timeout);
+
+    return success == pdTRUE ? true : false;
+}
+
+
+bool Queue::EnqueueFromISR(void *item, BaseType_t *pxHigherPriorityTaskWoken)
+{
+    BaseType_t success;
+
+    success = xQueueSendToBackFromISR(handle, item, pxHigherPriorityTaskWoken);
+
+    return success == pdTRUE ? true : false;
+}
+
+
+bool Queue::DequeueFromISR(void *item, BaseType_t *pxHigherPriorityTaskWoken)
+{
+    BaseType_t success;
+
+    success = xQueueReceiveFromISR(handle, item, pxHigherPriorityTaskWoken);
+
+    return success == pdTRUE ? true : false;
+}
+
+
+bool Queue::PeekFromISR(void *item)
+{
+    BaseType_t success;
+
+    success = xQueuePeekFromISR(handle, item);
+
+    return success == pdTRUE ? true : false;
+}
+
+
+bool Queue::IsEmpty()
+{
+    UBaseType_t cnt = uxQueueMessagesWaiting(handle);
+
+    return cnt == 0 ? true : false;
+}
+
+
+bool Queue::IsFull()
+{
+    UBaseType_t cnt = uxQueueSpacesAvailable(handle);
+
+    return cnt == 0 ? true : false;
+}
+
+
+void Queue::Flush()
+{
+    xQueueReset(handle);
+}
+
+
+UBaseType_t Queue::NumItems()
+{
+    return uxQueueMessagesWaiting(handle);
+}
+
+
+UBaseType_t Queue::NumSpacesLeft()
+{
+    return uxQueueSpacesAvailable(handle);
+}
+
+
+Deque::Deque(UBaseType_t maxItems, UBaseType_t itemSize)
+    : Queue(maxItems, itemSize)
+{
+}
+
+
+bool Deque::EnqueueToFront(void *item, TickType_t Timeout)
+{
+    BaseType_t success;
+
+    success = xQueueSendToFront(handle, item, Timeout);
+
+    return success == pdTRUE ? true : false;
+}
+
+
+bool Deque::EnqueueToFrontFromISR(void *item, BaseType_t *pxHigherPriorityTaskWoken)
+{
+    BaseType_t success;
+
+    success = xQueueSendToFrontFromISR(handle, item, pxHigherPriorityTaskWoken);
+
+    return success == pdTRUE ? true : false;
+}
+
+
+BinaryQueue::BinaryQueue(UBaseType_t itemSize)
+    : Queue(1, itemSize)
+{
+}
+
+
+bool BinaryQueue::Enqueue(void *item)
+{
+    (void)xQueueOverwrite(handle, item);
+    return true;
+}
+
+
+bool BinaryQueue::EnqueueFromISR(void *item, BaseType_t *pxHigherPriorityTaskWoken)
+{
+    (void)xQueueOverwriteFromISR(handle, item, pxHigherPriorityTaskWoken);
+    return true;
+}

+ 226 - 0
addons/c++/cread_write_lock.cpp

@@ -0,0 +1,226 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#include "read_write_lock.hpp"
+
+
+using namespace cpp_freertos;
+
+
+ReadWriteLock::ReadWriteLock()
+    : ReadCount(0)
+{
+    ReadLock = xSemaphoreCreateMutex();
+    if (ReadLock == NULL) {
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+        throw ReadWriteLockCreateException();
+#else
+        configASSERT(!"ReadWriteLock Constructor Failed");
+#endif
+    }
+
+    //
+    //  ResourceLock CANNOT be a mutex. In FreeRTOS, as in most OS's,
+    //  a thread is not allowed to unlock another thread's mutex. But
+    //  the very nature of a Reader Lock allows an arbitrary ordering 
+    //  of unlocks when multiple threads hold the reader lock. 
+    //  Semaphores are not subject to this constraint.
+    //
+    ResourceLock = xSemaphoreCreateBinary();
+    if (ResourceLock == NULL) {
+        vSemaphoreDelete(ReadLock);
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+        throw ReadWriteLockCreateException();
+#else
+        configASSERT(!"ReadWriteLock Constructor Failed");
+#endif
+    }
+
+    //
+    //  Initialize it as "full", so it behaves similar to a mutex.
+    //
+    xSemaphoreGive(ResourceLock);
+}
+
+
+ReadWriteLock::~ReadWriteLock()
+{
+    vSemaphoreDelete(ReadLock);
+    vSemaphoreDelete(ResourceLock);
+}
+
+
+void ReadWriteLockPreferReader::ReaderLock()
+{
+    xSemaphoreTake(ReadLock, portMAX_DELAY);
+
+    ReadCount++;
+    if (ReadCount == 1) {
+        xSemaphoreTake(ResourceLock, portMAX_DELAY);
+    }
+
+    xSemaphoreGive(ReadLock);
+}
+
+
+void ReadWriteLockPreferReader::ReaderUnlock()
+{
+    xSemaphoreTake(ReadLock, portMAX_DELAY);
+
+    ReadCount--;
+    if (ReadCount == 0) {
+        xSemaphoreGive(ResourceLock);
+    }
+
+    xSemaphoreGive(ReadLock);
+}
+
+
+void ReadWriteLockPreferReader::WriterLock()
+{
+    xSemaphoreTake(ResourceLock, portMAX_DELAY);
+}
+
+
+void ReadWriteLockPreferReader::WriterUnlock()
+{
+    xSemaphoreGive(ResourceLock);
+}
+
+
+ReadWriteLockPreferWriter::ReadWriteLockPreferWriter()
+    : ReadWriteLock(),
+      WriteCount(0)
+{
+    WriteLock = xSemaphoreCreateMutex();
+    if (WriteLock == NULL) {
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+        throw ReadWriteLockCreateException();
+#else
+        configASSERT(!"ReadWriteLockPreferWriter Constructor Failed");
+#endif
+    }
+
+    //
+    //  BlockReadersLock CANNOT be a mutex. In FreeRTOS, as in most OS's,
+    //  a thread is not allowed to unlock another thread's mutex. But
+    //  the very nature of a Reader Lock allows an arbitrary ordering 
+    //  of unlocks when multiple threads hold the reader lock. 
+    //  Semaphores are not subject to this constraint.
+    //
+    BlockReadersLock = xSemaphoreCreateBinary();
+    if (BlockReadersLock == NULL) {
+        vSemaphoreDelete(WriteLock);
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+        throw ReadWriteLockCreateException();
+#else
+        configASSERT(!"ReadWriteLockPreferWriter Constructor Failed");
+#endif
+    }
+
+    //
+    //  Initialize it as "full", so it behaves similar to a mutex.
+    //
+    xSemaphoreGive(BlockReadersLock);
+}
+
+
+ReadWriteLockPreferWriter::~ReadWriteLockPreferWriter()
+{
+    vSemaphoreDelete(WriteLock);
+    vSemaphoreDelete(BlockReadersLock);
+}
+
+
+void ReadWriteLockPreferWriter::ReaderLock()
+{
+    xSemaphoreTake(BlockReadersLock, portMAX_DELAY);
+    xSemaphoreTake(ReadLock, portMAX_DELAY);
+
+    ReadCount++;
+    if (ReadCount == 1) {
+        xSemaphoreTake(ResourceLock, portMAX_DELAY);
+    }
+
+    xSemaphoreGive(ReadLock);
+    xSemaphoreGive(BlockReadersLock);
+}
+
+
+void ReadWriteLockPreferWriter::ReaderUnlock()
+{
+    xSemaphoreTake(ReadLock, portMAX_DELAY);
+
+    ReadCount--;
+    if (ReadCount == 0) {
+        xSemaphoreGive(ResourceLock);
+    }
+
+    xSemaphoreGive(ReadLock);
+}
+
+
+void ReadWriteLockPreferWriter::WriterLock()
+{
+    xSemaphoreTake(WriteLock, portMAX_DELAY);
+
+    WriteCount++;
+    if (WriteCount == 1) {
+        xSemaphoreTake(BlockReadersLock, portMAX_DELAY);
+    }
+
+    xSemaphoreGive(WriteLock);
+
+    xSemaphoreTake(ResourceLock, portMAX_DELAY);
+}
+
+
+void ReadWriteLockPreferWriter::WriterUnlock()
+{
+    xSemaphoreGive(ResourceLock);
+
+    xSemaphoreTake(WriteLock, portMAX_DELAY);
+
+    WriteCount--;
+    if (WriteCount == 0) {
+        xSemaphoreGive(BlockReadersLock);
+    }
+
+    xSemaphoreGive(WriteLock);
+}

+ 144 - 0
addons/c++/csemaphore.cpp

@@ -0,0 +1,144 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#include "semaphore.hpp"
+
+
+using namespace cpp_freertos;
+
+
+bool Semaphore::Take(TickType_t xBlockTime)
+{
+    BaseType_t success;
+
+    success = xSemaphoreTake(handle, xBlockTime);
+
+    return success == pdTRUE ? true : false;
+}
+
+
+bool Semaphore::TakeFromISR(BaseType_t *pxHigherPriorityTaskWoken)
+{
+    BaseType_t success;
+
+    success = xSemaphoreTakeFromISR(handle, pxHigherPriorityTaskWoken);
+
+    return success == pdTRUE ? true : false;
+}
+
+
+bool Semaphore::Give()
+{
+    BaseType_t success;
+
+    success = xSemaphoreGive(handle);
+
+    return success == pdTRUE ? true : false;
+}
+
+
+bool Semaphore::GiveFromISR(BaseType_t *pxHigherPriorityTaskWoken)
+{
+    BaseType_t success;
+
+    success = xSemaphoreGiveFromISR(handle, pxHigherPriorityTaskWoken);
+
+    return success == pdTRUE ? true : false;
+}
+
+
+Semaphore::Semaphore()
+{
+}
+
+
+Semaphore::~Semaphore()
+{
+    vSemaphoreDelete(handle);
+}
+
+
+BinarySemaphore::BinarySemaphore(bool set)
+{
+    handle = xSemaphoreCreateBinary();
+
+    if (handle == NULL) {
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+        throw SemaphoreCreateException();
+#else
+        configASSERT(!"BinarySemaphore Constructor Failed");
+#endif
+    }
+
+    if (set) {
+        xSemaphoreGive(handle);
+    }
+}
+
+
+CountingSemaphore::CountingSemaphore(UBaseType_t maxCount, UBaseType_t initialCount)
+{
+    if (maxCount == 0) {
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+        throw SemaphoreCreateException("bad maxCount");
+#else
+        configASSERT(!"CountingSemaphore Constructor bad maxCount");
+#endif
+    }
+
+    if (initialCount > maxCount) {
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+        throw SemaphoreCreateException("bad initialCount");
+#else
+        configASSERT(!"CountingSemaphore Constructor bad initialCount");
+#endif
+    }
+
+    handle = xSemaphoreCreateCounting(maxCount, initialCount);
+
+    if (handle == NULL) {
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+        throw SemaphoreCreateException();
+#else
+        configASSERT(!"CountingSemaphore Constructor Failed");
+#endif
+    }
+}
+
+

+ 128 - 0
addons/c++/ctasklet.cpp

@@ -0,0 +1,128 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#include "tasklet.hpp"
+
+
+using namespace cpp_freertos;
+
+
+Tasklet::Tasklet()
+{
+    DtorLock = xSemaphoreCreateBinary();
+
+    if (DtorLock == NULL) {
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+        throw TaskletCreateException("Create DtorLock Failed");
+#else
+        configASSERT(!"Tasklet Constructor Failed");
+#endif
+    }
+
+    xSemaphoreGive(DtorLock);
+}
+
+
+Tasklet::~Tasklet()
+{
+}
+
+
+void Tasklet::CheckForSafeDelete()
+{
+    xSemaphoreTake(DtorLock, portMAX_DELAY);
+    vSemaphoreDelete(DtorLock);
+}
+
+
+void Tasklet::TaskletAdapterFunction(void *reference, uint32_t parameter)
+{
+    Tasklet *tasklet = static_cast<Tasklet *>(reference);
+    tasklet->Run(parameter);
+    xSemaphoreGive(tasklet->DtorLock);
+}
+
+
+bool Tasklet::Schedule( uint32_t parameter,
+                        TickType_t CmdTimeout)
+{
+    BaseType_t rc;
+
+    xSemaphoreTake(DtorLock, portMAX_DELAY);
+
+    rc = xTimerPendFunctionCall(TaskletAdapterFunction,
+                                this,
+                                parameter,
+                                CmdTimeout);
+
+    if (rc == pdPASS) {
+        return true;
+    }
+    else {
+        xSemaphoreGive(DtorLock);
+        return false;
+    }
+}
+
+
+bool Tasklet::ScheduleFromISR(  uint32_t parameter,
+                                BaseType_t *pxHigherPriorityTaskWoken)
+{
+    BaseType_t rc;
+
+    rc = xSemaphoreTakeFromISR(DtorLock, pxHigherPriorityTaskWoken);
+
+    if (rc != pdTRUE) {
+        return false;
+    }
+    
+    rc = xTimerPendFunctionCallFromISR( TaskletAdapterFunction,
+                                        this,
+                                        parameter,
+                                        pxHigherPriorityTaskWoken);
+
+    if (rc == pdPASS) {
+        return true;
+    }
+    else {
+        xSemaphoreGive(DtorLock);
+        return false;
+    }
+}
+

+ 272 - 0
addons/c++/cthread.cpp

@@ -0,0 +1,272 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#include <cstring>
+#include "thread.hpp"
+
+
+using namespace cpp_freertos;
+
+
+volatile bool Thread::SchedulerActive = false;
+MutexStandard Thread::StartGuardLock;
+
+
+//
+//  We want to use C++ strings. This is the default.
+//
+#ifndef CPP_FREERTOS_NO_CPP_STRINGS
+
+Thread::Thread( const std::string pcName,
+                uint16_t usStackDepth,
+                UBaseType_t uxPriority)
+    :   Name(pcName), 
+        StackDepth(usStackDepth), 
+        Priority(uxPriority),
+        ThreadStarted(false)
+{
+#if (INCLUDE_vTaskDelayUntil == 1)
+    delayUntilInitialized = false;
+#endif
+}
+
+
+Thread::Thread( uint16_t usStackDepth,
+                UBaseType_t uxPriority)
+    :   Name("Default"), 
+        StackDepth(usStackDepth), 
+        Priority(uxPriority),
+        ThreadStarted(false)
+{
+#if (INCLUDE_vTaskDelayUntil == 1)
+    delayUntilInitialized = false;
+#endif
+}
+
+//
+//  We do not want to use C++ strings. Fall back to character arrays.
+//
+#else
+
+Thread::Thread( const char *pcName,
+                uint16_t usStackDepth,
+                UBaseType_t uxPriority)
+    :   StackDepth(usStackDepth),
+        Priority(uxPriority),
+        ThreadStarted(false)
+{
+    for (int i = 0; i < configMAX_TASK_NAME_LEN - 1; i++) {
+        Name[i] = *pcName;
+        if (*pcName == 0)
+            break;
+        pcName++;
+    }
+    Name[configMAX_TASK_NAME_LEN - 1] = 0;
+
+#if (INCLUDE_vTaskDelayUntil == 1)
+    delayUntilInitialized = false;
+#endif
+}
+
+
+Thread::Thread( uint16_t usStackDepth,
+                UBaseType_t uxPriority)
+    :   StackDepth(usStackDepth),
+        Priority(uxPriority),
+        ThreadStarted(false)
+{
+    memset(Name, 0, sizeof(Name));
+#if (INCLUDE_vTaskDelayUntil == 1)
+    delayUntilInitialized = false;
+#endif
+}
+
+#endif
+
+
+bool Thread::Start()
+{
+    //
+    //  If the Scheduler is on, we need to lock before checking
+    //  the ThreadStarted variable. We'll leverage the LockGuard 
+    //  pattern, so we can create the guard and just forget it. 
+    //  Leaving scope, including the return, will automatically 
+    //  unlock it.
+    //
+    if (SchedulerActive) {
+
+        LockGuard guard (StartGuardLock);
+
+        if (ThreadStarted)
+            return false;
+        else 
+            ThreadStarted = true;
+    }
+    //
+    //  If the Scheduler isn't running, just check it.
+    //
+    else {
+
+        if (ThreadStarted)
+            return false;
+        else 
+            ThreadStarted = true;
+    }
+
+#ifndef CPP_FREERTOS_NO_CPP_STRINGS
+
+    BaseType_t rc = xTaskCreate(TaskFunctionAdapter,
+                                Name.c_str(),
+                                StackDepth,
+                                this,
+                                Priority,
+                                &handle);
+#else 
+
+    BaseType_t rc = xTaskCreate(TaskFunctionAdapter,
+                                Name,
+                                StackDepth,
+                                this,
+                                Priority,
+                                &handle);
+#endif
+
+    return rc != pdPASS ? false : true;
+}
+
+
+#if (INCLUDE_vTaskDelete == 1)
+
+//
+//  Deliberately empty. If this is needed, it will be overloaded.
+//
+void Thread::Cleanup()
+{
+}
+
+
+Thread::~Thread()
+{
+    vTaskDelete(handle);
+    handle = (TaskHandle_t)-1;
+}
+
+#else
+
+Thread::~Thread()
+{
+    configASSERT( ! "Cannot actually delete a thread object "
+                    "if INCLUDE_vTaskDelete is not defined.");
+}
+
+#endif
+
+
+void Thread::TaskFunctionAdapter(void *pvParameters)
+{
+    Thread *thread = static_cast<Thread *>(pvParameters);
+
+    thread->Run();
+
+#if (INCLUDE_vTaskDelete == 1)
+
+    thread->Cleanup();
+
+    vTaskDelete(thread->handle);
+
+#else
+    configASSERT( ! "Cannot return from a thread.run function "
+                    "if INCLUDE_vTaskDelete is not defined.");
+#endif
+}
+
+
+#if (INCLUDE_vTaskDelayUntil == 1)
+
+void Thread::DelayUntil(const TickType_t Period)
+{
+    if (!delayUntilInitialized) {
+        delayUntilInitialized = true;
+        delayUntilPreviousWakeTime = xTaskGetTickCount();
+    }
+
+    vTaskDelayUntil(&delayUntilPreviousWakeTime, Period);
+}
+
+
+void Thread::ResetDelayUntil()
+{
+    delayUntilInitialized = false;
+}
+
+#endif
+
+
+
+#ifdef CPP_FREERTOS_CONDITION_VARIABLES
+
+bool Thread::Wait(  ConditionVariable &Cv,
+                    Mutex &CvLock,
+                    TickType_t Timeout)
+{
+    Cv.AddToWaitList(this);
+
+    //
+    //  Drop the associated external lock, as per cv semantics.
+    //
+    CvLock.Unlock();
+
+    //
+    //  And block on the internal semaphore. The associated Cv
+    //  will call Thread::Signal, which will release the semaphore.
+    //
+    bool timed_out = ThreadWaitSem.Take(Timeout);
+    
+    //
+    //  Grab the external lock again, as per cv semantics.
+    //
+    CvLock.Lock();
+
+    return timed_out;
+}
+
+
+#endif
+
+

+ 108 - 0
addons/c++/ctickhook.cpp

@@ -0,0 +1,108 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#include "tickhook.hpp"
+
+#if ( configUSE_TICK_HOOK == 1 )
+
+using namespace std;
+using namespace cpp_freertos;
+
+
+list<TickHook *> TickHook::Callbacks;
+
+
+TickHook::TickHook()
+    : Enabled(true)
+{
+}
+
+
+TickHook::~TickHook()
+{
+    taskENTER_CRITICAL();
+    Callbacks.remove(this);
+    taskEXIT_CRITICAL();
+}
+
+
+void TickHook::Register()
+{
+    taskENTER_CRITICAL();
+    Callbacks.push_front(this);
+    taskEXIT_CRITICAL();
+}
+
+
+void TickHook::Disable()
+{
+    taskENTER_CRITICAL();
+    Enabled = false;
+    taskEXIT_CRITICAL();
+}
+
+
+void TickHook::Enable()
+{
+    taskENTER_CRITICAL();
+    Enabled = true;
+    taskEXIT_CRITICAL();
+}
+
+
+/**
+ *  We are a friend of the Tick class, which makes this much simplier.
+ */
+void vApplicationTickHook(void)
+{
+    for (list<TickHook *>::iterator it = TickHook::Callbacks.begin();
+         it != TickHook::Callbacks.end();
+         ++it) {
+
+        TickHook *tickHookObject = *it;
+
+        if (tickHookObject->Enabled){
+            tickHookObject->Run();
+        }
+    }
+}
+
+#endif
+
+

+ 169 - 0
addons/c++/ctimer.cpp

@@ -0,0 +1,169 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#include "timer.hpp"
+
+
+using namespace cpp_freertos;
+
+
+Timer::Timer(   const char * const TimerName,
+                TickType_t PeriodInTicks,
+                bool Periodic
+                )
+{
+    handle = xTimerCreate(  TimerName,
+                            PeriodInTicks,
+                            Periodic ? pdTRUE : pdFALSE,
+                            this,
+                            TimerCallbackFunctionAdapter);
+
+    if (handle == NULL) {
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+        throw TimerCreateException();
+#else
+        configASSERT(!"Timer Constructor Failed");
+#endif
+    }
+}
+
+
+Timer::Timer(   TickType_t PeriodInTicks,
+                bool Periodic
+                )
+{
+    handle = xTimerCreate(  "Default",
+                            PeriodInTicks,
+                            Periodic ? pdTRUE : pdFALSE,
+                            this,
+                            TimerCallbackFunctionAdapter);
+
+    if (handle == NULL) {
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+        throw TimerCreateException();
+#else
+        configASSERT(!"Timer Constructor Failed");
+#endif
+    }
+}
+
+
+Timer::~Timer()
+{
+    xTimerDelete(handle, portMAX_DELAY);
+}
+
+
+bool Timer::IsActive()
+{
+    return xTimerIsTimerActive(handle) == pdFALSE ? false : true;
+}
+
+
+bool Timer::Start(TickType_t CmdTimeout)
+{
+    return xTimerStart(handle, CmdTimeout) == pdFALSE ? false : true;
+}
+
+
+bool Timer::StartFromISR(BaseType_t *pxHigherPriorityTaskWoken)
+{
+    return xTimerStartFromISR(handle, pxHigherPriorityTaskWoken) == pdFALSE
+            ? false : true;
+}
+
+
+bool Timer::Stop(TickType_t CmdTimeout)
+{
+    return xTimerStop(handle, CmdTimeout) == pdFALSE ? false : true;
+}
+
+
+bool Timer::StopFromISR(BaseType_t *pxHigherPriorityTaskWoken)
+{
+    return xTimerStopFromISR(handle, pxHigherPriorityTaskWoken) == pdFALSE
+            ? false : true;
+}
+
+
+bool Timer::Reset(TickType_t CmdTimeout)
+{
+    return xTimerReset(handle, CmdTimeout) == pdFALSE ? false : true;
+}
+
+
+bool Timer::ResetFromISR(BaseType_t *pxHigherPriorityTaskWoken)
+{
+    return xTimerResetFromISR(handle, pxHigherPriorityTaskWoken) == pdFALSE
+            ? false : true;
+}
+
+
+bool Timer::SetPeriod(  TickType_t NewPeriod,
+                        TickType_t CmdTimeout)
+{
+    return xTimerChangePeriod(handle, NewPeriod, CmdTimeout) == pdFALSE
+            ? false : true;
+}
+
+
+bool Timer::SetPeriodFromISR(   TickType_t NewPeriod,
+                                BaseType_t *pxHigherPriorityTaskWoken)
+{
+    return xTimerChangePeriodFromISR(   handle, NewPeriod,
+                                        pxHigherPriorityTaskWoken) == pdFALSE
+            ? false : true;
+}
+
+
+#if (INCLUDE_xTimerGetTimerDaemonTaskHandle == 1)
+
+TaskHandle_t Timer::GetTimerDaemonHandle()
+{
+    return xTimerGetTimerDaemonTaskHandle();
+}
+
+#endif
+
+
+void Timer::TimerCallbackFunctionAdapter(TimerHandle_t xTimer)
+{
+    Timer *timer = static_cast<Timer *>(pvTimerGetTimerID(xTimer));
+    timer->Run();
+}

+ 207 - 0
addons/c++/cworkqueue.cpp

@@ -0,0 +1,207 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#include "workqueue.hpp"
+
+
+using namespace cpp_freertos;
+
+
+WorkItem::WorkItem(bool freeAfterComplete)
+    : FreeItemAfterCompleted(freeAfterComplete)
+{
+}
+
+
+WorkItem::~WorkItem()
+{
+}
+
+
+bool WorkItem::FreeAfterRun()
+{
+    return FreeItemAfterCompleted;
+}
+
+
+WorkQueue::WorkQueue(   const char * const Name,
+                        uint16_t StackDepth,
+                        UBaseType_t Priority,
+                        UBaseType_t maxWorkItems)
+{
+    //
+    //  Build the Queue first, since the Thread is going to access 
+    //  it as soon as it can, maybe before we leave this ctor.
+    //
+    WorkItemQueue = new Queue(maxWorkItems, sizeof(WorkItem *));
+    ThreadComplete = new BinarySemaphore();
+    WorkerThread = new CWorkerThread(Name, StackDepth, Priority, this);
+    //
+    //  Our ctor chain is complete, we can start.
+    //
+    WorkerThread->Start();
+}
+
+
+WorkQueue::WorkQueue(   uint16_t StackDepth,
+                        UBaseType_t Priority,
+                        UBaseType_t maxWorkItems)
+{
+    //
+    //  Build the Queue first, since the Thread is going to access 
+    //  it as soon as it can, maybe before we leave this ctor.
+    //
+    WorkItemQueue = new Queue(maxWorkItems, sizeof(WorkItem *));
+    ThreadComplete = new BinarySemaphore();
+    WorkerThread = new CWorkerThread(StackDepth, Priority, this);
+    //
+    //  Our ctor chain is complete, we can start.
+    //
+    WorkerThread->Start();
+}
+
+
+#if (INCLUDE_vTaskDelete == 1)
+
+WorkQueue::~WorkQueue()
+{
+    //
+    //  This dtor is tricky, because of the multiple objects in 
+    //  play, and the multithreaded nature of this specific object.
+    //
+
+    //
+    //  Note that we cannot flush the queue. If there are items 
+    //  in the queue maked freeAfterComplete, we would leak the 
+    //  memory. 
+    //
+
+    //
+    //  Send a message that it's time to cleanup.
+    //
+    WorkItem *work = NULL;
+    WorkItemQueue->Enqueue(&work);
+
+    //
+    //  Wait until the thread has run enough to signal that it's done.
+    //
+    ThreadComplete->Take();
+
+    //
+    //  Then delete the queue and thread. Order doesn't matter here.
+    //
+    delete WorkItemQueue;
+    delete WorkerThread;
+    delete ThreadComplete;
+}
+
+#endif
+
+
+bool WorkQueue::QueueWork(WorkItem *work)
+{
+    return WorkItemQueue->Enqueue(&work);
+}
+
+
+WorkQueue::CWorkerThread::CWorkerThread(const char * const Name,
+                                        uint16_t StackDepth,
+                                        UBaseType_t Priority,
+                                        WorkQueue *Parent)
+    : Thread(Name, StackDepth, Priority), ParentWorkQueue(Parent)
+{
+}
+
+
+WorkQueue::CWorkerThread::CWorkerThread(uint16_t StackDepth,
+                                        UBaseType_t Priority,
+                                        WorkQueue *Parent)
+    : Thread(StackDepth, Priority), ParentWorkQueue(Parent)
+{
+}
+
+
+WorkQueue::CWorkerThread::~CWorkerThread()
+{
+}
+
+
+void WorkQueue::CWorkerThread::Run()
+{
+    while (true) {
+
+        WorkItem *work;
+
+        //
+        //  Wait forever for work.
+        //
+        ParentWorkQueue->WorkItemQueue->Dequeue(&work);
+
+        //
+        //  If we dequeue a NULL item, its our sign to exit.
+        //  We are being deconstructed.
+        //
+        if (work == NULL) {
+            //
+            //  Exit the task loop.
+            //
+            break;
+        }
+
+        //
+        //  Else we have an item, run it.
+        //
+        work->Run();
+
+        //
+        //  If this was a dynamic, fire and forget item and we were 
+        //  requested to clean it up, do so.
+        //
+        if (work->FreeAfterRun()) {
+            delete work;
+        }
+    }
+
+    //
+    //  Signal the dtor that the thread is exiting.
+    //
+    ParentWorkQueue->ThreadComplete->Give();
+}
+
+

+ 139 - 0
addons/c++/include/condition_variable.hpp

@@ -0,0 +1,139 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef CONDITION_VARIABLE_HPP_
+#define CONDITION_VARIABLE_HPP_
+
+#include <list>
+#include "mutex.hpp"
+
+
+/**
+ *  Condition variables are an additon to the FreeRTOS C++ Wrapper
+ *  classes. If you want to include them, you need to define the 
+ *  following in your makefile or project.
+ */
+#ifdef CPP_FREERTOS_CONDITION_VARIABLES
+
+
+namespace cpp_freertos {
+
+//
+//  Forward declaration. We need to prevent a circular dependency
+//  between the Thread class and the ConditionVariable class.
+//
+class Thread;
+
+
+/**
+ *  Class implementation of condition variable based on
+ *  FreeRTOS C++ Wrapper classes.
+ *  
+ *  A condition variable isn't really a variable. It's a list
+ *  of threads.
+ *
+ *  The design here is that a Thread "waits", and a ConditionVariable
+ *  "signals". This affects where the public interfaces reside.
+ */
+class ConditionVariable {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+    
+        /**
+         *  Constructor to create a condition variable.
+         */
+        ConditionVariable();
+
+        /**
+         *  Signal a thread waiting on this ConditionVariable.
+         *  Signaling is implemented as FIFO.
+         */
+        void Signal();
+
+        /**
+         *  Signal all threads waiting on this ConditionVariable.
+         */
+        void Broadcast();
+
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Private API
+    //  The internals of this wrapper class.
+    //
+    /////////////////////////////////////////////////////////////////////////
+    private:
+
+        /**
+         *  Protect the internal ConditionVariable state.
+         */
+        MutexStandard Lock;
+
+        /**
+         *  Implementation of a wait list of Threads.
+         */
+        std::list<Thread *> WaitList;
+
+        /**
+         *  Internal helper function to queue a Thread to 
+         *  this ConditionVariable's wait list.
+         */
+        void AddToWaitList(Thread *thread);
+
+    /**
+     *  The Thread class and the ConditionVariable class are interdependent.
+     *  If we allow the Thread class to access the internals of the
+     *  ConditionVariable, we can reduce the public interface which is a
+     *  good thing.
+     */
+    friend class Thread;
+};
+
+
+}
+
+#endif
+
+#endif
+

+ 144 - 0
addons/c++/include/critical.hpp

@@ -0,0 +1,144 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef CRITICAL_HPP_
+#define CRITICAL_HPP_
+
+#include "FreeRTOS.h"
+#include "task.h"
+
+
+namespace cpp_freertos {
+
+
+/**
+ *  Wrapper class around various critical section type
+ *  synchronization mechanisms within FreeRTOS.
+ */
+class CriticalSection {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //  Available from anywhere.
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+        /**
+         *  Disable context switches as well as maskable interrupts.
+         */
+        static inline void Enter()
+        {
+            taskENTER_CRITICAL();
+        }
+
+        /**
+         *  Re-enable context switches.
+         */
+        static inline void Exit()
+        {
+            taskEXIT_CRITICAL();
+        }
+
+        /**
+         *  Disable context switches as well as maskable interrupts
+         *  from an interrupt context.
+         *
+         *  @return Opaque representation of interrupt mask state.
+         *  This must be passed back to the corresponding call to 
+         *  ExitFromISR().
+         *
+         *  @note See the following for further details:
+         *  http://www.freertos.org/taskENTER_CRITICAL_FROM_ISR_taskEXIT_CRITICAL_FROM_ISR.html
+         */
+        static inline BaseType_t EnterFromISR()
+        {
+            return taskENTER_CRITICAL_FROM_ISR();
+        }
+
+        /**
+         *  Re-enable context switches from an interrupt context.
+         *
+         *  @param savedInterruptStatus This should be the value you 
+         *  received from calling EnterFromISR().
+         *
+         *  @note See the following for further details:
+         *  http://www.freertos.org/taskENTER_CRITICAL_FROM_ISR_taskEXIT_CRITICAL_FROM_ISR.html
+         */
+        static inline void ExitFromISR(BaseType_t savedInterruptStatus)
+        {
+            taskEXIT_CRITICAL_FROM_ISR(savedInterruptStatus);
+        }
+
+        /**
+         *  Disable all maskable interrupts.
+         */
+        static inline void DisableInterrupts()
+        {
+            taskDISABLE_INTERRUPTS();
+        }
+
+        /**
+         *  Enable all maskable interrupts.
+         */
+        static inline void EnableInterrupts()
+        {
+            taskENABLE_INTERRUPTS();
+        }
+
+        /**
+         *  Suspend the scheduler without disabling interrupts.
+         */
+        static inline void SuspendScheduler()
+        {
+            vTaskSuspendAll();
+        }
+
+        /**
+         *  Re-enable the scheduler.
+         */
+        static inline void ResumeScheduler()
+        {
+            xTaskResumeAll();
+        }
+};
+
+
+}
+#endif

+ 307 - 0
addons/c++/include/event_groups.hpp

@@ -0,0 +1,307 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Danilo Pucci Smokovitz (dnlps@hotmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+#ifndef EVENT_GROUPS_HPP_
+#define EVENT_GROUPS_HPP_
+
+/**
+ *  C++ exceptions are used by default when constructors fail.
+ *  If you do not want this behavior, define the following in your makefile
+ *  or project. Note that in most / all cases when a constructor fails,
+ *  it's a fatal error. In the cases when you've defined this, the new
+ *  default behavior will be to issue a configASSERT() instead.
+ */
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+#include <exception>
+#include <string>
+#include <cstdio>
+#ifdef CPP_FREERTOS_NO_CPP_STRINGS
+#error "FreeRTOS-Addons require C++ Strings if you are using exceptions"
+#endif
+#endif
+#include "FreeRTOS.h"
+#include "event_groups.h"
+
+
+namespace cpp_freertos {
+
+
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+/**
+ *  This is the exception that is thrown if an EventGroup constructor fails.
+ */
+class EventGroupCreateException : public std::exception {
+
+    public:
+        /**
+         *  Create the exception.
+         */
+        EventGroupCreateException()
+        {
+            sprintf(errorString, "Event Group Constructor Failed");
+        }
+
+        /**
+         *  Create the exception.
+         */
+        explicit EventGroupCreateException(const char *info)
+        {
+            snprintf(errorString, sizeof(errorString),
+                        "Event Group Constructor Failed %s", info);
+        }
+
+        /**
+         *  Get what happened as a string.
+         *  We are overriding the base implementation here.
+         */
+        virtual const char *what() const throw()
+        {
+            return errorString;
+        }
+
+    private:
+        /**
+         *  A text string representing what failed.
+         */
+        char errorString[80];
+};
+#endif
+
+
+/**
+ *  @todo - document this class
+ */
+class EventGroup {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+
+        /**
+         *  Construct a Event Group
+         */
+        EventGroup();
+
+#if( configSUPPORT_STATIC_ALLOCATION == 1 )
+        /**
+         *  Construct a Event Group with static allocation
+         */
+        EventGroup(StaticEventGroup_t *pxEventGroupBuffer);
+#endif
+        /**
+         *  Allow two or more tasks to use an event group to sync each other.
+         *
+         *  @param uxBitsToSet A bit mask that specifies the event bit, or
+         *  event bits, to set 1 in the event group. The value of the event
+         *  groups is updated by bitwise ORing the event group's existing
+         *  value with the passed in uxBitsToSet.
+         *
+         *  @param uxBitsToWaitFor The bit or bits to set in the event
+         *  group before determining if (and possibly waiting for), all the
+         *  bits specified by the uxBitsToWait parameter are set.
+         *
+         *  @param xTicksToWait The maximum amount of time (specified in
+         *  'ticks') to wait for all the bits specified by the
+         *  uxBitsToWaitFor parameter value to become set.
+         *
+         *  @return If EventGroup::Sync returned because all the bits it
+         *  was waiting for were set then the returned value is the event
+         *  group value before any bits were automatically cleared.
+         *  If EventGroup::Sync returned because its timeout expired then
+         *  not all the bits being waited for will be set.
+         */
+        EventBits_t Sync(   const EventBits_t uxBitsToSet,
+                            const EventBits_t uxBitsToWaitFor,
+                            TickType_t xTicksToWait);
+
+        /**
+         *  Read bits within an RTOS event group, optionally entering the
+         *  Blocked state (with a timeout) to wait for a bit or group of
+         *  bits to become set.
+         *
+         *  @param uxBitsToWaitFor A bitwise value that indicates the bit
+         *  or bits to test inside the event group.
+         *
+         *  @param xClearOnExit If xClearOnExit is set to true then any bits
+         *  set in the value passed as the uxBitsToWaitFor parameter will be
+         *  cleared in the event group before EventGroup::WaitBits returns
+         *  if EventGroup::WaitBits returns for any reason other than a
+         *  timeout. The timeout value is set by the xTicksToWait parameter.
+         *  If xClearOnExit is set to false then the bits set in the event
+         *  group are not altered when the call to EventGroup::WaitBits
+         *  returns.
+         *
+         *  @param xWaitForAllBits is used to create either a logical AND
+         *  test (where all bits must be set) or a logical OR test (where
+         *  one or more bits must be set) as follows:
+         *
+         *      @par    If xWaitForAllBits is set to true then
+         *              EventGroup::WaitBits will return when either all the
+         *              bits set in the value passed as the uxBitsToWaitFor
+         *              parameter are set in the event group or the specified
+         *              block time expires.
+         *
+         *      @par   If xWaitForAllBits is set to false then
+         *              EventGroup::WaitBits will return when any of the bits
+         *              set in the value passed as the uxBitsToWaitFor
+         *              parameter are set in the event group or the specified
+         *              block time expires.
+         *
+         *  @param xTicksToWait The maximum amount of time (specified in
+         *  'ticks') to wait for one/all (depending on the xWaitForAllBits
+         *  value) of the bits specified by uxBitsToWaitFor to become set.
+         *
+         *  @return The value of the event group at the time either the event
+         *  bits being waited for became set, or the block time expired. The
+         *  current value of the event bits in an event group will be
+         *  different to the returned value if a higher priority task or
+         *  interrupt changed the value of an event bit between the calling
+         *  task leaving the Blocked state and exiting the
+         *  EventGroup::WaitBits function. Test the return value to know
+         *  which bits were set. If EventGroup::WaitBits returned because its
+         *  timeout expired then not all the bits being waited for will be
+         *  set. If EventGroup::WaitBits returned because the bits it was
+         *  waiting for were set then the returned value is the event group
+         *  value before any bits were automatically cleared because the
+         *  xClearOnExit parameter was set to true.
+         */
+        EventBits_t WaitBits(   const EventBits_t uxBitsToWaitFor,
+                                bool xClearOnExit,
+                                bool xWaitForAllBits,
+                                TickType_t xTicksToWait);
+
+        /**
+         *  Clear bits (flags) within an event group.
+         *
+         *  @param uxBitsToClear A bitwise value that indicates the bit or
+         *  bits to clear in the event group.
+         *
+         *  @return The value of the event group before the specified bits
+         *  were cleared.
+         */
+        EventBits_t ClearBits(const EventBits_t uxBitsToClear);
+
+        /**
+         *  Clear bits (flags) within an event group from ISR context.
+         *
+         *  @param uxBitsToClear A bitwise value that indicates the bit or
+         *  bits to clear in the event group.
+         *
+         *  @return The value of the event group before the specified bits
+         *  were cleared.
+         */
+        BaseType_t ClearBitsFromISR(const EventBits_t uxBitsToClear);
+
+        /**
+        *  Returns the current value of the event bits (event flags) in an
+        *  event group.
+        *
+        *  @return The value of the event bits in the event group at the time
+        *  EventGroup::GetBitsFromISR was called.
+        */
+        EventBits_t GetBits();
+
+        /**
+         *  Returns the current value of the event bits (event flags) in an
+         *  event group from ISR context.
+         *
+         *  @return The value of the event bits in the event group at the
+         *  time EventGroup::GetBitsFromISR was called.
+         */
+        EventBits_t GetBitsFromISR();
+
+        /**
+         *  Set bits (flags) within an event group.
+         *
+         *  @param uxBitsToSet A bitwise value that indicates the bit or bits
+         *  to set in the event group.
+         *
+         *  @return The value of the event group at the time the call to
+         *  EventGroup::SetBits returns
+         */
+        EventBits_t SetBits(const EventBits_t uxBitsToSet);
+
+
+        #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )
+        /**
+         *  Set bits (flags) within an event group from ISR context.
+         *
+         *  @param uxBitsToSet A bitwise value that indicates the bit or bits
+         *  to set in the event group.
+         *
+         *  @param pxHigherPriorityTaskWoken A bitwise value that indicates
+         *  the bit or bits to set in the event group.
+         *
+         *  @return Calling this function will result in a message being sent
+         *  to the RTOS daemon task. If the priority of the daemon task is
+         *  higher than the priority of the currently running task (the
+         *  task the interrupt interrupted) then *pxHigherPriorityTaskWoken
+         *  will be set to true by EventGroupSetBitsFromISR, indicating that
+         *  a context switch should be requested before the interrupt exits.
+         *  For that reason *pxHigherPriorityTaskWoken must be initialised
+         *  to false.
+         */
+        BaseType_t SetBitsFromISR(  const EventBits_t uxBitsToSet,
+                                    BaseType_t *pxHigherPriorityTaskWoken);
+
+        #endif
+
+        /**
+         *  Our destructor
+         */
+        virtual ~EventGroup();
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Protected API
+    //  Not intended for use by application code.
+    //
+    /////////////////////////////////////////////////////////////////////////
+    protected:
+        /**
+         *  FreeRTOS Event Group handle.
+         */
+        EventGroupHandle_t handle;
+
+};
+
+}
+
+#endif

+ 292 - 0
addons/c++/include/mem_pool.hpp

@@ -0,0 +1,292 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef MEM_POOL_HPP_
+#define MEM_POOL_HPP_
+
+/**
+ *  C++ exceptions are used by default when constructors fail.
+ *  If you do not want this behavior, define the following in your makefile
+ *  or project. Note that in most / all cases when a constructor fails,
+ *  it's a fatal error. In the cases when you've defined this, the new
+ *  default behavior will be to issue a configASSERT() instead.
+ */
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+#include <exception>
+#include <string>
+#include <cstdio>
+#ifdef CPP_FREERTOS_NO_CPP_STRINGS
+#error "FreeRTOS-Addons require C++ Strings if you are using exceptions"
+#endif
+#endif
+#include <list>
+#include "FreeRTOS.h"
+#include "mutex.hpp"
+
+namespace cpp_freertos {
+
+
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+/**
+ *  This is the exception that is thrown if a MemoryPool malloc fails.
+ */
+class MemoryPoolMallocException : public std::exception {
+
+    public:
+        /**
+         *  Create the exception.
+         */
+        MemoryPoolMallocException()
+        {
+            sprintf(errorString, "MemoryPool malloc Failed");
+        }
+
+        /**
+         *  Get what happened as a string.
+         *  We are overriding the base implementation here.
+         */
+        virtual const char *what() const throw()
+        {
+            return errorString;
+        }
+
+    private:
+        /**
+         *  A text string representing what failed.
+         */
+        char errorString[80];
+};
+
+/**
+ *  This is the exception that is thrown if the Alignment argument
+ *  is invalid.
+ */
+class MemoryPoolBadAlignmentException : public std::exception {
+
+    public:
+        /**
+         *  Create the exception.
+         */
+        MemoryPoolBadAlignmentException()
+        {
+            sprintf(errorString, "MemoryPool Bad Alignment");
+        }
+
+        /**
+         *  Get what happened as a string.
+         *  We are overriding the base implementation here.
+         */
+        virtual const char *what() const throw()
+        {
+            return errorString;
+        }
+
+    private:
+        /**
+         *  A text string representing what failed.
+         */
+        char errorString[80];
+};
+
+#endif
+
+
+/**
+ *  Memory Pools are fixed size allocations to prevent fragmentation.
+ *
+ *  This is a new feature to FreeRTOS Wrappers and is not in and of
+ *  itself a wrapper.
+ *
+ *  Memory Pools are thread safe, but cannot be used in ISR context.
+ *  The OS must be running, because these use Mutexes to protect internal
+ *  data structures.
+ */
+class MemoryPool {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+
+        /**
+         *  Constructor to create a Memory Pool.
+         *
+         *  This constructor uses the system malloc to actually obtain
+         *  the memory.
+         *
+         *  @param itemSize How big is each item you want to allocate.
+         *  @param itemCount How many items max do you want to allocate
+         *      at once.
+         *  @param Alignment Power of 2 value denoting on which address boundary the
+         *      memory will be aligned to. Must be at least sizeof(unsigned char *).
+         *  @throws MemoryPoolMallocException on failure.
+         *  @throws MemoryPoolBadAlignmentException on failure.
+         */
+        MemoryPool( int itemSize,
+                    int itemCount,
+                    int alignment);
+
+        /**
+         *  Constructor to create a Memory Pool.
+         *
+         *  This constructor uses memory you pass in to actually create
+         *  the pool. This constructor does not throw.
+         *
+         *  @param itemSize How big is each item you want to allocate.
+         *  @param preallocatedMemory Pointer to the preallocated memory
+         *  you are dedicating to this pool.
+         *  @param preallocatedMemorySize How big is the buffer you are
+         *  passing in.
+         *  @param Alignment Power of 2 value denoting on which address boundary the
+         *      memory will be aligned to. Must be at least sizeof(unsigned char *).
+         *  @throws MemoryPoolBadAlignmentException on failure.
+         */
+        MemoryPool( int itemSize,
+                    void *preallocatedMemory,
+                    int preallocatedMemorySize,
+                    int alignment);
+
+        /**
+         *  Allows you to add memory to a MemoryPool.
+         *
+         *  Items will be the same size as you initially asked for.
+         *
+         *  @param itemCount How many more items max do you want to allocate
+         *  @throws MemoryPoolMallocException on failure.
+         */
+        void AddMemory(int itemCount);
+
+        /**
+         *  Allows you to add memory to a MemoryPool.
+         *
+         *  Items will be the same size as you initially asked for.
+         *
+         *  @param preallocatedMemory Pointer to the preallocated memory
+         *  you are dedicating to this pool.
+         *  @param preallocatedMemorySize How big is the buffer you are
+         *  passing in.
+         */
+        void AddMemory( void *preallocatedMemory,
+                        int preallocatedMemorySize);
+
+        /**
+         *  Allocate an item from the pool.
+         *
+         *  @return Pointer of the memory or NULL if the pool is empty.
+         */
+        void *Allocate();
+
+        /**
+         *  Returns the item back to it's pool.
+         *
+         *  @note There is no checking that the item is actually
+         *  valid to be returned to this pool.
+         */
+        void Free(void *item);
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Private API
+    //  The internals of this class.
+    //
+    /////////////////////////////////////////////////////////////////////////
+    private:
+
+        /**
+         *  Standard Mutex to allow thread safety.
+         */
+        Mutex *Lock;
+
+        /**
+         *  Save the item size for additions.
+         */
+        int ItemSize;
+
+        /**
+         *  The overall alignment of an item.
+         */
+        int Alignment;
+
+        /**
+         *  All of the real work is done with STL lists.
+         */
+        std::list<void *>FreeItems;
+
+        /**
+         *  Adjusts and validates the alignment argument
+         *  passed in the ctor.
+         */
+        void CalculateValidAlignment();
+
+        /**
+         *  Calculate the true item size, based on alignment.
+         */
+        void CalculateItemSize();
+
+//
+//  If we are using C++11 or later, take advantage of the
+//  newer features to find bugs.
+//
+#if __cplusplus >= 201103L
+        /**
+         *  To correctly delete a Memory Pool, we'd have to guarantee that
+         *  all allocations had been returned to us. We side step this issue
+         *  as well as all the associated overhead with supporting this by
+         *  not allowing destructors.
+         */
+        ~MemoryPool() = delete;
+#else
+        /**
+         *  To correctly delete a Memory Pool, we'd have to guarantee that
+         *  all allocations had been returned to us. We side step this issue
+         *  by making the destructor private so it can't be accessed.
+         */
+        ~MemoryPool();
+#endif
+
+
+};
+
+
+}
+
+#endif
+

+ 305 - 0
addons/c++/include/mutex.hpp

@@ -0,0 +1,305 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef MUTEX_HPP_
+#define MUTEX_HPP_
+
+/**
+ *  C++ exceptions are used by default when constructors fail.
+ *  If you do not want this behavior, define the following in your makefile
+ *  or project. Note that in most / all cases when a constructor fails,
+ *  it's a fatal error. In the cases when you've defined this, the new 
+ *  default behavior will be to issue a configASSERT() instead.
+ */
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+#include <exception>
+#include <string>
+#include <cstdio>
+#ifdef CPP_FREERTOS_NO_CPP_STRINGS
+#error "FreeRTOS-Addons require C++ Strings if you are using exceptions"
+#endif
+#endif
+#include "FreeRTOS.h"
+#include "semphr.h"
+
+namespace cpp_freertos {
+
+
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+/**
+ *  This is the exception that is thrown if a Mutex constructor fails.
+ */
+class MutexCreateException : public std::exception {
+
+    public:
+        /**
+         *  Create the exception.
+         */
+        MutexCreateException()
+        {
+            sprintf(errorString, "Mutex Constructor Failed");
+        }
+
+        /**
+         *  Get what happened as a string.
+         *  We are overriding the base implementation here.
+         */
+        virtual const char *what() const throw()
+        {
+            return errorString;
+        }
+
+    private:
+        /**
+         *  A text string representing what failed.
+         */
+        char errorString[80];
+};
+#endif
+
+
+/**
+ *  Base wrapper class around FreeRTOS's implementation of mutexes.
+ *
+ *  By definition, Mutexes can @em NOT be used from ISR contexts.
+ *
+ *  @note It is expected that an application will instantiate one of the
+ *        derived classes and use that object for synchronization. It is
+ *        not expected that a user or application will derive from these
+ *        classes.
+ */
+class Mutex {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+        /**
+         *  Lock the Mutex.
+         *
+         *  Each type of Mutex implements it's own locking code as per the
+         *  FreeRTOS API.
+         *
+         *  @param Timeout How long to wait to get the Lock until giving up.
+         *  @return true if the Lock was acquired, false if it timed out.
+         */
+        virtual bool Lock(TickType_t Timeout = portMAX_DELAY) = 0;
+
+        /**
+         *  Unlock the Mutex.
+         *
+         *  @return true if the Lock was released, false if it failed. (Hint,
+         *           if it fails, did you call Lock() first?)
+         */
+        virtual bool Unlock() = 0;
+
+        /**
+         *  Our destructor
+         */
+        virtual ~Mutex();
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Protected API
+    //  Not intended for use by application code.
+    //
+    /////////////////////////////////////////////////////////////////////////
+    protected:
+        /**
+         *  FreeRTOS semaphore handle.
+         */
+        SemaphoreHandle_t handle;
+
+        /**
+         *  This constructor should not be public.
+         */
+        Mutex();
+};
+
+
+/**
+ *  Standard usage Mutex.
+ *  By default calls to Lock these objects block forever, but this can be
+ *  changed by simply passing in a argument to the Lock() method.
+ *  These objects are not recursively acquirable. Calling Lock() twice from
+ *  the same Thread (i.e. task) will deadlock.
+ *
+ *  @note Standard mutexes use less resources than recursive mutexes. You
+ *        should typically use this type of Mutex, unless you have a strong
+ *        need for a MutexRecursive mutex.
+ */
+class MutexStandard : public Mutex {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+        /**
+         *  Create a standard, non-recursize Mutex.
+         *
+         *  @throws ThreadMutexException on failure.
+         */
+        MutexStandard();
+
+        /**
+         *  Lock the Mutex.
+         *
+         *  @param Timeout How long to wait to get the Lock until giving up.
+         *  @return true if the Lock was acquired, false if it timed out.
+         */
+        virtual bool Lock(TickType_t Timeout = portMAX_DELAY);
+
+        /**
+         *  Unlock the Mutex.
+         *
+         *  @return true if the Lock was released, false if it failed. (Hint,
+         *           if it fails, did you call Lock() first?)
+         */
+        virtual bool Unlock();
+};
+
+
+#if (configUSE_RECURSIVE_MUTEXES == 1)
+
+/**
+ *  Recursive usage Mutex.
+ *
+ *  By default calls to Lock these objects block forever, but this can be
+ *  changed by simply passing in a argument to the Lock() method.
+ *  These objects are recursively acquirable. Calling Lock() twice from
+ *  the same Thread (i.e. task) works fine. The caller just needs to be sure to
+ *  call Unlock() as many times as Lock().
+ *
+ *  @note Recursive mutexes use more resources than standard mutexes. You
+ *        should be sure that you actually need this type of synchronization
+ *        before using it.
+ */
+class MutexRecursive : public Mutex {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+        /**
+         *  Create a recursize Mutex.
+         *
+         *  @throws ThreadMutexException on failure.
+         */
+        MutexRecursive();
+
+        /**
+         *  Lock the Mutex.
+         *
+         *  @param Timeout How long to wait to get the Lock until giving up.
+         *  @return true if the Lock was acquired, false if it timed out.
+         */
+        virtual bool Lock(TickType_t Timeout = portMAX_DELAY);
+
+        /**
+         *  Unlock the Mutex.
+         *
+         *  @return true if the Lock was released, false if it failed. (Hint,
+         *           if it fails, did you call Lock() first?)
+         */
+        virtual bool Unlock();
+};
+
+#endif
+
+
+/**
+ *  Synchronization helper class that leverages the C++ language to help
+ *  prevent deadlocks.
+ *  This is a C++11 feature that allows Mutex Locking and Unlocking to behave
+ *  following an RAII style. The constructor of this helper object locks the
+ *  Mutex. The destructor unlocks the Mutex. Since C++ guarantees that an
+ *  object's desctuctor is always called when it goes out of scope, calls to
+ *  Unlock become unnecessary and are in fact guaranteed as long as correct
+ *  scoping is used.
+ */
+class LockGuard {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+        /**
+         *  Create a LockGuard with a specific Mutex.
+         *
+         *  @post The Mutex will be locked.
+         *  @note There is an infinite timeout for acquiring the Lock.
+         */
+        explicit LockGuard(Mutex& m);
+
+        /**
+         *  Destroy a LockGuard.
+         *
+         *  @post The Mutex will be unlocked.
+         */
+        ~LockGuard();
+
+        /////////////////////////////////////////////////////////////////////////
+        //
+        //  Private API
+        //
+        /////////////////////////////////////////////////////////////////////////
+    private:
+        /**
+         *  We do not want a copy constructor.
+         */
+        LockGuard(const LockGuard&);
+
+        /**
+         *  Reference to the Mutex we locked, so it can be unlocked
+         *  in the destructor.
+         */
+        Mutex& mutex;
+};
+
+
+}
+#endif

+ 351 - 0
addons/c++/include/queue.hpp

@@ -0,0 +1,351 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef QUEUE_HPP_
+#define QUEUE_HPP_
+
+/**
+ *  C++ exceptions are used by default when constructors fail.
+ *  If you do not want this behavior, define the following in your makefile
+ *  or project. Note that in most / all cases when a constructor fails,
+ *  it's a fatal error. In the cases when you've defined this, the new 
+ *  default behavior will be to issue a configASSERT() instead.
+ */
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+#include <exception>
+#include <cstdio>
+#include <string>
+#ifdef CPP_FREERTOS_NO_CPP_STRINGS
+#error "FreeRTOS-Addons require C++ Strings if you are using exceptions"
+#endif
+#endif
+#include "FreeRTOS.h"
+#include "queue.h"
+
+
+namespace cpp_freertos {
+
+
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+/**
+ *  This is the exception that is thrown if a Queue constructor fails.
+ */
+class QueueCreateException : public std::exception {
+
+    public:
+        /**
+         *  Create the exception.
+         */
+        QueueCreateException()
+        {
+            sprintf(errorString, "Queue Constructor Failed");
+        }
+
+        /**
+         *  Create the exception.
+         */
+        explicit QueueCreateException(const char *info)
+        {
+            snprintf(errorString, sizeof(errorString),
+                        "Queue Constructor Failed %s", info);
+        }
+
+        /**
+         *  Get what happened as a string.
+         *  We are overriding the base implementation here.
+         */
+        virtual const char *what() const throw()
+        {
+            return errorString;
+        }
+
+    private:
+        /**
+         *  A text string representing what failed.
+         */
+        char errorString[80];
+};
+#endif
+
+
+/**
+ *  Queue class wrapper for FreeRTOS queues. This class provides enqueue
+ *  and dequeue operations.
+ *
+ *  @note It is expected that an application will instantiate this class or
+ *        one of the derived classes and use that. It is not expected that
+ *        a user or application will derive from these classes.
+ */
+class Queue {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+        /**
+         *  Our constructor.
+         *
+         *  @throws QueueCreateException
+         *  @param maxItems Maximum number of items this queue can hold.
+         *  @param itemSize Size of an item in a queue.
+         *  @note FreeRTOS queues use a memcpy / fixed size scheme for queues.
+         */
+        Queue(UBaseType_t maxItems, UBaseType_t itemSize);
+
+        /**
+         *  Our destructor.
+         */
+        virtual ~Queue();
+
+        /**
+         *  Add an item to the back of the queue.
+         *
+         *  @param item The item you are adding.
+         *  @return true if the item was added, false if it was not.
+         */
+        virtual bool Enqueue(void *item);
+
+        /**
+         *  Add an item to the back of the queue.
+         *
+         *  @param item The item you are adding.
+         *  @param Timeout How long to wait to add the item to the queue if
+         *         the queue is currently full.
+         *  @return true if the item was added, false if it was not.
+         */
+        virtual bool Enqueue(void *item, TickType_t Timeout);
+
+        /**
+         *  Remove an item from the front of the queue.
+         *
+         *  @param item Where the item you are removing will be returned to.
+         *  @param Timeout How long to wait to remove an item if the queue
+         *         is currently empty.
+         *  @return true if an item was removed, false if no item was removed.
+         */
+        bool Dequeue(void *item, TickType_t Timeout = portMAX_DELAY);
+
+        /**
+         *  Make a copy of an item from the front of the queue. This will
+         *  not remove it from the head of the queue.
+         *
+         *  @param item Where the item you are removing will be returned to.
+         *  @param Timeout How long to wait to remove an item if the queue
+         *         is currently empty.
+         *  @return true if an item was copied, false if no item was copied.
+         */
+        bool Peek(void *item, TickType_t Timeout = portMAX_DELAY);
+
+        /**
+         *  Add an item to the back of the queue in ISR context.
+         *
+         *  @param item The item you are adding.
+         *  @param pxHigherPriorityTaskWoken Did this operation result in a
+         *         rescheduling event.
+         *  @return true if the item was added, false if it was not.
+         */
+        virtual bool EnqueueFromISR(void *item, BaseType_t *pxHigherPriorityTaskWoken);
+
+        /**
+         *  Remove an item from the front of the queue in ISR context.
+         *
+         *  @param item Where the item you are removing will be returned to.
+         *  @param pxHigherPriorityTaskWoken Did this operation result in a
+         *         rescheduling event.
+         *  @return true if an item was removed, false if no item was removed.
+         */
+        bool DequeueFromISR(void *item, BaseType_t *pxHigherPriorityTaskWoken);
+
+        /**
+         *  Make a copy of an item from the front of the queue. This will
+         *  not remove it from the head of the queue.
+         *
+         *  @param item Where the item you are removing will be returned to.
+         *  @return true if an item was copied, false if no item was copied.
+         */
+        bool PeekFromISR(void *item);
+
+        /**
+         *  Is the queue empty?
+         *  @return true if the queue was empty when this was called, false if
+         *  the queue was not empty.
+         */
+        bool IsEmpty();
+
+        /**
+         *  Is the queue full?
+         *  @return true if the queue was full when this was called, false if
+         *  the queue was not full.
+         */
+        bool IsFull();
+
+        /**
+         *  Remove all objects from the queue.
+         */
+        void Flush();
+
+        /**
+         *  How many items are currently in the queue.
+         *  @return the number of items in the queue.
+         */
+        UBaseType_t NumItems();
+
+        /**
+         *  How many empty spaves are currently left in the queue.
+         *  @return the number of remaining spaces.
+         */
+        UBaseType_t NumSpacesLeft();
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Protected API
+    //  Not intended for use by application code.
+    //
+    /////////////////////////////////////////////////////////////////////////
+    protected:
+        /**
+         *  FreeRTOS queue handle.
+         */
+        QueueHandle_t handle;
+};
+
+
+/**
+ *  Enhanced queue class that implements a double ended queue (a "deque"),
+ *  almost. Unlike the traditional CommSci version, there is no way to
+ *  dequeue from the back. Practically, this most likely isn't a big deal.
+ *
+ *  @note It is expected that an application will instantiate this class or
+ *        one of the derived classes and use that. It is not expected that
+ *        a user or application will derive from these classes.
+ */
+class Deque : public Queue {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+        /**
+         *  Our constructor.
+         *
+         *  @throws QueueCreateException
+         *  @param maxItems Maximum number of items thsi queue can hold.
+         *  @param itemSize Size of an item in a queue.
+         *  @note FreeRTOS queues use a memcpy / fixed size scheme for queues.
+         */
+        Deque(UBaseType_t maxItems, UBaseType_t itemSize);
+
+        /**
+         *  Add an item to the front of the queue. This will result in
+         *  the item being removed first, ahead of all of the items
+         *  added by the base calss Dequeue() function.
+         *
+         *  @param item The item you are adding.
+         *  @param Timeout How long to wait to add the item to the queue if
+         *         the queue is currently full.
+         *  @return true if the item was added, false if it was not.
+         */
+        bool EnqueueToFront(void *item, TickType_t Timeout = portMAX_DELAY);
+
+        /**
+         *  Add an item to the front of the queue. This will result in
+         *  the item being removed first, ahead of all of the items
+         *  added by the base calss Dequeue() function.
+         *
+         *  @param item The item you are adding.
+         *  @param pxHigherPriorityTaskWoken Did this operation result in a
+         *         rescheduling event.
+         *  @return true if the item was added, false if it was not.
+         */
+        bool EnqueueToFrontFromISR(void *item, BaseType_t *pxHigherPriorityTaskWoken);
+};
+
+
+/**
+ *  Binary queue with overwrite. This queue can only hold one item.
+ *  If sucessive Enqueue operations are called, that item is overwritten
+ *  with whatever the last item was.
+ *
+ *  @note It is expected that an application will instantiate this class or
+ *        one of the derived classes and use that. It is not expected that
+ *        a user or application will derive from these classes.
+ */
+class BinaryQueue : public Queue {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+        /**
+         *  Our constructor.
+         *
+         *  @throws QueueCreateException
+         *  @param itemSize Size of an item in a queue.
+         *  @note FreeRTOS queues use a memcpy / fixed size scheme for queues.
+         */
+        explicit BinaryQueue(UBaseType_t itemSize);
+
+         /**
+          *  Add an item to the queue.
+          *
+          *  @param item The item you are adding.
+          *  @return true always, because of overwrite.
+          */
+        virtual bool Enqueue(void *item);
+
+         /**
+          *  Add an item to the queue in ISR context.
+          *
+          *  @param item The item you are adding.
+          *  @param pxHigherPriorityTaskWoken Did this operation result in a
+          *         rescheduling event.
+          *  @return true always, because of overwrite.
+          */
+        virtual bool EnqueueFromISR(void *item, BaseType_t *pxHigherPriorityTaskWoken);
+};
+
+
+}
+#endif

+ 285 - 0
addons/c++/include/read_write_lock.hpp

@@ -0,0 +1,285 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef READ_WRITE_LOCK_HPP_
+#define READ_WRITE_LOCK_HPP_
+
+
+/**
+ *  C++ exceptions are used by default when constructors fail.
+ *  If you do not want this behavior, define the following in your makefile
+ *  or project. Note that in most / all cases when a constructor fails,
+ *  it's a fatal error. In the cases when you've defined this, the new 
+ *  default behavior will be to issue a configASSERT() instead.
+ */
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+#include <exception>
+#include <string>
+#include <cstdio>
+#ifdef CPP_FREERTOS_NO_CPP_STRINGS
+#error "FreeRTOS-Addons require C++ Strings if you are using exceptions"
+#endif
+#endif
+#include "FreeRTOS.h"
+#include "semphr.h"
+
+
+namespace cpp_freertos {
+
+
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+/**
+ *  This is the exception that is thrown if a ReadWriteLock constructor fails.
+ */
+class ReadWriteLockCreateException : public std::exception {
+
+    public:
+        /**
+         *  Create the exception.
+         */
+        ReadWriteLockCreateException()
+        {
+            sprintf(errorString, "ReadWriteLock Constructor Failed");
+        }
+
+        /**
+         *  Get what happened as a string.
+         *  We are overriding the base implementation here.
+         */
+        virtual const char *what() const throw()
+        {
+            return errorString;
+        }
+
+    private:
+        /**
+         *  A text string representing what failed.
+         */
+        char errorString[80];
+};
+#endif
+
+
+/**
+ *  Abstract base class encapsulating a Reader/Writer lock.
+ *
+ *  These locks are based on mutexs and cannot be used in any way from
+ *  ISR context. Likewise, these locks block indefinitely.
+ *
+ *  @note It is expected that an application will instantiate one of the
+ *        derived classes and use that object for synchronization. It is
+ *        not expected that a user or application will derive from these
+ *        classes.
+ */
+class ReadWriteLock {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+        /**
+         *  Constructor
+         *
+         *  @throws ReadWriteLockCreateException on failure.
+         */
+        ReadWriteLock();
+
+        /**
+         *  Destructor
+         */
+        virtual ~ReadWriteLock();
+
+        /**
+         *  Take the lock as a Reader.
+         *  This allows multiple reader access.
+         */
+        virtual void ReaderLock() = 0;
+
+        /**
+         *  Unlock the Reader.
+         */
+        virtual void ReaderUnlock() = 0;
+
+        /**
+         *  Take the lock as a Writer.
+         *  This allows only one thread access.
+         */
+        virtual void WriterLock() = 0;
+
+        /**
+         *  Unlock the Writer.
+         */
+        virtual void WriterUnlock() = 0;
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Protected API
+    //  Not intended for use by application code.
+    //
+    /////////////////////////////////////////////////////////////////////////
+    protected:
+        /**
+         *  How many active readers are there.
+         */
+        int ReadCount;
+
+        /**
+         *  Protect ReadCount.
+         */
+        SemaphoreHandle_t ReadLock;
+
+        /**
+         *  Protect this resource from multiple writer access, or
+         *  from Reader access when a writer is changing something.
+         */
+        SemaphoreHandle_t ResourceLock;
+};
+
+
+/**
+ *  Concrete derived class that implements a Reader/Writer lock
+ *  that favors the Readers. That is, with enough aggressive readers,
+ *  a Writer may starve.
+ */
+class ReadWriteLockPreferReader : public ReadWriteLock {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+        /**
+         *  Take the lock as a Reader.
+         *  This allows multiple reader access.
+         */
+        virtual void ReaderLock();
+
+        /**
+         *  Unlock the Reader.
+         */
+        virtual void ReaderUnlock();
+
+        /**
+         *  Take the lock as a Writer.
+         *  This allows only one thread access.
+         */
+        virtual void WriterLock();
+
+        /**
+         *  Unlock the Writer.
+         */
+        virtual void WriterUnlock();
+};
+
+
+/**
+ *  Concrete derived class that implements a Reader/Writer lock
+ *  that favors the Writers. That is, with enough aggressive writers,
+ *  a Reader may starve.
+ */
+class ReadWriteLockPreferWriter : public ReadWriteLock {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+        /**
+         *  Our derived constructor.
+         */
+        ReadWriteLockPreferWriter();
+
+        /**
+         *  Our derived destructor.
+         */
+        virtual ~ReadWriteLockPreferWriter();
+
+        /**
+         *  Take the lock as a Reader.
+         *  This allows multiple reader access.
+         */
+        virtual void ReaderLock();
+
+        /**
+         *  Unlock the Reader.
+         */
+        virtual void ReaderUnlock();
+
+        /**
+         *  Take the lock as a Writer.
+         *  This allows only one thread access.
+         */
+        virtual void WriterLock();
+
+        /**
+         *  Unlock the Writer.
+         */
+        virtual void WriterUnlock();
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Private API
+    //  The internals of this wrapper class.
+    //
+    /////////////////////////////////////////////////////////////////////////
+    private:
+        /**
+         *  Number of Writers waiting for the Resource Lock, including any
+         *  current Writer already holdign it.
+         */
+        int WriteCount;
+
+        /**
+         *  Protect WriteCount.
+         */
+        SemaphoreHandle_t WriteLock;
+
+        /**
+         *  Lock to stop reader threads from starving a Writer.
+         */
+        SemaphoreHandle_t BlockReadersLock;
+};
+
+
+}
+#endif

+ 238 - 0
addons/c++/include/semaphore.hpp

@@ -0,0 +1,238 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef SEMAPHORE_HPP_
+#define SEMAPHORE_HPP_
+
+/**
+ *  C++ exceptions are used by default when constructors fail.
+ *  If you do not want this behavior, define the following in your makefile
+ *  or project. Note that in most / all cases when a constructor fails,
+ *  it's a fatal error. In the cases when you've defined this, the new 
+ *  default behavior will be to issue a configASSERT() instead.
+ */
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+#include <exception>
+#include <string>
+#include <cstdio>
+#ifdef CPP_FREERTOS_NO_CPP_STRINGS
+#error "FreeRTOS-Addons require C++ Strings if you are using exceptions"
+#endif
+#endif
+#include "FreeRTOS.h"
+#include "semphr.h"
+
+
+namespace cpp_freertos {
+
+
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+/**
+ *  This is the exception that is thrown if a Semaphore constructor fails.
+ */
+class SemaphoreCreateException : public std::exception {
+
+    public:
+        /**
+         *  Create the exception.
+         */
+        SemaphoreCreateException()
+        {
+            sprintf(errorString, "Semaphore Constructor Failed");
+        }
+
+        /**
+         *  Create the exception.
+         */
+        explicit SemaphoreCreateException(const char *info)
+        {
+            snprintf(errorString, sizeof(errorString),
+                        "Semaphore Constructor Failed %s", info);
+        }
+
+        /**
+         *  Get what happened as a string.
+         *  We are overriding the base implementation here.
+         */
+        virtual const char *what() const throw()
+        {
+            return errorString;
+        }
+
+    private:
+        /**
+         *  A text string representing what failed.
+         */
+        char errorString[80];
+};
+#endif
+
+
+/**
+ *
+ *  Base wrapper class around FreeRTOS's implementation of semaphores.
+ *
+ *  It is not expected that an application will derive from this class.
+ *
+ *  Note that we distinguish between Semaphore, Binary Semaphores,
+ *  Counting Semaphores, and Mutexes. Mutexes, while implemented as a kind
+ *  of semaphore in FreeRTOS, are conceptually very different in use and
+ *  behavior from semaphores. We acknowledge this difference in the class
+ *  heirarchy, implementing mutextes as a completely different class heirarchy.
+ */
+class Semaphore {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+        /**
+         *  Aquire (take) a semaphore.
+         *
+         *  Example of blocking indefinitely:
+         *      aSemaphore.Take();
+         *
+         *  Example of blocking for 100 ticks:
+         *      aSemaphore.Take(100);
+         *
+         *  @param Timeout How long to wait to get the Lock until giving up.
+         *  @return true if the Semaphore was acquired, false if it timed out.
+         */
+        bool Take(TickType_t Timeout = portMAX_DELAY);
+
+        /**
+         *  Release (give) a semaphore.
+         *
+         *  @return true if the Semaphore was released, false if it failed.
+         */
+        bool Give();
+
+        /**
+         *  Aquire (take) a semaphore from ISR context.
+         *
+         *  @param pxHigherPriorityTaskWoken Did this operation result in a
+         *         rescheduling event.
+         *  @return true if the Semaphore was acquired, false if it timed out.
+         */
+        bool TakeFromISR(BaseType_t *pxHigherPriorityTaskWoken);
+
+        /**
+         *  Release (give) a semaphore from ISR context.
+         *
+         *  @param pxHigherPriorityTaskWoken Did this operation result in a
+         *         rescheduling event.
+         *  @return true if the Semaphore was released, false if it failed.
+         */
+        bool GiveFromISR(BaseType_t *pxHigherPriorityTaskWoken);
+
+        /**
+         *  Our destructor
+         */
+        virtual ~Semaphore();
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Protected API
+    //  Not intended for use by application code.
+    //
+    /////////////////////////////////////////////////////////////////////////
+    protected:
+        /**
+         *  FreeRTOS semaphore handle.
+         */
+        SemaphoreHandle_t handle;
+
+        /**
+         *  We do not want a Semaphore ctor. This class should never be
+         *  directly created, this is a base class only.
+         */
+        Semaphore();
+};
+
+
+/**
+ *  Wrapper class for Binary Semaphores.
+ */
+class BinarySemaphore : public Semaphore {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+        /**
+         *  Constructor to create a binary semaphore.
+         *
+         *  @param set Is this semaphore "full" or not?
+         *  @throws SemaphoreCreateException on failure.
+         *  @return Instance of a BinarySemaphore.
+         */
+        explicit BinarySemaphore(bool set = false);
+};
+
+
+/**
+ *  Wrapper class for Counting Semaphores.
+ */
+class CountingSemaphore : public Semaphore {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+        /**
+         *  Constructor to create a counting semaphore.
+         *  This ctor throws a SemaphoreCreateException on failure.
+         *
+         *  @param maxCount Must be greater than 0.
+         *  @param initialCount Must not be greater than maxCount.
+         *  @throws SemaphoreCreateException on failure.
+         *  @return Instance of a CountingSemaphore.
+         */
+        CountingSemaphore(UBaseType_t maxCount, UBaseType_t initialCount);
+};
+
+
+}
+#endif

+ 214 - 0
addons/c++/include/tasklet.hpp

@@ -0,0 +1,214 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef TASKLET_HPP_
+#define TASKLET_HPP_
+
+
+/**
+ *  C++ exceptions are used by default when constructors fail.
+ *  If you do not want this behavior, define the following in your makefile
+ *  or project. Note that in most / all cases when a constructor fails,
+ *  it's a fatal error. In the cases when you've defined this, the new 
+ *  default behavior will be to issue a configASSERT() instead.
+ */
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+#include <exception>
+#include <string>
+#include <cstdio>
+#ifdef CPP_FREERTOS_NO_CPP_STRINGS
+#error "FreeRTOS-Addons require C++ Strings if you are using exceptions"
+#endif
+#endif
+#include "FreeRTOS.h"
+#include "timers.h"
+#include "semphr.h"
+
+
+namespace cpp_freertos {
+
+
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+/**
+ *  This is the exception that is thrown if a Tasklet constructor fails.
+ */
+class TaskletCreateException : public std::exception {
+
+    public:
+        /**
+         *  Create the exception.
+         */
+        TaskletCreateException()
+        {
+            sprintf(errorString, "Tasklet Constructor Failed");
+        }
+
+        /**
+         *  Create the exception.
+         */
+        explicit TaskletCreateException(const char *info)
+        {
+            snprintf(errorString, sizeof(errorString),
+                        "Tasklet Constructor Failed %s", info);
+        }
+
+        /**
+         *  Get what happened as a string.
+         *  We are overriding the base implementation here.
+         */
+        virtual const char *what() const throw()
+        {
+            return errorString;
+        }
+
+    private:
+        /**
+         *  A text string representing what failed.
+         */
+        char errorString[80];
+};
+#endif
+
+
+/**
+ *  A FreeRTOS wrapper for its concept of a Pended Function.
+ *  In Linux, one permutation of this would be a Tasklet, or
+ *  bottom half processing from an ISR.
+ *
+ *  This is an abstract base class.
+ *  To use this, you need to subclass it. All of your Tasklets should
+ *  be derived from the Tasklet class. Then implement the virtual Run
+ *  function. This is a similar design to Java threading.
+ */
+class Tasklet {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+        /**
+         *  Constructor
+         *  @note Do not construct inside an ISR! This includes creating 
+         *  local instances of this object.
+         */
+        Tasklet();
+
+        /**
+         *  Destructor
+         *  @note Do not delete inside an ISR! This includes the automatic 
+         *  deletion of local instances of this object when leaving scope.
+         */
+        virtual ~Tasklet();
+
+        /**
+         *  Schedule this Tasklet to run.
+         *
+         *  @param parameter Value passed to your Run method.
+         *  @param CmdTimeout How long to wait to send this command to the
+         *         timer daemon.
+         *  @returns true if this command will be sent to the timer daemon,
+         *           false if it will not (i.e. timeout).
+         */
+        bool Schedule(  uint32_t parameter,
+                        TickType_t CmdTimeout = portMAX_DELAY);
+
+        /**
+         *  Schedule this Tasklet to run from ISR context.
+         *  This allows FreeRTOS ISRs to defer processing from the ISR
+         *  into a task context.
+         *
+         *  @param parameter Value passed to your Run method.
+         *  @param pxHigherPriorityTaskWoken Did this operation result in a
+         *         rescheduling event.
+         *  @returns true if this command will be sent to the timer daemon,
+         *           false if it will not (i.e. timeout).
+         */
+        bool ScheduleFromISR(   uint32_t parameter,
+                                BaseType_t *pxHigherPriorityTaskWoken);
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Protected API
+    //  Available from inside your Tasklet implementation.
+    //  You should make sure that you are only calling these methods
+    //  from within your Run() method, or that your Run() method is on the
+    //  callstack.
+    //
+    /////////////////////////////////////////////////////////////////////////
+    protected:
+        /**
+         *  Implementation of your actual tasklet code.
+         *  You must override this function.
+         *
+         *  @param parameter Value passed to you from the Schedule() methods.
+         */
+        virtual void Run(uint32_t parameter) = 0;
+
+        /**
+         *  You must call this in your dtor, to synchronize between 
+         *  being called and being deleted.
+         */
+        void CheckForSafeDelete();
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Private API
+    //  The internals of this wrapper class.
+    //
+    /////////////////////////////////////////////////////////////////////////
+    private:
+        /**
+         *  Adapter function that allows you to write a class
+         *  specific Run() function that interfaces with FreeRTOS.
+         *  Look at the implementation of the constructors and this
+         *  code to see how the interface between C and C++ is performed.
+         */
+        static void TaskletAdapterFunction(void *ref, uint32_t parameter);
+
+        /**
+         *  Protect against accidental deletion before we were executed.
+         */
+        SemaphoreHandle_t DtorLock;
+};
+
+}
+#endif
+

+ 462 - 0
addons/c++/include/thread.hpp

@@ -0,0 +1,462 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef THREAD_HPP_
+#define THREAD_HPP_
+
+/**
+ *  The default in the C++ Wrapper classes is to use the C++ string class. 
+ *  If you do not want this, define the following in your makefile or 
+ *  project, and the Thread class will default to using character arrays
+ *  instead of C++ strings.
+ *
+ *  @note If you define this, you also must define CPP_FREERTOS_NO_EXCEPTIONS.
+ *  Some classes throw exceptions if they cannot be constructed, and the 
+ *  exceptions they throw depend on C++ strings.
+ */
+#ifndef CPP_FREERTOS_NO_CPP_STRINGS
+#include <string>
+#endif
+#include "FreeRTOS.h"
+#include "task.h"
+#include "mutex.hpp"
+#include "semaphore.hpp"
+#include "condition_variable.hpp"
+
+namespace cpp_freertos {
+
+
+/**
+ *  Wrapper class around FreeRTOS's implementation of a task.
+ *
+ *  This is an abstract base class.
+ *  To use this, you need to subclass it. All of your threads should
+ *  be derived from the Thread class. Then implement the virtual Run
+ *  function. This is a similar design to Java threading.
+ *
+ *  By default, we leverage C++ strings for the Thread Name. If this
+ *  is not desirable, define CPP_FREERTOS_NO_CPP_STRINGS and the class
+ *  will fall back to C character arrays.
+ */
+class Thread {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //  Available from anywhere. Many of these require a Thread reference
+    //  if they are operating on a thread.
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+        /**
+         *  Constructor to create a named thread.
+         *
+         *  @param Name Name of the thread. Only useful for debugging.
+         *  @param StackDepth Number of "words" allocated for the Thread stack.
+         *  @param Priority FreeRTOS priority of this Thread.
+         */
+#ifndef CPP_FREERTOS_NO_CPP_STRINGS
+        Thread( const std::string Name,
+                uint16_t StackDepth,
+                UBaseType_t Priority);
+#else
+        Thread( const char *Name,
+                uint16_t StackDepth,
+                UBaseType_t Priority);
+#endif
+
+        /**
+         *  Constructor to create an unnamed thread.
+         *
+         *  @param StackDepth Number of "words" allocated for the Thread stack.
+         *  @param Priority FreeRTOS priority of this Thread.
+         */
+        Thread( uint16_t StackDepth,
+                UBaseType_t Priority);
+
+        /**
+         *  Starts a thread.
+         *
+         *  This is the API call that actually starts the thread running. 
+         *  It creates a backing FreeRTOS task. By separating object creation 
+         *  from starting the Thread, it solves the pure virtual fuction call 
+         *  failure case. If we attempt to automatically call xTaskCreate 
+         *  from the base class constructor, in certain conditions the task 
+         *  starts to run "before" the derived class is constructed! So we 
+         *  don't do that anymore.
+         *
+         *  This may be called from your ctor once you have completed 
+         *  your objects construction (so as the last step). 
+         *
+         *  This should only be called once ever! 
+         */
+        bool Start();
+
+        /**
+         *  Our destructor. This must exist even if FreeRTOS is
+         *  configured to disallow task deletion.
+         */
+        virtual ~Thread();
+
+        /**
+         *  Accessor to get the thread's backing task handle.
+         *  There is no setter, on purpose.
+         *
+         *  @return FreeRTOS task handle.
+         */
+        inline TaskHandle_t GetHandle()
+        {
+            return handle;
+        }
+
+        /**
+         *  Yield the scheduler.
+         */
+        static inline void Yield()
+        {
+            taskYIELD();
+        }
+
+        /**
+         *  Start the scheduler.
+         *
+         *  @note You need to use this call. Do NOT directly call 
+         *  vTaskStartScheduler while using this library.
+         */
+        static inline void StartScheduler()
+        {
+            SchedulerActive = true;
+            vTaskStartScheduler();
+        }
+
+        /**
+         *  End the scheduler.
+         *
+         *  @note Please see the FreeRTOS documentation regarding constraints
+         *  with the implementation of this.
+         *
+         *  @note You need to use this call. Do NOT directly call 
+         *  vTaskEndScheduler while using this library.
+         */
+        static inline void EndScheduler()
+        {
+            vTaskEndScheduler();
+            SchedulerActive = false;
+        }
+
+#if (INCLUDE_vTaskSuspend == 1)
+        /**
+         *  Suspend this thread.
+         *
+         *  @note While a Thread can Suspend() itself, it cannot Resume() 
+         *  itself, becauseit's suspended.
+         */
+        inline void Suspend()
+        {
+            vTaskSuspend(GetHandle());
+        }
+
+        /**
+         *  Resume a specific thread.
+         */
+        inline void Resume()
+        {
+            vTaskResume(GetHandle());
+        }
+#endif
+
+#if (INCLUDE_xTaskResumeFromISR == 1)
+        /**
+         *  Resume a specific thread from ISR context.
+         */
+        inline void ResumeFromISR()
+        {
+            xTaskResumeFromISR(GetHandle());
+        }
+#endif
+
+#if (INCLUDE_uxTaskPriorityGet == 1)
+        /**
+         *  Get the priority of this Thread.
+         *
+         *  @return Priority at the time this was called.
+         */
+        inline UBaseType_t GetPriority()
+        {
+            return (uxTaskPriorityGet(GetHandle()));
+        }
+
+        /**
+         *  Get the priority of this Thread from ISR context.
+         *
+         *  @return Priority at the time this was called.
+         */
+        inline UBaseType_t GetPriorityFromISR()
+        {
+            return (uxTaskPriorityGetFromISR(GetHandle()));
+        }
+#endif
+
+
+#if (INCLUDE_vTaskPrioritySet == 1)
+        /**
+         *  Set the priority of this thread.
+         *
+         *  @param NewPriority The thread's new priority.
+         */
+        inline void SetPriority(UBaseType_t NewPriority)
+        {
+            Priority = NewPriority;
+            vTaskPrioritySet(GetHandle(), NewPriority);
+        }
+#endif
+
+        /**
+         *  Get the name of this thread.
+         *
+         *  @return a C++ string with the name of the task.
+         */
+#ifndef CPP_FREERTOS_NO_CPP_STRINGS
+        inline std::string GetName()
+        {
+            return Name;
+        }
+#else
+        inline char* GetName()
+        {
+            return pcTaskGetName(handle);
+        }
+#endif
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Protected API
+    //  Available from inside your Thread implementation.
+    //  You should make sure that you are only calling these methods
+    //  from within your Run() method, or that your Run() method is on the
+    //  callstack.
+    //
+    /////////////////////////////////////////////////////////////////////////
+    protected:
+        /**
+         *  Implementation of your actual thread code.
+         *  You must override this function.
+         *  @note If INCLUDE_vTaskDelete is defined, then you may return from
+         *  your Run method. This will cause the task to be deleted from
+         *  FreeRTOS, however you are still responsible to delete the
+         *  task object. If this is not defined, then retuning from your Run()
+         *  method will result in an assert.
+         */
+        virtual void Run() = 0;
+
+#if (INCLUDE_vTaskDelete == 1)
+        /**
+         *  Called on exit from your Run() routine. 
+         *  
+         *  It is optional whether you implement this or not.
+         *
+         *  If you allow your Thread to exit its Run method, 
+         *  implementing a Cleanup method allows you to call 
+         *  your Thread's destructor. If you decide to call delete 
+         *  in your Cleanup function, be aware that additional 
+         *  derived classes shouldn't call delete. 
+         */ 
+        virtual void Cleanup();
+#else
+        /**
+         *  If we can't delete a task, it makes no sense to have a
+         *  Cleanup routine.
+         */
+#endif
+
+#if (INCLUDE_vTaskDelay == 1)
+        /**
+         *  Delay this thread for at least Delay ticks.
+         *
+         *  @param Delay How long to delay the thread.
+         */
+        void inline Delay(const TickType_t Delay)
+        {
+            vTaskDelay(Delay);
+        }
+#endif
+
+#if (INCLUDE_vTaskDelayUntil == 1)
+        /**
+         *  Delay this thread for Period ticks, taking into account
+         *  the execution time of the thread.
+         *
+         *  This FreeRTOS permutation of delay can be used by periodic
+         *  tasks to ensure a constant execution frequency.
+         *
+         *  @param Period How long to delay the thread.
+         */
+        void DelayUntil(const TickType_t Period);
+
+        /**
+         *  If you need to adjust or reset the period of the
+         *  DelayUntil method.
+         */
+        void ResetDelayUntil();
+#endif
+
+
+#ifdef CPP_FREERTOS_CONDITION_VARIABLES
+
+        /**
+         *  Have this thread wait on a condition variable.
+         *
+         *  @note Threads wait, while ConditionVariables signal.
+         *
+         *  @param Cv The condition variable associated with the Wait.
+         *  @param CvLock The required condition variable lock. The
+         *  Lock must be held before calling Wait.
+         *  @param Timeout Allows you to specify a timeout on the Wait,
+         *  if desired.
+         *
+         *  @return true if the condition variable was signaled,
+         *  false if it timed out.
+         */
+        bool Wait(  ConditionVariable &Cv,
+                    Mutex &CvLock,
+                    TickType_t Timeout = portMAX_DELAY);
+
+#endif
+
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Private API
+    //  The internals of this wrapper class.
+    //
+    /////////////////////////////////////////////////////////////////////////
+    private:
+        /**
+         *  Reference to the underlying task handle for this thread.
+         *  Can be obtained from GetHandle().
+         */
+        TaskHandle_t handle;
+
+        /**
+         *  We need to track whether the scheduler is active or not.
+         */
+        static volatile bool SchedulerActive;
+
+        /**
+         *  The name of this thread.
+         */
+#ifndef CPP_FREERTOS_NO_CPP_STRINGS
+        const std::string Name;
+#else
+        char Name[configMAX_TASK_NAME_LEN];
+#endif
+
+        /**
+         *  Stack depth of this Thread, in words.
+         */
+        const uint16_t StackDepth;
+
+        /**
+         *  A saved / cached copy of what the Thread's priority is.
+         */
+        UBaseType_t Priority;
+
+        /**
+         *  Flag whether or not the Thread was started.
+         */
+        bool ThreadStarted;
+        
+        /**
+         *  Make sure no one calls Start more than once.
+         */
+        static MutexStandard StartGuardLock;
+
+        /**
+         *  Adapter function that allows you to write a class
+         *  specific Run() function that interfaces with FreeRTOS.
+         *  Look at the implementation of the constructors and this
+         *  code to see how the interface between C and C++ is performed.
+         */
+        static void TaskFunctionAdapter(void *pvParameters);
+
+#if (INCLUDE_vTaskDelayUntil == 1)
+        /**
+         *  Flag denoting if we've setup delay until yet.
+         */
+        bool delayUntilInitialized;
+
+        /**
+         *  Book keeping value for delay until.
+         */
+        TickType_t delayUntilPreviousWakeTime;
+#endif
+
+#ifdef CPP_FREERTOS_CONDITION_VARIABLES
+
+        /**
+         *  How we wait and signal the thread when using condition variables.
+         *  Because a semaphore maintains state, this solves the race
+         *  condition between dropping the CvLock and waiting.
+         */
+        BinarySemaphore ThreadWaitSem;
+
+        /**
+         *  Internal helper function to signal this thread.
+         */
+        inline void Signal()
+        {
+            ThreadWaitSem.Give();
+        }
+
+    /**
+     *  The Thread class and the ConditionVariable class are interdependent.
+     *  If we allow the ConditionVariable class to access the internals of 
+     *  the Thread class, we can reduce the public interface, which is a
+     *  good thing.
+     */
+    friend class ConditionVariable;
+
+#endif
+
+};
+
+
+}
+#endif
+

+ 158 - 0
addons/c++/include/tickhook.hpp

@@ -0,0 +1,158 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef TICK_HOOK_HPP_
+#define TICK_HOOK_HPP_
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include <list>
+
+#if ( configUSE_TICK_HOOK == 1 )
+
+/**
+ *  FreeRTOS expects this function to exist and requires it to be 
+ *  named as such with the following signature.
+ */
+extern "C" void vApplicationTickHook(void);
+
+namespace cpp_freertos {
+
+/**
+ *  Wrapper class for Tick hooks, functions you want to run within 
+ *  the tick ISR. 
+ *
+ *  This is an abstract base class.
+ *  To use this, you need to subclass it. All of your tick functions 
+ *  should be derived from this class. Then implement the virtual Run
+ *  function. 
+ *
+ *  You can register multiple hooks with this class. The order of 
+ *  execution should not be assumed. All tick hooks will execute 
+ *  every tick.
+ */    
+class TickHook {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //  Available from anywhere. 
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+        /**
+         *  Constructor.
+         */
+        TickHook();
+
+        /**
+         *  Destructor
+         */
+        virtual ~TickHook();
+
+        /**
+         *  After this is called your Run routine will execute in the 
+         *  Tick ISR. This registration cannot be done in the base class 
+         *  constructor. Once your object is fully constructed, you "may"
+         *  call this in your derived class's constructor.
+         *  @note Immedately after you call this function, your TickHook
+         *  Run() method will run, perhaps before you even return from this 
+         *  call. You "must" be ready to run before you call Register().
+         */
+        void Register();
+        
+        /**
+         *  Disable the tick hook from running, without removing it 
+         *  from the tick hook list.
+         */
+        void Disable();
+
+        /**
+         *  Enable this Idle Hook to run. This call is not necessary
+         *  if you haven't called Disable.
+         */
+        void Enable();
+        
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Protected API
+    //
+    /////////////////////////////////////////////////////////////////////////
+    protected:
+        /**
+         *  Implementation of your actual Tick Hook code.
+         *  You must override this function.
+         */
+        virtual void Run() = 0;
+
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Private API
+    //  The internals of this wrapper class.
+    //
+    /////////////////////////////////////////////////////////////////////////
+    private:
+        /**
+         *  List of Tick Hook callbacks that are executed in the 
+         *  Tick ISR.
+         */
+        static std::list<TickHook *>Callbacks;
+
+        /**
+         *  Should the tick hook run?
+         */
+        bool Enabled;
+
+    /**
+     *  Allow the global vApplicationTickHook() function access
+     *  to the internals of this class. This simplifies the overall
+     *  design.
+     */
+    friend void ::vApplicationTickHook();
+};
+
+
+
+}
+#endif
+#endif
+
+

+ 113 - 0
addons/c++/include/ticks.hpp

@@ -0,0 +1,113 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef TICKS_HPP_
+#define TICKS_HPP_
+
+#include "FreeRTOS.h"
+#include "task.h"
+
+
+namespace cpp_freertos {
+
+
+/**
+ *  Class encapsulating FreeRTOS idea of a tick.
+ */
+class Ticks {
+
+    public:
+        /**
+         *  Get the current tick count.
+         *
+         *  @return Current tick count.
+         */
+        static inline TickType_t GetTicks()
+        {
+            return xTaskGetTickCount();
+        }
+
+        /**
+         *  Get the current tick count from ISR context.
+         *
+         *  @return Current tick count.
+         */
+        static inline TickType_t GetTicksFromISR()
+        {
+            return xTaskGetTickCountFromISR();
+        }
+
+        /**
+         *  Convert from ticks to ms.
+         *
+         *  @param ticks ticks to convert.
+         *  @return milliseconds.
+         */
+        static inline TickType_t TicksToMs(TickType_t ticks)
+        {
+            return ticks * portTICK_PERIOD_MS;
+        }
+
+        /**
+         *  Convert from ms to ticks.
+         *
+         *  @param milliseconds milliseconds to convert.
+         *  @return ticks
+         */
+        static inline TickType_t MsToTicks(TickType_t milliseconds)
+        {
+            return milliseconds / portTICK_PERIOD_MS;
+        }
+
+        /**
+         *  Convert from seconds to ticks.
+         *
+         *  @param seconds seconds to convert.
+         *  @return ticks
+         */
+        static inline TickType_t SecondsToTicks(TickType_t seconds)
+        {
+            return (seconds * 1000) / portTICK_PERIOD_MS;
+        }
+};
+
+
+}
+#endif
+

+ 292 - 0
addons/c++/include/timer.hpp

@@ -0,0 +1,292 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef TIMER_HPP_
+#define TIMER_HPP_
+
+
+/**
+ *  C++ exceptions are used by default when constructors fail.
+ *  If you do not want this behavior, define the following in your makefile
+ *  or project. Note that in most / all cases when a constructor fails,
+ *  it's a fatal error. In the cases when you've defined this, the new 
+ *  default behavior will be to issue a configASSERT() instead.
+ */
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+#include <exception>
+#include <string>
+#include <cstdio>
+#ifdef CPP_FREERTOS_NO_CPP_STRINGS
+#error "FreeRTOS-Addons require C++ Strings if you are using exceptions"
+#endif
+#endif
+#include "FreeRTOS.h"
+#include "timers.h"
+
+
+namespace cpp_freertos {
+
+
+#ifndef CPP_FREERTOS_NO_EXCEPTIONS
+/**
+ *  This is the exception that is thrown if a Thread constructor fails.
+ */
+class TimerCreateException  : public std::exception {
+
+    public:
+        /**
+         *  Create the exception.
+         */
+        TimerCreateException()
+        {
+            sprintf(errorString, "Timer Constructor Failed");
+        }
+
+        /**
+         *  Get what happened as a string.
+         *  We are overriding the base implementation here.
+         */
+        virtual const char *what() const throw()
+        {
+            return errorString;
+        }
+
+    private:
+        /**
+         *  A text string representing what failed.
+         */
+        char errorString[40];
+};
+#endif
+
+
+/**
+ *  Wrapper class around FreeRTOS's implementation of a timer.
+ *
+ *  This is an abstract base class.
+ *  To use this, you need to subclass it. All of your timers should
+ *  be derived from the Timer class. Then implement the virtual Run
+ *  function. This is a similar design to Java threading.
+ */
+class Timer {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+        /**
+         *  Construct a named timer.
+         *  Timers are not active after they are created, you need to
+         *  activate them via Start, Reset, etc.
+         *
+         *  @throws TimerCreateException
+         *  @param TimerName Name of the timer for debug.
+         *  @param PeriodInTicks When does the timer expire and run your Run()
+         *         method.
+         *  @param Periodic true if the timer expires every PeriodInTicks.
+         *         false if this is a one shot timer.
+         */
+        Timer(  const char * const TimerName,
+                TickType_t PeriodInTicks,
+                bool Periodic = true
+                );
+
+        /**
+         *  Construct an unnamed timer.
+         *  Timers are not active after they are created, you need to
+         *  activate them via Start, Reset, etc.
+         *
+         *  @throws TimerCreateException
+         *  @param PeriodInTicks When does the timer expire and run your Run()
+         *         method.
+         *  @param Periodic true if the timer expires every PeriodInTicks.
+         *         false if this is a one shot timer.
+         */
+        Timer(  TickType_t PeriodInTicks,
+                bool Periodic = true
+                );
+
+        /**
+         *  Destructor
+         */
+        virtual ~Timer();
+
+        /**
+         *  Is the timer currently active?
+         *
+         *  @return true if the timer is active, false otherwise.
+         */
+        bool IsActive();
+
+        /**
+         *  Start a timer. This changes the state to active.
+         *
+         *  @param CmdTimeout How long to wait to send this command to the
+         *         timer code.
+         *  @returns true if this command will be sent to the timer code,
+         *           false if it will not (i.e. timeout).
+         */
+        bool Start(TickType_t CmdTimeout = portMAX_DELAY);
+
+        /**
+         *  Start a timer from ISR context. This changes the state to active.
+         *
+         *  @param pxHigherPriorityTaskWoken Did this operation result in a
+         *         rescheduling event.
+         *  @returns true if this command will be sent to the timer code,
+         *           false if it will not (i.e. timeout).
+         */
+        bool StartFromISR(BaseType_t *pxHigherPriorityTaskWoken);
+
+        /**
+         *  Stop a timer. This changes the state to inactive.
+         *
+         *  @param CmdTimeout How long to wait to send this command to the
+         *         timer code.
+         *  @returns true if this command will be sent to the timer code,
+         *           false if it will not (i.e. timeout).
+         */
+        bool Stop(TickType_t CmdTimeout = portMAX_DELAY);
+
+        /**
+         *  Stop a timer from ISR context. This changes the state to inactive.
+         *
+         *  @param pxHigherPriorityTaskWoken Did this operation result in a
+         *         rescheduling event.
+         *  @returns true if this command will be sent to the timer code,
+         *           false if it will not (i.e. timeout).
+         */
+        bool StopFromISR(BaseType_t *pxHigherPriorityTaskWoken);
+
+        /**
+         *  Reset a timer. This changes the state to active.
+         *
+         *  @param CmdTimeout How long to wait to send this command to the
+         *         timer code.
+         *  @returns true if this command will be sent to the timer code,
+         *           false if it will not (i.e. timeout).
+         */
+        bool Reset(TickType_t CmdTimeout = portMAX_DELAY);
+
+        /**
+         *  Reset a timer from ISR context. This changes the state to active.
+         *
+         *  @param pxHigherPriorityTaskWoken Did this operation result in a
+         *         rescheduling event.
+         *  @returns true if this command will be sent to the timer code,
+         *           false if it will not (i.e. timeout).
+         */
+        bool ResetFromISR(BaseType_t *pxHigherPriorityTaskWoken);
+
+        /**
+         *  Change a timer's period.
+         *
+         *  @param NewPeriod The period in ticks.
+         *  @param CmdTimeout How long to wait to send this command to the
+         *         timer code.
+         *  @returns true if this command will be sent to the timer code,
+         *           false if it will not (i.e. timeout).
+         */
+        bool SetPeriod( TickType_t NewPeriod,
+                        TickType_t CmdTimeout = portMAX_DELAY);
+
+        /**
+         *  Change a timer's period from ISR context.
+         *
+         *  @param NewPeriod The period in ticks.
+         *  @param pxHigherPriorityTaskWoken Did this operation result in a
+         *         rescheduling event.
+         *  @returns true if this command will be sent to the timer code,
+         *           false if it will not (i.e. timeout).
+         */
+        bool SetPeriodFromISR(  TickType_t NewPeriod,
+                                BaseType_t *pxHigherPriorityTaskWoken);
+
+#if (INCLUDE_xTimerGetTimerDaemonTaskHandle == 1)
+        /**
+         *  If you need it, obtain the task handle of the FreeRTOS
+         *  task that is running the timers.
+         *
+         *  @return Task handle of the FreeRTOS timer task.
+         */
+        static TaskHandle_t GetTimerDaemonHandle();
+#endif
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Protected API
+    //  Available from inside your Thread implementation.
+    //  You should make sure that you are only calling these methods
+    //  from within your Run() method, or that your Run() method is on the
+    //  callstack.
+    //
+    /////////////////////////////////////////////////////////////////////////
+    protected:
+        /**
+         *  Implementation of your actual timer code.
+         *  You must override this function.
+         */
+        virtual void Run() = 0;
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Private API
+    //  The internals of this wrapper class.
+    //
+    /////////////////////////////////////////////////////////////////////////
+    private:
+        /**
+         *  Reference to the underlying timer handle.
+         */
+        TimerHandle_t handle;
+
+        /**
+         *  Adapter function that allows you to write a class
+         *  specific Run() function that interfaces with FreeRTOS.
+         *  Look at the implementation of the constructors and this
+         *  code to see how the interface between C and C++ is performed.
+         */
+        static void TimerCallbackFunctionAdapter(TimerHandle_t xTimer);
+};
+
+
+}
+#endif

+ 54 - 0
addons/c++/include/version.hpp

@@ -0,0 +1,54 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef VERSION_CPP_WRAPPERS_HPP_
+#define VERSION_CPP_WRAPPERS_HPP_
+
+
+namespace cpp_freertos {
+
+#define CPP_WRAPPERS_VERSION_MAJOR      1
+#define CPP_WRAPPERS_VERSION_MINOR      5
+#define CPP_WRAPPERS_VERSION_RELEASE    0
+
+#define CPP_WRAPPERS_VERSION_STRING "1.5.0"
+
+}
+#endif
+

+ 247 - 0
addons/c++/include/workqueue.hpp

@@ -0,0 +1,247 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef WORK_QUEUE_HPP_
+#define WORK_QUEUE_HPP_
+
+#include "thread.hpp"
+#include "queue.hpp"
+#include "semaphore.hpp"
+
+
+namespace cpp_freertos {
+
+
+#define DEFAULT_MAX_WORK_ITEMS          10
+#define DEFAULT_WORK_QUEUE_STACK_SIZE   (configMINIMAL_STACK_SIZE * 2)
+#define DEFAULT_WORK_QUEUE_PRIORITY     (tskIDLE_PRIORITY + 1)
+
+
+/**
+ *  This class encapsulates the idea of a discrete, non-repeating task.
+ *  Create a WorkItem when there is something you need to do on a different
+ *  Thread, but doesn't have to happen periodically. This is a great 
+ *  construct for one off fire and forget tasks.
+ *
+ *  This is an abstract base class.
+ *  To use this, you need to subclass it. All of your WorkItems should
+ *  be derived from this class. Then implement the virtual Run
+ *  function. This is a similar design to Java threading.
+ */
+class WorkItem {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+
+        /**
+         *  Our constructor.
+         *
+         *  @param freeAfterComplete If you pass in a true, you are 
+         *  requesing the WorkQueue itself to delete this WorkItem after
+         *  it has run it. 
+         *  @note Only set freeAfterComplete = true if:
+         *  1) You dynamically allocated it (i.e. used "new")
+         *  2) After you call QueueWork() you promise never to touch 
+         *     this object again. 
+         */
+        WorkItem(bool freeAfterComplete = false);
+
+        /**
+         *  Our destructor.
+         */
+        virtual ~WorkItem();
+        
+        /**
+         *  Allows a client to decide if this WorkItem is marked
+         *  for automatic deletion.
+         */
+        bool FreeAfterRun();
+
+        /**
+         *  Implementation of your actual WorkItem function.
+         *  You must override this function.
+         */
+        virtual void Run() = 0;
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Private API
+    //  The internals of this wrapper class.
+    //
+    /////////////////////////////////////////////////////////////////////////
+    private:
+        /**
+         *  Designates whether this WorkItem should be deleted 
+         *  after the WorkQueue has run it.
+         */
+        const bool FreeItemAfterCompleted;
+};
+
+
+/**
+ *  This class is the "engine" for WorkItems. Create one or more WorkQueues
+ *  to accept WorkItems. WorkQueues pull WorkItems off of a FIFO queue and 
+ *  run them sequentially.
+ */
+class WorkQueue {
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Public API
+    //
+    /////////////////////////////////////////////////////////////////////////
+    public:
+        /**
+         *  Constructor to create a named WorkQueue.
+         *
+         *  @throws ThreadCreateException, QueueCreateException, 
+         *          SemaphoreCreateException
+         *  @param Name Name of the thread internal to the WorkQueue. 
+         *         Only useful for debugging.
+         *  @param StackDepth Number of "words" allocated for the Thread stack.
+         *  @param Priority FreeRTOS priority of this Thread.
+         *  @param MaxWorkItems Maximum number of WorkItems this WorkQueue can hold.
+         */
+        WorkQueue(  const char * const Name,
+                    uint16_t StackDepth = DEFAULT_WORK_QUEUE_STACK_SIZE,
+                    UBaseType_t Priority = DEFAULT_WORK_QUEUE_PRIORITY,
+                    UBaseType_t MaxWorkItems = DEFAULT_MAX_WORK_ITEMS);
+
+        /**
+         *  Constructor to create an unnamed WorkQueue.
+         *
+         *  @throws ThreadCreateException, QueueCreateException, 
+         *          SemaphoreCreateException
+         *  @param StackDepth Number of "words" allocated for the Thread stack.
+         *  @param Priority FreeRTOS priority of this Thread.
+         *  @param MaxWorkItems Maximum number of WorkItems this WorkQueue can hold.
+         */
+        WorkQueue(  uint16_t StackDepth = DEFAULT_WORK_QUEUE_STACK_SIZE,
+                    UBaseType_t Priority = DEFAULT_WORK_QUEUE_PRIORITY,
+                    UBaseType_t MaxWorkItems = DEFAULT_MAX_WORK_ITEMS);
+
+#if (INCLUDE_vTaskDelete == 1)
+        /**
+         *  Our destructor.
+         *
+         *  @note Given the multithreaded nature of this class, the dtor 
+         *  may block until the underlying Thread has had a chance to 
+         *  clean up.
+         */
+        ~WorkQueue();
+#else
+//
+//  If we are using C++11 or later, take advantage of the 
+//  newer features to find bugs.
+//
+#if __cplusplus >= 201103L
+        /**
+         *  If we can't delete a task, it makes no sense to have a
+         *  destructor.
+         */
+        ~WorkQueue() = delete;
+#endif
+#endif
+
+        /**
+         *  Send a WorkItem off to be executed.
+         *
+         *  @param work Pointer to a WorkItem.
+         *  @return true if it was queued, false otherwise.
+         *  @note This function may block if the WorkQueue is presently full.
+         */ 
+        bool QueueWork(WorkItem *work);
+
+    /////////////////////////////////////////////////////////////////////////
+    //
+    //  Private API
+    //  The internals of this class.
+    //
+    /////////////////////////////////////////////////////////////////////////
+    private:
+
+        /**
+         *  An internal derived Thread class, in which we do our real work.
+         */
+        class CWorkerThread : public Thread {
+
+            public:
+                CWorkerThread(  const char * const Name,
+                                uint16_t StackDepth,
+                                UBaseType_t Priority,
+                                WorkQueue *Parent);
+
+                CWorkerThread(  uint16_t StackDepth,
+                                UBaseType_t Priority,
+                                WorkQueue *Parent);
+
+                virtual ~CWorkerThread();
+
+            protected:
+                virtual void Run();
+
+            private:
+                const WorkQueue *ParentWorkQueue;
+        };
+        
+        /**
+         *  Pointer to our WorkerThread.
+         */
+        CWorkerThread *WorkerThread;
+
+        /**
+         *  Pointer to our work queue itself.
+         */
+        Queue *WorkItemQueue;
+
+        /**
+         *  Semaphore to support deconstruction without race conditions.
+         */
+        BinarySemaphore *ThreadComplete;
+};
+
+
+}
+#endif
+
+

+ 313 - 0
addons/c/UnitTests/Dlist/main.c

@@ -0,0 +1,313 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "dlist.h"
+
+
+/**
+ *  Deliberately insert the Node link in the middle of the struct.
+ *  This is worst case and tests that we can recover the data after 
+ *  dealing with the Nodes.
+ */
+typedef struct TestDataNode_t_ {
+
+    int Data1;
+    DlNode_t Node;
+    int Data2;
+
+} TestDataNode_t;
+
+
+/*
+ *  Helper function to allocate and init test nodes.
+ */
+TestDataNode_t *CreateTestDataNode(int d1, int d2)
+{
+    TestDataNode_t *n;
+
+    n = malloc(sizeof(TestDataNode_t));
+
+    if (!n)
+        return NULL;
+
+    n->Node.Next = NULL;
+    n->Node.Prev = NULL;
+    n->Data1 = d1;
+    n->Data2 = d2;
+
+    return n;
+}
+
+
+/**
+ *  Helper function to clean up.
+ *  @note You cannot use the DlForEachNode() macro here,
+ *  because we are freeing each element. This would create a condition
+ *  where we were accessing memory that we had just freed if we tried
+ *  to use the macro.
+ */
+void FreeList(DlNode_t *Head)
+{
+    DlNode_t *Cur;
+    TestDataNode_t *Node;
+
+    while (!DlIsListEmpty(Head)) {
+        Cur = DlRemoveNodeFromTail(Head);
+        Node = CONTAINING_RECORD(Cur, TestDataNode_t, Node);
+        free(Node);
+    }
+}
+
+
+/*
+ *  Helper function.
+ *  @note This is a good place to use the ForEachSingleListNode()
+ *  macro.
+ */
+void PrintList(const char *Title, DlNode_t *Head)
+{
+    TestDataNode_t *Node;
+    DlNode_t *Cur;
+
+    printf("\n%s\n", Title);
+    printf("---------------------\n");
+
+    DlForEachNode(Head, Cur) {
+        Node = CONTAINING_RECORD(Cur, TestDataNode_t, Node);
+        printf("DATA: (%d, %d)\n", Node->Data1, Node->Data2);
+    } 
+}
+
+
+void TestMacros(void)
+{
+    TestDataNode_t T;
+
+    printf("Test Macros\n");
+    printf("---------------------\n");
+    printf("OFFSET_OF(Data1) = %d\n", (int)OFFSET_OF(TestDataNode_t, Data1));
+    printf("OFFSET_OF(Node)  = %d\n", (int)OFFSET_OF(TestDataNode_t, Node));
+    printf("OFFSET_OF(Data2) = %d\n", (int)OFFSET_OF(TestDataNode_t, Data2));
+    
+    printf("&T       = %p\n", (void *)&T);
+    printf("&T.Data1 = %p\n", (void *)&T.Data1);
+    printf("&T.Node  = %p\n", (void *)&T.Node);
+    printf("&T.Data2 = %p\n", (void *)&T.Data2);
+
+    printf("CONTAINING_RECORD(Data1) = %p\n", (void *)CONTAINING_RECORD(&T.Data1, TestDataNode_t, Data1));
+    printf("CONTAINING_RECORD(Node)  = %p\n", (void *)CONTAINING_RECORD(&T.Node,  TestDataNode_t, Node));
+    printf("CONTAINING_RECORD(Data2) = %p\n", (void *)CONTAINING_RECORD(&T.Data2, TestDataNode_t, Data2));
+}
+
+
+int main (void)
+{
+    DlNode_t Head;
+    TestDataNode_t *n[5];
+    int i;
+    DlNode_t *Node;
+    TestDataNode_t *TestDataNode;
+
+
+    /* -------------------------------- */
+    TestMacros();
+
+    /* -------------------------------- */
+    DlInitHead(&Head);
+
+    for (i = 0; i < 5; i++)
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+
+    DlAddNodeToHead(&Head, &n[1]->Node);
+    DlAddNodeToHead(&Head, &n[0]->Node);
+
+    DlAddNodeToTail(&Head, &n[3]->Node);
+    DlAddNodeToTail(&Head, &n[4]->Node);
+
+    DlInsertNodeAfter(&n[1]->Node, &n[2]->Node);
+
+    PrintList("Test 1", &Head);
+    FreeList(&Head);
+
+
+    /* Test 2 -------------------------------- */
+    DlInitHead(&Head);
+
+    for (i = 0; i < 5; i++)
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+
+    for (i = 0; i < 5; i++)
+        DlAddNodeToHead(&Head, &n[i]->Node);
+
+    PrintList("Test 2", &Head);
+    FreeList(&Head);
+
+
+    /* Test 3 -------------------------------- */
+    DlInitHead(&Head);
+
+    for (i = 0; i < 5; i++)
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+
+    for (i = 0; i < 5; i++)
+        DlAddNodeToTail(&Head, &n[i]->Node);
+
+    PrintList("Test 3", &Head);
+    FreeList(&Head);
+
+
+    /* Test 4 -------------------------------- */
+    DlInitHead(&Head);
+
+    for (i = 0; i < 5; i++)
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+
+    DlInsertNodeAfter(&Head, &n[0]->Node);
+    for (i = 0; i < (5-1); i++)
+        DlInsertNodeAfter(&n[i]->Node, &n[i+1]->Node);
+
+    PrintList("Test 4", &Head);
+    FreeList(&Head);
+
+
+    /* Test 5 -------------------------------- */
+    DlInitHead(&Head);
+
+    for (i = 0; i < 5; i++)
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+
+    DlAddNodeToHead(&Head, &n[0]->Node);
+    for (i = 0; i < (5-1); i++)
+        DlInsertNodeBefore(&n[i]->Node, &n[i+1]->Node);
+
+    PrintList("Test 5", &Head);
+    FreeList(&Head);
+
+
+
+    DlInitHead(&Head);
+
+    for (i = 0; i < 5; i++) {
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+        DlAddNodeToTail(&Head, &n[i]->Node);
+    }
+
+    PrintList("Start for Tests 6-10", &Head);
+
+
+    /* Test 6 -------------------------------- */
+    DlRemoveNode(&n[0]->Node);
+    PrintList("Test 6", &Head);
+    free(n[0]);
+
+    /* Test 7 -------------------------------- */
+    DlRemoveNode(&n[4]->Node);
+    PrintList("Test 7", &Head);
+    free(n[4]);
+
+    /* Test 8 -------------------------------- */
+    DlRemoveNode(&n[2]->Node);
+    PrintList("Test 8", &Head);
+    free(n[2]);
+
+    /* Test 9 -------------------------------- */
+    DlRemoveNode(&n[1]->Node);
+    PrintList("Test 9", &Head);
+    free(n[1]);
+
+    /* Test 10 -------------------------------- */
+    DlRemoveNode(&n[3]->Node);
+    PrintList("Test 10", &Head);
+    free(n[3]);
+
+
+    /***********************************************************/
+    for (i = 0; i < 5; i++) {
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+        DlAddNodeToTail(&Head, &n[i]->Node);
+    }
+    
+    PrintList("Test 11", &Head);
+
+    for (i = 0; i < 6; i++) {
+        Node = DlRemoveNodeFromHead(&Head);
+        if (Node) {
+            TestDataNode = CONTAINING_RECORD(Node, TestDataNode_t, Node);
+            printf("\n\nRemoved: (%d, %d)\n", TestDataNode->Data1, TestDataNode->Data2);
+        }
+        else {
+            printf("\n\nRemoved: List was empty!\n");
+        }
+        if (i < 5)
+            free(TestDataNode);
+        PrintList("Test 11 - cont", &Head);
+    }
+
+
+    /***********************************************************/
+    for (i = 0; i < 5; i++) {
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+        DlAddNodeToTail(&Head, &n[i]->Node);
+    }
+    
+    PrintList("Test 12", &Head);
+
+    for (i = 0; i < 6; i++) {
+        Node = DlRemoveNodeFromTail(&Head);
+        if (Node) {
+            TestDataNode = CONTAINING_RECORD(Node, TestDataNode_t, Node);
+            printf("\n\nRemoved: (%d, %d)\n", TestDataNode->Data1, TestDataNode->Data2);
+        }
+        else {
+            printf("\n\nRemoved: List was empty!\n");
+        }
+        if (i < 5)
+            free(TestDataNode);
+        PrintList("Test 12 - cont", &Head);
+    }
+    
+
+    FreeList(&Head);
+
+    return 0;
+}
+
+

+ 183 - 0
addons/c/UnitTests/Queue/main.c

@@ -0,0 +1,183 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "queue_simple.h"
+
+
+/**
+ *  Deliberately insert the Node link in the middle of the struct.
+ *  This is worst case and tests that we can recover the data after 
+ *  dealing with the Nodes.
+ */
+typedef struct TestDataNode_t_ {
+
+    int Data1;
+    DlNode_t Node;
+    int Data2;
+
+} TestDataNode_t;
+
+
+/*
+ *  Helper function to allocate and init test nodes.
+ */
+TestDataNode_t *CreateTestDataNode(int d1, int d2)
+{
+    TestDataNode_t *n;
+
+    n = malloc(sizeof(TestDataNode_t));
+
+    if (!n)
+        return NULL;
+
+    n->Node.Next = NULL;
+    n->Node.Prev = NULL;
+    n->Data1 = d1;
+    n->Data2 = d2;
+
+    return n;
+}
+
+
+/*
+ *  Helper function.
+ *
+ *  We cheat and use the internal DList to iterate the Queue.
+ *
+ *  @note! The internal structure of the queue actually stores items
+ *  in reverse order. This isn't a problem, unless you cheat (like 
+ *  we are) and peek inside. In this case, just use the reverse 
+ *  iterator.
+ */
+void PrintQueue(const char *Title, Queue_t *Queue)
+{
+    TestDataNode_t *Node;
+    DlNode_t *Cur;
+
+    printf("\n%s\n", Title);
+    printf("---------------------\n");
+    printf("Count: %d\n", Queue->Count);
+    DlForEachNodeReverse(&Queue->Head, Cur) {
+        Node = CONTAINING_RECORD(Cur, TestDataNode_t, Node);
+        printf("DATA: (%d, %d)\n", Node->Data1, Node->Data2);
+    }
+}
+
+
+void FreeQueue(Queue_t *Queue)
+{
+    TestDataNode_t *Node;
+    DlNode_t *Cur;
+
+    while(!IsQueueEmpty(Queue)) {
+        Cur = Dequeue(Queue);
+        Node = CONTAINING_RECORD(Cur, TestDataNode_t, Node);
+        free(Node);
+    }
+}
+
+
+void FreeTestDataNode(DlNode_t *Node)
+{
+    TestDataNode_t *TestDataNode;
+
+    TestDataNode = CONTAINING_RECORD(Node, TestDataNode_t, Node);
+    free(TestDataNode);
+}
+
+
+int main (void)
+{
+    Queue_t Queue;
+    TestDataNode_t *n[5];    
+    int i;
+    DlNode_t *Node1;
+    DlNode_t *Node2;
+
+    /* -------------------------------- */
+    InitQueue(&Queue);
+    for (i = 0; i < 5; i++) {
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+        Enqueue(&Queue, &n[i]->Node);
+    }
+
+    PrintQueue("Test 1", &Queue);
+
+    FreeQueue(&Queue);
+
+    /* -------------------------------- */
+    InitQueue(&Queue);
+    for (i = 0; i < 5; i++) {
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+        Enqueue(&Queue, &n[i]->Node);
+    }
+
+    Node1 = Dequeue(&Queue); /* n1 */
+    Node2 = Dequeue(&Queue); /* n2 */
+    FreeTestDataNode(Node2);
+
+    Enqueue(&Queue, Node1);
+
+    PrintQueue("Test 2", &Queue);
+
+    FreeQueue(&Queue);
+
+    /* -------------------------------- */
+    InitQueue(&Queue);
+    for (i = 0; i < 5; i++) {
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+        Enqueue(&Queue, &n[i]->Node);
+    }
+
+    for (i = 0; i < 6; i++) {
+        Node1 = Dequeue(&Queue);
+        if (Node1)
+            FreeTestDataNode(Node1);
+    }
+
+    PrintQueue("Test 3", &Queue);
+
+    FreeQueue(&Queue);
+    
+    return 0;
+}
+
+

+ 314 - 0
addons/c/UnitTests/Slist/main.c

@@ -0,0 +1,314 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "slist.h"
+
+
+/**
+ *  Deliberately insert the Node link in the middle of the struct.
+ *  This is worst case and tests that we can recover the data after 
+ *  dealing with the Nodes.
+ */
+typedef struct TestDataNode_t_ {
+
+    int Data1;
+    SlNode_t Node;
+    int Data2;
+
+} TestDataNode_t;
+
+
+/*
+ *  Helper function to allocate and init test nodes.
+ */
+TestDataNode_t *CreateTestDataNode(int d1, int d2)
+{
+    TestDataNode_t *n;
+
+    n = malloc(sizeof(TestDataNode_t));
+
+    if (!n)
+        return NULL;
+
+    n->Node.Next = NULL;
+    n->Data1 = d1;
+    n->Data2 = d2;
+
+    return n;
+}
+
+
+/**
+ *  Helper function to clean up.
+ *  @note You cannot use the SlForEachNode() macro here,
+ *  because we are freeing each element. This would create a condition
+ *  where we were accessing memory that we had just freed if we tried
+ *  to use the macro.
+ */
+void FreeList(SlNode_t *Head)
+{
+    SlNode_t *Cur;
+    TestDataNode_t *Node;
+
+    Cur = Head->Next;
+
+    while (Cur != NULL){
+        Node = CONTAINING_RECORD(Cur, TestDataNode_t, Node);
+        Cur = Cur->Next;
+        free(Node);
+    }
+}
+
+
+/*
+ *  Helper function.
+ *  @note This is a good place to use the ForEachSingleListNode()
+ *  macro.
+ */
+void PrintList(const char *Title, SlNode_t *Head)
+{
+    TestDataNode_t *Node;
+    SlNode_t *Cur;
+
+    printf("\n%s\n", Title);
+    printf("---------------------\n");
+
+    SlForEachNode(Head, Cur) {
+        Node = CONTAINING_RECORD(Cur, TestDataNode_t, Node);
+        printf("DATA: (%d, %d)\n", Node->Data1, Node->Data2);
+    } 
+}
+
+
+void TestMacros(void)
+{
+    TestDataNode_t T;
+
+    printf("Test Macros\n");
+    printf("---------------------\n");
+    printf("OFFSET_OF(Data1) = %d\n", (int)OFFSET_OF(TestDataNode_t, Data1));
+    printf("OFFSET_OF(Node)  = %d\n", (int)OFFSET_OF(TestDataNode_t, Node));
+    printf("OFFSET_OF(Data2) = %d\n", (int)OFFSET_OF(TestDataNode_t, Data2));
+    
+    printf("&T       = %p\n", (void *)&T);
+    printf("&T.Data1 = %p\n", (void *)&T.Data1);
+    printf("&T.Node  = %p\n", (void *)&T.Node);
+    printf("&T.Data2 = %p\n", (void *)&T.Data2);
+
+    printf("CONTAINING_RECORD(Data1) = %p\n", (void *)CONTAINING_RECORD(&T.Data1, TestDataNode_t, Data1));
+    printf("CONTAINING_RECORD(Node)  = %p\n", (void *)CONTAINING_RECORD(&T.Node,  TestDataNode_t, Node));
+    printf("CONTAINING_RECORD(Data2) = %p\n", (void *)CONTAINING_RECORD(&T.Data2, TestDataNode_t, Data2));
+}
+
+
+int main (void)
+{
+    SlNode_t Head;
+    TestDataNode_t *n[5];
+    int i;
+    SlNode_t *Node;
+    TestDataNode_t *TestDataNode;
+
+
+    /* -------------------------------- */
+    TestMacros();
+
+    /* -------------------------------- */
+    SlInitHead(&Head);
+
+    for (i = 0; i < 5; i++)
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+
+    SlAddNodeToHead(&Head, &n[1]->Node);
+    SlAddNodeToHead(&Head, &n[0]->Node);
+
+    SlAddNodeToTail(&Head, &n[3]->Node);
+    SlAddNodeToTail(&Head, &n[4]->Node);
+
+    SlInsertNodeAfter(&n[1]->Node, &n[2]->Node);
+
+    PrintList("Test 1", &Head);
+    FreeList(&Head);
+
+
+    /* Test 2 -------------------------------- */
+    SlInitHead(&Head);
+
+    for (i = 0; i < 5; i++)
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+
+    for (i = 0; i < 5; i++)
+        SlAddNodeToHead(&Head, &n[i]->Node);
+
+    PrintList("Test 2", &Head);
+    FreeList(&Head);
+
+
+    /* Test 3 -------------------------------- */
+    SlInitHead(&Head);
+
+    for (i = 0; i < 5; i++)
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+
+    for (i = 0; i < 5; i++)
+        SlAddNodeToTail(&Head, &n[i]->Node);
+
+    PrintList("Test 3", &Head);
+    FreeList(&Head);
+
+
+    /* Test 4 -------------------------------- */
+    SlInitHead(&Head);
+
+    for (i = 0; i < 5; i++)
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+
+    SlInsertNodeAfter(&Head, &n[0]->Node);
+    for (i = 0; i < (5-1); i++)
+        SlInsertNodeAfter(&n[i]->Node, &n[i+1]->Node);
+
+    PrintList("Test 4", &Head);
+    FreeList(&Head);
+
+
+    /* Test 5 -------------------------------- */
+    SlInitHead(&Head);
+
+    for (i = 0; i < 5; i++)
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+
+    SlAddNodeToHead(&Head, &n[0]->Node);
+    for (i = 0; i < (5-1); i++)
+        SlInsertNodeBefore(&Head, &n[i]->Node, &n[i+1]->Node);
+
+    PrintList("Test 5", &Head);
+    FreeList(&Head);
+
+
+
+    SlInitHead(&Head);
+
+    for (i = 0; i < 5; i++) {
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+        SlAddNodeToTail(&Head, &n[i]->Node);
+    }
+
+    PrintList("Start for Tests 6-10", &Head);
+
+
+    /* Test 6 -------------------------------- */
+    SlRemoveNode(&Head, &n[0]->Node);
+    PrintList("Test 6", &Head);
+    free(n[0]);
+
+    /* Test 7 -------------------------------- */
+    SlRemoveNode(&Head, &n[4]->Node);
+    PrintList("Test 7", &Head);
+    free(n[4]);
+
+    /* Test 8 -------------------------------- */
+    SlRemoveNode(&Head, &n[2]->Node);
+    PrintList("Test 8", &Head);
+    free(n[2]);
+
+    /* Test 9 -------------------------------- */
+    SlRemoveNode(&Head, &n[1]->Node);
+    PrintList("Test 9", &Head);
+    free(n[1]);
+
+    /* Test 10 -------------------------------- */
+    SlRemoveNode(&Head, &n[3]->Node);
+    PrintList("Test 10", &Head);
+    free(n[3]);
+
+
+    /***********************************************************/
+    for (i = 0; i < 5; i++) {
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+        SlAddNodeToTail(&Head, &n[i]->Node);
+    }
+    
+    PrintList("Test 11", &Head);
+
+    for (i = 0; i < 6; i++) {
+        Node = SlRemoveNodeFromHead(&Head);
+        if (Node) {
+            TestDataNode = CONTAINING_RECORD(Node, TestDataNode_t, Node);
+            printf("\n\nRemoved: (%d, %d)\n", TestDataNode->Data1, TestDataNode->Data2);
+        }
+        else {
+            printf("\n\nRemoved: List was empty!\n");
+        }
+        if (i < 5)
+            free(TestDataNode);
+        PrintList("Test 11 - cont", &Head);
+    }
+
+
+    /***********************************************************/
+    for (i = 0; i < 5; i++) {
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+        SlAddNodeToTail(&Head, &n[i]->Node);
+    }
+    
+    PrintList("Test 12", &Head);
+
+    for (i = 0; i < 6; i++) {
+        Node = SlRemoveNodeFromTail(&Head);
+        if (Node) {
+            TestDataNode = CONTAINING_RECORD(Node, TestDataNode_t, Node);
+            printf("\n\nRemoved: (%d, %d)\n", TestDataNode->Data1, TestDataNode->Data2);
+        }
+        else {
+            printf("\n\nRemoved: List was empty!\n");
+        }
+        if (i < 5)
+            free(TestDataNode);
+        PrintList("Test 12 - cont", &Head);
+    }
+    
+
+    FreeList(&Head);
+
+    return 0;
+}
+
+

+ 176 - 0
addons/c/UnitTests/Stack/main.c

@@ -0,0 +1,176 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "stack_simple.h"
+
+
+/**
+ *  Deliberately insert the Node link in the middle of the struct.
+ *  This is worst case and tests that we can recover the data after 
+ *  dealing with the Nodes.
+ */
+typedef struct TestDataNode_t_ {
+
+    int Data1;
+    SlNode_t Node;
+    int Data2;
+
+} TestDataNode_t;
+
+
+/*
+ *  Helper function to allocate and init test nodes.
+ */
+TestDataNode_t *CreateTestDataNode(int d1, int d2)
+{
+    TestDataNode_t *n;
+
+    n = malloc(sizeof(TestDataNode_t));
+
+    if (!n)
+        return NULL;
+
+    n->Node.Next = NULL;
+    n->Data1 = d1;
+    n->Data2 = d2;
+
+    return n;
+}
+
+
+/*
+ *  Helper function.
+ *  We cheat and use the internal SList to iterate the stack.
+ */
+void PrintStack(const char *Title, Stack_t *Stack)
+{
+    TestDataNode_t *Node;
+    SlNode_t *Cur;
+
+    printf("\n%s\n", Title);
+    printf("---------------------\n");
+    printf("Count: %d\n", Stack->Count);
+    SlForEachNode(&Stack->Head, Cur) {
+        Node = CONTAINING_RECORD(Cur, TestDataNode_t, Node);
+        printf("DATA: (%d, %d)\n", Node->Data1, Node->Data2);
+    } 
+}
+
+
+void FreeStack(Stack_t *Stack)
+{
+    TestDataNode_t *Node;
+    SlNode_t *Cur;
+
+    while(!IsStackEmpty(Stack)) {
+        Cur = PopOffStack(Stack);
+        Node = CONTAINING_RECORD(Cur, TestDataNode_t, Node);
+        free(Node);
+    }
+}
+
+
+void FreeTestDataNode(SlNode_t *Node)
+{
+    TestDataNode_t *TestDataNode;
+
+    TestDataNode = CONTAINING_RECORD(Node, TestDataNode_t, Node);
+    free(TestDataNode);
+}
+
+
+int main (void)
+{
+    Stack_t Stack;
+    TestDataNode_t *n[5];    
+    int i;
+    SlNode_t *Node1;
+    SlNode_t *Node2;
+
+    /* -------------------------------- */
+    InitStack(&Stack);
+    for (i = 0; i < 5; i++) {
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+        PushOnStack(&Stack, &n[i]->Node);
+    }
+
+    PrintStack("Test 1", &Stack);
+
+    FreeStack(&Stack);
+
+    /* -------------------------------- */
+    InitStack(&Stack);
+    for (i = 0; i < 5; i++) {
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+        PushOnStack(&Stack, &n[i]->Node);
+    }
+
+    Node1 = PopOffStack(&Stack); /* n4 */
+    Node2 = PopOffStack(&Stack); /* n3 */
+    FreeTestDataNode(Node2);
+
+    PushOnStack(&Stack, Node1);
+
+    PrintStack("Test 2", &Stack);
+
+    FreeStack(&Stack);
+
+    /* -------------------------------- */
+    InitStack(&Stack);
+    for (i = 0; i < 5; i++) {
+        n[i] = CreateTestDataNode(i + 1,  10 + (i + 1));
+        PushOnStack(&Stack, &n[i]->Node);
+    }
+
+    for (i = 0; i < 6; i++) {
+        Node1 = PopOffStack(&Stack);
+        if (Node1)
+            FreeTestDataNode(Node1);
+    }
+
+    PrintStack("Test 3", &Stack);
+
+    FreeStack(&Stack);
+    
+    return 0;
+}
+
+

+ 131 - 0
addons/c/dlist.c

@@ -0,0 +1,131 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#include <stdlib.h>
+#include "dlist.h"
+
+
+void DlInsertNodeAfter( DlNode_t *Marker,
+                        DlNode_t *Node)
+{
+    if (Marker == NULL)
+        return;
+
+    if (Node == NULL)
+        return;
+
+    Node->Next = Marker->Next;
+    Node->Prev = Marker;
+
+    Marker->Next->Prev = Node;
+    Marker->Next = Node;
+}
+
+
+void DlInsertNodeBefore(DlNode_t *Marker,
+                        DlNode_t *Node)
+{
+    DlInsertNodeAfter(Marker->Prev, Node);
+}
+
+
+void DlAddNodeToHead(   DlNode_t *Head, 
+                        DlNode_t *Node)
+{
+    DlInsertNodeAfter(Head, Node);
+}
+
+
+void DlAddNodeToTail(   DlNode_t *Head,
+                        DlNode_t *Node)
+{
+    DlInsertNodeAfter(Head->Prev, Node);
+}
+
+
+void DlRemoveNode(DlNode_t *Node)
+{
+    if (Node == NULL)
+        return;
+
+    Node->Next->Prev = Node->Prev;
+    Node->Prev->Next = Node->Next;
+}
+
+
+DlNode_t *DlRemoveNodeFromHead(DlNode_t *Head)
+{
+    /****************/
+    DlNode_t *Node;
+    /****************/
+
+    if (Head == NULL)
+        return NULL;
+
+    if (DlIsListEmpty(Head))
+        return NULL;
+    
+    Node = Head->Next;
+
+    DlRemoveNode(Node);
+
+    return Node;
+}
+
+
+DlNode_t *DlRemoveNodeFromTail(DlNode_t *Head)
+{
+    /****************/
+    DlNode_t *Node;
+    /****************/
+
+    if (Head == NULL)
+        return NULL;
+
+    if (DlIsListEmpty(Head))
+        return NULL;
+
+    Node = Head->Prev;
+
+    DlRemoveNode(Node);
+
+    return Node;
+}
+
+

+ 213 - 0
addons/c/include/dlist.h

@@ -0,0 +1,213 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef DLIST_H_
+#define DLIST_H_
+
+
+/**
+ *  The doubly linked list structure.
+ *
+ *  This is designed to be embedded within your data 
+ *  structure(s).
+ *
+ *  These lists require more storage overhead than a singly linked list 
+ *  (two pointers per item), but almost all operations take O(1) time.
+ */
+typedef struct DlNode_t_ {
+
+    /**
+     *  Pointer to the next item in the list.
+     */
+    struct DlNode_t_ *Next;
+
+    /**
+     *  Pointer to the previous item in the list.
+     */
+    struct DlNode_t_ *Prev;
+
+} DlNode_t;
+
+
+/**
+ *  Macro to initialize a list head.
+ *
+ *  @param _head Pointer to the list head.
+ */
+#define DlInitHead(_head)       \
+{                               \
+    (_head)->Next = (_head);    \
+    (_head)->Prev = (_head);    \
+}
+
+
+/**
+ *  Add a node to the list head.
+ *  Runs in O(1) time.
+ *
+ *  @param Head A pointer to the existing list head.
+ *  @param Node A pointer to the node you are adding.
+ */
+void DlAddNodeToHead(   DlNode_t *Head, 
+                        DlNode_t *Node);
+
+
+/**
+ *  Add a node to the list tail.
+ *  Runs in O(1) time.
+ *  
+ *  @param Head A pointer to the existing list head.
+ *  @param Node A pointer to the node you are adding.
+ */
+void DlAddNodeToTail(   DlNode_t *Head,
+                        DlNode_t *Node);
+
+
+/**
+ *  Removes the node from the list head.
+ *  Runs in O(1) time.
+ *
+ *  @param Head A pointer to the existing list head.
+ *  @return The node removed, or NULL for an empty list.
+ */
+DlNode_t *DlRemoveNodeFromHead(DlNode_t *Head);
+
+
+/**
+ *  Removes the node from the list tail.
+ *  Runs in O(1) time.
+ *  
+ *  @param Head A pointer to the existing list head.
+ *  @return The node removed, or NULL for an empty list.
+ */
+DlNode_t *DlRemoveNodeFromTail(DlNode_t *Head);
+
+
+/**
+ *  Check if the list is empty.
+ *
+ *  @param _head A pointer to the existing list head.
+ *  @return true if the list is empty, false otherwise.
+ */
+#define DlIsListEmpty(_head) \
+    ((_head)->Next == _head)
+
+
+/**
+ *  Inserts a new node into the list right after the marker element.
+ *  Runs in O(1) time.
+ *
+ *  @param Marker The node you are inserting after. Cannot be NULL.
+ *  @param Node The node you are inserting. Cannot be NULL.
+ */
+void DlInsertNodeAfter( DlNode_t *Marker,
+                        DlNode_t *Node);
+
+
+/**
+ *  Inserts a new node into the list right before the marker element.
+ *  Runs in O(1) time.
+ *
+ *  @param Marker Node you are inserting before. Cannot be NULL.
+ *  @param Node The node you are inserting. Cannot be NULL.
+ */
+void DlInsertNodeBefore(DlNode_t *Marker, 
+                        DlNode_t *Node);
+
+
+/**
+ *  Removes a node from the list.
+ *  Runs in O(1) time.
+ *
+ *  @param Node The node you are removing.
+ */
+void DlRemoveNode(DlNode_t *Node);
+
+
+/**
+ *  Given here in case you do not have an equivalent macro.
+ *  @param _type The structure type.
+ *  @param _field The name of the field you want the offset to.
+ *  @returns The offset into _type where _field starts, in bytes.
+ */
+#ifndef OFFSET_OF
+#define OFFSET_OF(_type, _field)    \
+    ((size_t)&((_type *)0)->_field)
+#endif
+
+
+/**
+ *  Given here in case you do not have an equivalent macro.
+ *  @param _address The real address of the _field you have.
+ *  @param _type The structure type.
+ *  @param _field The name of the field you want the offset to.
+ *  @returns A typed pointer to the structure containing the _field 
+ *  at _address.
+ */
+#ifndef CONTAINING_RECORD
+#define CONTAINING_RECORD(_address, _type, _field)  \
+    ((_type *)((unsigned char *)(_address) - OFFSET_OF(_type, _field)))
+#endif
+
+
+/**
+ *  Macro to ease walking through all of the nodes in a list.
+ *  Runs in O(n) time.
+ *
+ *  @param _head A pointer to the list head. Cannot be NULL.
+ *  @param _node An DlNode_t pointer that you need to define before calling
+ *                  this macro.
+ */
+#define DlForEachNode(_head, _node) \
+    for ((_node) = (_head)->Next; (_node) != (_head); (_node) = (_node)->Next)
+
+/**
+ *  Macro to ease walking through all of the nodes in a list.
+ *  Runs in O(n) time.
+ *
+ *  @param _head A pointer to the list head. Cannot be NULL.
+ *  @param _node An DlNode_t pointer that you need to define before calling
+ *                  this macro.
+ */
+#define DlForEachNodeReverse(_head, _node) \
+    for ((_node) = (_head)->Prev; (_node) != (_head); (_node) = (_node)->Prev)
+
+#endif
+
+

+ 139 - 0
addons/c/include/mem_pool.h

@@ -0,0 +1,139 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef MEM_POOL_H_
+#define MEM_POOL_H_
+
+
+/**
+ *  Handle for memory pools. 
+ *
+ *  These are fixed allocation size memory areas.
+ */
+typedef void * MemoryPool_t;
+
+
+/**
+ *  Create a MemoryPool
+ *
+ *  @param itemSize How big is an allocation.
+ *  @param itemCount What's the maximum number of allocations allowed?
+ *  @param Alignment Power of 2 value denoting on which address boundary the 
+ *  memory will be aligned to. Must be at least sizeof(unsigned char *).
+ *  @return A Handle to the pool, or NULL on failure.
+ */
+MemoryPool_t CreateMemoryPool(  int itemSize, 
+                                int itemCount,
+                                int Alignment);
+
+
+/**
+ *  There is no DeleteMemoryPool() by design!
+ */
+
+
+/**
+ *  Allows you to add extra memory to a pool.
+ *
+ *  @param pool An existing memory pool.
+ *  @param ItemCount How many more items you want to add.
+ *  @return pdPASS on success, pdFAIL on error.
+ */
+int AddExtraMemoryToPool(   MemoryPool_t pool, 
+                            int ItemCount);
+
+
+/**
+ *  Create a MemoryPool
+ *
+ *  @param ItemSize How big is an allocation.
+ *  @param PreallocatedMemory Pointer to the preallocated memory
+ *  you are dedicating to this pool.
+ *  @param PreallocatedMemorySize How big is the buffer you are
+ *  passing in.
+ *  @param Alignment Power of 2 value denoting on which address boundary the 
+ *  memory will be aligned to. Must be at least sizeof(unsigned char *).
+ *  @return A Handle to the pool, or NULL on failure.
+ */
+MemoryPool_t CreateMemoryPoolStatic(int ItemSize,
+                                    void *PreallocatedMemory,
+                                    int PreallocatedMemorySize,
+                                    int Alignment);
+
+
+/**
+ *  Allows you to add extra memory to a pool.
+ *
+ *  @param pool An existing memory pool.
+ *  @param PreallocatedMemory Pointer to the preallocated memory
+ *  you are dedicating to this pool.
+ *  @param PreallocatedMemorySize How big is the buffer you are
+ *  passing in.
+ *  @return pdPASS on success, pdFAIL on error.
+ */
+int AddExtraMemoryToPoolStatic( MemoryPool_t pool, 
+                                void *PreallocatedMemory,
+                                int PreallocatedMemorySize);
+
+
+/**
+ *  Get a memory buffer from the pool.
+ *
+ *  Note that this can block, and cannnot be used from ISR context.
+ *
+ *  @param pool A handle to a MemoryPool.
+ *  @return A pointer or NULL on failure.
+ */
+void *MemoryPoolAllocate(MemoryPool_t pool);
+
+
+/**
+ *  Return a memory buffer to the pool.
+ *
+ *  @note This can block, and cannnot be used from ISR context.
+ *  @note There is no check that the memory passed in is valid.
+ *
+ *  @param pool A handle to a MemoryPool.
+ *  @param memory memory obtained from MemoryPoolAllocate().
+ */
+void MemoryPoolFree(MemoryPool_t pool, void *memory);
+
+
+#endif
+

+ 81 - 0
addons/c/include/queue_simple.h

@@ -0,0 +1,81 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+
+#ifndef QUEUE_H_
+#define QUEUE_H_
+
+
+#include "dlist.h"
+
+
+typedef struct Queue_t_ {
+
+    /**
+     *  How many items are in the queue.
+     */
+    int Count;
+
+    /**
+     *  We use a doubly linked list as our queue.
+     */
+    DlNode_t Head;
+
+} Queue_t;
+
+
+void InitQueue(Queue_t *Queue);
+
+
+void Enqueue(Queue_t *Queue, DlNode_t *Node);
+
+
+DlNode_t *Dequeue(Queue_t *Queue);
+
+
+/**
+ *  @return True if the stack is empty, false otherwise.
+ */
+#define IsQueueEmpty(_queue) \
+    ((_queue)->Count == 0)
+
+
+#endif
+
+

+ 116 - 0
addons/c/include/read_write_lock.h

@@ -0,0 +1,116 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef READ_WRITE_LOCK_H_
+#define READ_WRITE_LOCK_H_
+
+
+/**
+ *  Handle for Reader/Writer locks.
+ */
+typedef void * ReadWriteLock_t;
+
+
+/**
+ *  Create a Reader/Writer lock that offers preference 
+ *  to all readers.
+ *
+ *  @return A handle to the lock, or NULL on failure.
+ */
+ReadWriteLock_t *CreateReadWriteLockPreferReader(void);
+
+
+/**
+ *  Create a Reader/Writer lock that offers preference 
+ *  to all writers.
+ *
+ *  @return A handle to the lock, or NULL on failure.
+ */
+ReadWriteLock_t *CreateReadWriteLockPreferWriter(void);
+
+
+/**
+ *  Free an already allocated Reader/Writer lock.
+ *
+ *  @param lock The lock you are freeing.
+ */
+void FreeReadWriteLock(ReadWriteLock_t *lock);
+
+
+/**
+ *  Lock as a Reader.
+ *
+ *  This allows you shared read only access to whatever is being 
+ *  protected by this lock.
+ *
+ *  @param Lock The lock you are taking.
+ */
+void ReaderLock(ReadWriteLock_t *Lock);
+
+/**
+ *  Unlock as a Reader. 
+ *
+ *  You should have already locked this using ReaderLock().
+ *
+ *  @param Lock The lock you are releasing.
+ */
+void ReaderUnlock(ReadWriteLock_t *Lock);
+
+/**
+ *  Lock as a Writer.
+ *
+ *  This allows you exclusive read / write access to whatever is being
+ *  protected by this lock.
+ *
+ *  @param Lock The lock you are taking.
+ */
+void WriterLock(ReadWriteLock_t *Lock);
+
+/**
+ *  Unlock as a Writer. 
+ *
+ *  You should have already locked this using WriterLock().
+ *
+ *  @param Lock The lock you are releasing.
+ */
+void WriterUnlock(ReadWriteLock_t *Lock);
+
+
+#endif
+

+ 200 - 0
addons/c/include/slist.h

@@ -0,0 +1,200 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef SLIST_H_
+#define SLIST_H_
+
+
+/**
+ *  The singly linked list structure.
+ *
+ *  This is designed to be embedded within your data 
+ *  structure(s).
+ *
+ *  These lists offer the smallest storage overhead (one pointer per item),
+ *  but many operations may take O(n) time.
+ */
+typedef struct SlNode_t_ {
+    
+    /**
+     *  A pointer to ourselves.
+     */
+    struct SlNode_t_ *Next;
+
+} SlNode_t;
+
+
+/**
+ *  Macro to initialize a list head.
+ *
+ *  @param _head A pointer to the list head.
+ */
+#define SlInitHead(_head) \
+    (_head)->Next = NULL;
+
+
+/**
+ *  Add a node to the list head.
+ *  Runs in O(1) time.
+ *
+ *  @param _head A pointer to the existing list head.
+ *  @param _node A pointer to the node you are adding.
+ */
+#define SlAddNodeToHead(_head, _node) \
+    SlInsertNodeAfter(_head, _node)
+
+
+/**
+ *  Add a node to the list tail.
+ *  Runs in O(n) time.
+ *  
+ *  @param Head A pointer to the existing list head.
+ *  @param Node A pointer to the node you are adding.
+ */
+void SlAddNodeToTail(   SlNode_t *Head,
+                        SlNode_t *Node);
+
+
+/**
+ *  Removes the node from the list head.
+ *  Runs in O(1) time.
+ *
+ *  @param Head A pointer to the existing list head.
+ *  @return The node removed, or NULL for an empty list.
+ */
+SlNode_t *SlRemoveNodeFromHead(SlNode_t *Head);
+
+
+/**
+ *  Removes the node from the list tail.
+ *  Runs in O(n) time.
+ *  
+ *  @param Head A pointer to the existing list head.
+ *  @return The node removed, or NULL for an empty list.
+ */
+SlNode_t *SlRemoveNodeFromTail(SlNode_t *Head);
+
+
+/**
+ *  Check if the list is empty.
+ *
+ *  @param _head A pointer to the existing list head.
+ *  @return true if the list is empty, false otherwise.
+ */
+#define SlIsListEmpty(_head) \
+    ((_head)->Next == NULL)
+
+
+/**
+ *  Inserts a new node into the list right after the marker element.
+ *  Runs in O(1) time.
+ *
+ *  @param Marker The node you are inserting after. Cannot be NULL.
+ *  @param Node The node you are inserting. Cannot be NULL.
+ */
+void SlInsertNodeAfter( SlNode_t *Marker,
+                        SlNode_t *Node);
+
+
+/**
+ *  Inserts a new node into the list right before the marker element.
+ *  Runs in O(n) time.
+ *
+ *  @param Head Pointer to the list head.
+ *  @param Marker Node you are inserting before. Cannot be NULL.
+ *  @param Node The node you are inserting. Cannot be NULL.
+ */
+void SlInsertNodeBefore(SlNode_t *Head, 
+                        SlNode_t *Marker, 
+                        SlNode_t *Node);
+
+
+/**
+ *  Removes a node from the list.
+ *  Runs in O(n) time worst case.
+ *
+ *  @param Head Pointer to the list head.
+ *  @param Node The node you are removing.
+ */
+void SlRemoveNode(  SlNode_t *Head, 
+                    SlNode_t *Node);
+
+
+/**
+ *  Given here in case you do not have an equivalent macro.
+ *  @param _type The structure type.
+ *  @param _field The name of the field you want the offset to.
+ *  @returns The offset into _type where _field starts, in bytes.
+ */
+#ifndef OFFSET_OF
+#define OFFSET_OF(_type, _field)    \
+    ((size_t)&((_type *)0)->_field)
+#endif
+
+
+/**
+ *  Given here in case you do not have an equivalent macro.
+ *  @param _address The real address of the _field you have.
+ *  @param _type The structure type.
+ *  @param _field The name of the field you want the offset to.
+ *  @returns A typed pointer to the structure containing the _field 
+ *  at _address.
+ */
+#ifndef CONTAINING_RECORD
+#define CONTAINING_RECORD(_address, _type, _field)  \
+    ((_type *)((unsigned char *)(_address) - OFFSET_OF(_type, _field)))
+#endif
+
+
+/**
+ *  Macro to ease walking through all of the nodes in a list.
+ *  Runs in O(n) time.
+ *
+ *  This will work for an empty list.
+ *
+ *  @param _head A pointer to the list head. Cannot be NULL.
+ *  @param _node An SlNode_t pointer that you need to define before calling
+ *                  this macro.
+ */
+#define SlForEachNode(_head, _node) \
+    for ((_node) = (_head)->Next; (_node) != NULL; (_node) = (_node)->Next)
+
+
+#endif
+

+ 106 - 0
addons/c/include/stack_simple.h

@@ -0,0 +1,106 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef STACK_H_
+#define STACK_H_
+
+
+#include "slist.h"
+
+
+/**
+ *  The stack structure, we leverage low overhead singly linked lists here.
+ */
+typedef struct Stack_t_ {
+
+    /**
+     *  How many items are in the stack.
+     */
+    int Count;
+
+    /**
+     *  The head of the stack.
+     */
+    SlNode_t Head;
+
+} Stack_t;
+
+
+/**
+ *  Initialize a Stack structure you provide.
+ *
+ *  @param Stack Pointer to your stack structure.
+ */
+void InitStack(Stack_t *Stack);
+
+
+/**
+ *  Push an item onto the stack.
+ *
+ *  Note that you have to have embedded an SListNode inside your data 
+ *  structure.
+ *
+ *  @param Stack Pointer to your stack structure.
+ *  @param Node The SListNode you want on the stack.
+ */
+void PushOnStack(   Stack_t *Stack, 
+                    SlNode_t *Node);
+
+
+/**
+ *  Pop an item off the stack.
+ *
+ *  Note that you have to have embedded an SListNode inside your data 
+ *  structure.
+ *
+ *  @param Stack Pointer to your stack structure.
+ *  @return An SListNode from the stack, or NULL if it's empty.
+ */
+SlNode_t *PopOffStack(Stack_t *Stack);
+
+
+/**
+ *  @return True if the stack is empty, false otherwise.
+ */
+#define IsStackEmpty(_stack) \
+    ((_stack)->Count == 0)
+
+
+#endif
+

+ 53 - 0
addons/c/include/version.h

@@ -0,0 +1,53 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef VERSION_C_ADDONS_H_
+#define VERSION_C_ADDONS_H_
+
+
+#define C_ADDONS_VERSION_MAJOR      1
+#define C_ADDONS_VERSION_MINOR      1
+#define C_ADDONS_VERSION_RELEASE    0
+
+#define C_ADDONS_VERSION_STRING "1.1.0"
+
+
+#endif
+
+

+ 122 - 0
addons/c/include/workqueue.h

@@ -0,0 +1,122 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef WORKQUEUE_H_
+#define WORKQUEUE_H_
+
+
+#include "FreeRTOS.h"
+#include "semphr.h"
+
+
+/**
+ *  All your work items are actually functions that take a 
+ *  void * parameter.
+ */
+typedef void (* WorkItem_t)(void *UserData);
+
+
+/**
+ *  Handle for the actual work queue.
+ */
+typedef void * WorkQueue_t;
+
+
+/**
+ *  Default stack size of the Worker Task.
+ */
+#define DEFAULT_WORK_QUEUE_STACK_SIZE   (configMINIMAL_STACK_SIZE * 2)
+
+
+/**
+ *  Default task priority of the Worker Task.
+ */
+#define DEFAULT_WORK_QUEUE_PRIORITY     (tskIDLE_PRIORITY + 1)
+
+
+/**
+ *  Create a WorkQueue, specifying all options.
+ *
+ *  @param Name The name of the worker thread.
+ *  @param StackSize The size of the worker thread stack, in words.
+ *  @param Priority The priority of the worker thread.
+ *  @return A handle, or NULL on error.
+ */
+WorkQueue_t CreateWorkQueueEx(  const char * const Name,
+                                uint16_t StackSize,
+                                UBaseType_t Priority);
+
+
+/**
+ *  Create a WorkQueue using the defaults.
+ *
+ *  @return A handle, or NULL on error.
+ */
+#define CreateWorkQueue()                   \
+    CreateWorkQueueEx("wq",                 \
+            DEFAULT_WORK_QUEUE_STACK_SIZE,  \
+            DEFAULT_WORK_QUEUE_PRIORITY)    \
+
+
+#if (INCLUDE_vTaskDelete == 1)
+
+/**
+ *  Destroy a WorkQueue, if allowed.
+ *
+ *  @param WorkQueue The work queue.
+ */
+void DestroyWorkQueue(WorkQueue_t WorkQueue);
+
+#endif
+
+/**
+ *  Add an item of work onto the queue.
+ *
+ *  @param WorkQueue The work queue.
+ *  @param WorkItem The function you want called.
+ *  @param UserData A value passed back to you.
+ *  @return pdPASS on success, pdFAIL on error.
+ */
+int QueueWorkItem(  WorkQueue_t WorkQueue, 
+                    WorkItem_t WorkItem, 
+                    void *UserData);
+
+
+#endif
+

+ 113 - 0
addons/c/include/zero_copy_queue.h

@@ -0,0 +1,113 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#ifndef ZERO_COPY_QUEUE_H_
+#define ZERO_COPY_QUEUE_H_
+
+
+/**
+ *  Handle for ZeroCopyQueues. 
+ *
+ *  These queues only copy a single pointer instead of the 
+ *  entire data structure, which is how FreeRTOS works by default.
+ */
+typedef void * ZeroCopyQueue_t;
+
+
+/**
+ *  Create a Zero Copy Queue.
+ *
+ *  @param itemSize Maximum size of the item.
+ *  @param itemCount What's the maximum number of items allowed?
+ *  @param Alignment Power of 2 value denoting on which address boundary the 
+ *  memory will be aligned to. Must be at least sizeof(unsigned char *).
+ *  @return A Handle to the ZeroCopyQueue, or NULL on failure.
+ */
+ZeroCopyQueue_t ZcqCreateQueue( int itemSize,
+                                int itemCount,
+                                int Alignment);
+
+
+/**
+ *  Allocate an item to use or queue.
+ *
+ *  Note that this can block, and cannnot be used from ISR context.
+ *
+ *  @param zcq A handle to a ZeroCopyQueue_t.
+ *  @return A pointer or NULL on failure.
+ */
+void *ZcqAllocateItem(ZeroCopyQueue_t zcq);
+
+
+/**
+ *  Free a previously allocated item back into the base pool.
+ *
+ *  @note This can block, and cannnot be used from ISR context.
+ *  @note There is no check that the memory passed in is valid.
+ *
+ *  @param zcq A handle to a ZeroCopyQueue_t.
+ *  @param item An item obtained from ZcqAllocateItem().
+ */
+void ZcqFreeItem(ZeroCopyQueue_t zcq, void *item);
+
+
+/**
+ *  Queue an item obtained from ZcqAllocateItem().
+ *
+ *  @param zcq A handle to a ZeroCopyQueue_t.
+ *  @param item An item obtained from ZcqAllocateItem().
+ *  @param Timeout Timeout in FreeRTOS ticks.
+ *  @return 1 on success, 0 on failure.
+ */
+int ZcqEnqueueItem(ZeroCopyQueue_t zcq, void *item, TickType_t Timeout);
+
+
+/**
+ *  Dequeue an item from ZcqEnqueueItem().
+ *
+ *  @param zcq A handle to a ZeroCopyQueue_t.
+ *  @param Timeout Timeout in FreeRTOS ticks.
+ *  @return An item obtained from ZcqAllocateItem() on success.
+ *  NULL on failure.
+ */
+void *ZcqDequeueItem(ZeroCopyQueue_t zcq, TickType_t Timeout);
+
+
+#endif
+

+ 360 - 0
addons/c/mem_pool.c

@@ -0,0 +1,360 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#include <stdlib.h>
+#include "FreeRTOS.h"
+#include "semphr.h"
+#include "mem_pool.h"
+#include "stack_simple.h"
+
+
+/**
+ *  The actual Memory Pool data structure.
+ *
+ *  This is a variable length data structure.
+ */
+typedef struct MemPool_t_ {
+
+    /**
+     *  We need a lock to make this thread safe.
+     */
+    SemaphoreHandle_t Lock;
+    
+    /**
+     *  Memory blocks are stored on a stack.
+     */
+    Stack_t Stack;
+
+    /**
+     *  Save the item size for additions.
+     */
+    int ItemSize;
+
+    /**
+     *  The overall alignment of an item.
+     */
+    int Alignment;
+
+    /**
+     *  The begining of the actual memory pool itself.
+     */
+    unsigned char Buffer[1];
+
+} MemPool_t;
+
+
+static int CalculateAndVerifyAlignment(int Alignment)
+{
+    /*********************************/
+    int i;
+    int alignmentBit = 0x1;
+    /*********************************/
+
+    /**
+     *  Guarantee that the alignment is the size of a pointer.
+     */
+    if (Alignment < (int)sizeof(unsigned char *)) {
+        Alignment = (int)sizeof(unsigned char *);
+    }
+
+    for (i = 0; i < 31; i++) {
+        if (Alignment == alignmentBit) {
+            break;
+        }
+        alignmentBit <<= 1; 
+    }
+
+    if (i >= 31) {
+        return 0;
+    }
+    else {
+        return Alignment;
+    }
+}
+
+
+static int CalculateItemSize(   int ItemSize,
+                                int Alignment)
+{
+    /*********************************/
+    int alignmentCount;
+    /*********************************/
+
+    if (ItemSize <= Alignment) {
+        /**
+         *  The 2* accounts for the SList struct inside each memory block.
+         */
+        ItemSize = 2 * Alignment;
+    }
+    else {
+        alignmentCount = ItemSize / Alignment;
+        if (ItemSize % Alignment != 0) {
+            alignmentCount++;
+        }
+        /**
+         *  The +1 accounts for the SList struct inside each memory block.
+         */
+        ItemSize = ((alignmentCount + 1) * Alignment);
+    }
+    
+    return ItemSize;
+}
+    
+
+MemoryPool_t CreateMemoryPool(  int ItemSize,
+                                int ItemCount,
+                                int Alignment)
+{
+    /*********************************/
+    MemPool_t *MemPool;
+    int MemPoolSize;
+    unsigned char *ptr;
+    SlNode_t *Node;
+    int i;
+    /*********************************/
+
+    Alignment = CalculateAndVerifyAlignment(Alignment);
+
+    if (Alignment == 0) {
+        return NULL;
+    }
+
+    ItemSize = CalculateItemSize(ItemSize, Alignment);
+
+    MemPoolSize = sizeof(MemPool_t) - sizeof(unsigned char)
+                    + (ItemCount * ItemSize);
+
+    MemPool = (MemPool_t *)malloc(MemPoolSize);
+    if (!MemPool) {
+        return NULL;
+    }
+
+    MemPool->Lock = xSemaphoreCreateMutex();
+    if (MemPool->Lock == NULL) {
+        free(MemPool);
+        return NULL;
+    }
+
+    InitStack(&MemPool->Stack);
+    MemPool->ItemSize = ItemSize;
+    MemPool->Alignment = Alignment;
+
+    ptr = MemPool->Buffer;
+
+    for (i = 0; i < ItemCount; i++) {
+        
+        Node = (SlNode_t *)ptr;
+    
+        PushOnStack(&MemPool->Stack, Node);
+
+        ptr += MemPool->ItemSize;
+    }
+    
+    return (MemoryPool_t)MemPool;
+}
+
+
+int AddExtraMemoryToPool(   MemoryPool_t pool, 
+                            int ItemCount)
+{
+    /*********************************/
+    MemPool_t *MemPool;
+    SlNode_t *Node;
+    unsigned char *ptr;
+    int i;
+    int AdditionalPoolSize;
+    /*********************************/
+
+    MemPool = (MemPool_t *)pool;
+
+    AdditionalPoolSize = ItemCount * MemPool->ItemSize;
+
+    ptr = (unsigned char *)malloc(AdditionalPoolSize);
+    if (ptr == NULL) {
+        return pdFAIL;
+    }
+
+    for (i = 0; i < ItemCount; i++) {
+        
+        Node = (SlNode_t *)ptr;
+    
+        xSemaphoreTake(MemPool->Lock, portMAX_DELAY);
+        
+        PushOnStack(&MemPool->Stack, Node);
+
+        xSemaphoreGive(MemPool->Lock);
+    
+        ptr += MemPool->ItemSize;
+    }
+
+    return pdPASS;
+}
+
+
+MemoryPool_t CreateMemoryPoolStatic(int ItemSize,
+                                    void *PreallocatedMemory,
+                                    int PreallocatedMemorySize,
+                                    int Alignment)
+{
+    /*********************************/
+    MemPool_t *MemPool;
+    int MemPoolSize;
+    unsigned char *ptr;
+    SlNode_t *Node;
+    /*********************************/
+
+    Alignment = CalculateAndVerifyAlignment(Alignment);
+
+    if (Alignment == 0) {
+        return NULL;
+    }
+
+    ItemSize = CalculateItemSize(ItemSize, Alignment);
+
+    MemPoolSize = sizeof(MemPool_t) - sizeof(unsigned char);
+
+    MemPool = (MemPool_t *)malloc(MemPoolSize);
+    if (!MemPool) {
+        return NULL;
+    }
+
+    MemPool->Lock = xSemaphoreCreateMutex();
+    if (MemPool->Lock == NULL) {
+        free(MemPool);
+        return NULL;
+    }
+
+    InitStack(&MemPool->Stack);
+    MemPool->ItemSize = ItemSize;
+    MemPool->Alignment = Alignment;
+
+    ptr = (unsigned char *)PreallocatedMemory;
+
+    while (PreallocatedMemorySize >= ItemSize) {
+        
+        Node = (SlNode_t *)ptr;
+        PushOnStack(&MemPool->Stack, Node);
+        ptr += MemPool->ItemSize;
+        PreallocatedMemorySize -= MemPool->ItemSize;
+    }
+    
+    return (MemoryPool_t)MemPool;
+}
+
+
+int AddExtraMemoryToPoolStatic( MemoryPool_t pool, 
+                                void *PreallocatedMemory,
+                                int PreallocatedMemorySize)
+{
+    /*********************************/
+    MemPool_t *MemPool;
+    SlNode_t *Node;
+    unsigned char *ptr;
+    /*********************************/
+
+    MemPool = (MemPool_t *)pool;
+    ptr = (unsigned char *)PreallocatedMemory;
+
+    while (PreallocatedMemorySize >= MemPool->ItemSize) {
+
+        Node = (SlNode_t *)ptr;
+
+        xSemaphoreTake(MemPool->Lock, portMAX_DELAY);
+        
+        PushOnStack(&MemPool->Stack, Node);
+
+        xSemaphoreGive(MemPool->Lock);
+
+        ptr += MemPool->ItemSize;
+    }
+
+    return pdPASS;
+}
+
+
+void *MemoryPoolAllocate(MemoryPool_t pool)
+{
+    /*********************************/
+    MemPool_t *MemPool;
+    SlNode_t *Node;
+    unsigned char *ptr;
+    /*********************************/
+
+    MemPool = (MemPool_t *)pool;
+
+    xSemaphoreTake(MemPool->Lock, portMAX_DELAY);
+
+    if (MemPool->Stack.Count == 0) {
+        xSemaphoreGive(MemPool->Lock);
+        return NULL;
+    }
+
+    Node = PopOffStack(&MemPool->Stack);
+
+    xSemaphoreGive(MemPool->Lock);
+
+    ptr = ((unsigned char *)Node) + MemPool->Alignment;
+
+    return (void *)ptr;
+}
+
+
+void MemoryPoolFree(MemoryPool_t pool, void *memory)
+{
+    /*********************************/
+    MemPool_t *MemPool;
+    SlNode_t *Node;
+    unsigned char *ptr;
+    /*********************************/
+
+    MemPool = (MemPool_t *)pool;
+
+    ptr = ((unsigned char *)memory) - MemPool->Alignment;
+
+    Node = (SlNode_t *)ptr;
+
+    xSemaphoreTake(MemPool->Lock, portMAX_DELAY);
+
+    PushOnStack(&MemPool->Stack, Node);
+
+    xSemaphoreGive(MemPool->Lock);
+}
+
+
+

+ 83 - 0
addons/c/queue_simple.c

@@ -0,0 +1,83 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#include <stdlib.h>
+#include "queue_simple.h"
+
+
+void InitQueue(Queue_t *Queue)
+{
+    if (Queue == NULL)
+        return;
+
+    Queue->Count = 0;
+    DlInitHead(&Queue->Head);
+}
+
+
+void Enqueue(Queue_t *Queue, DlNode_t *Node)
+{
+    if (Queue == NULL)
+        return;
+
+    if (Node == NULL)
+        return;
+
+    Queue->Count++;
+    DlAddNodeToHead(&Queue->Head, Node);
+}
+
+
+DlNode_t *Dequeue(Queue_t *Queue)
+{
+    DlNode_t *Node;
+
+    if (Queue == NULL)
+        return NULL;
+
+    if (Queue->Count <= 0)
+        return NULL;
+
+    Queue->Count--;
+    Node = DlRemoveNodeFromTail(&Queue->Head);
+
+    return Node;
+}
+
+

+ 459 - 0
addons/c/read_write_lock.c

@@ -0,0 +1,459 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#include <stdlib.h>
+#include "FreeRTOS.h"
+#include "semphr.h"
+#include "read_write_lock.h"
+
+
+/*
+ *  We need to differentiate which type of lock this is. We can 
+ *  also use this as a sanity check, signature.
+ */
+enum ReaderWriterLockType {
+
+    RwPreferReader = 0x72656164,    /* "read" */
+    RwPreferWriter = 0x77726974     /* "writ" */
+};
+
+
+typedef struct RWLockPreferReader_t_ {
+
+    /**
+     *  Specify a type as well as using this as a signature.
+     */
+    enum ReaderWriterLockType Type;
+
+    /**
+     *  How many active readers are there.
+     */
+    int ReadCount;
+
+    /**
+     *  Protect ReadCount.
+     */
+    SemaphoreHandle_t ReadLock;
+
+    /**
+     *  Protect this resource from multiple writer access, or
+     *  from Reader access when a writer is changing something.
+     */
+    SemaphoreHandle_t ResourceLock;
+
+} RWLockPreferReader_t;
+
+
+typedef struct RWLockPreferWriter_t_ {
+
+    /*
+     *  --------------------------------------------------------
+     *  THIS PORTION MUST MIRROR THE PREFER READER STRUCTURE
+     */
+    enum ReaderWriterLockType Type;
+
+    /**
+     *  How many active readers are there.
+     */
+    int ReadCount;
+
+    /**
+     *  Protect ReadCount.
+     */
+    SemaphoreHandle_t ReadLock;
+
+    /**
+     *  Protect this resource from multiple writer access, or
+     *  from Reader access when a writer is changing something.
+     */
+    SemaphoreHandle_t ResourceLock;
+
+    /*
+     *  --------------------------------------------------------
+     *  WRITER ONLY ADDITION
+     */
+
+    /**
+     *  Number of Writers waiting for the Resource Lock, including any
+     *  current Writer already holdign it.
+     */
+    int WriteCount;
+
+    /**
+     *  Protect WriteCount.
+     */
+    SemaphoreHandle_t WriteLock;
+
+    /**
+     *  Lock to stop reader threads from starving a Writer.
+     */
+    SemaphoreHandle_t BlockReadersLock;
+
+} RWLockPreferWriter_t;
+
+
+
+ReadWriteLock_t *CreateReadWriteLockPreferReader(void)
+{
+    RWLockPreferReader_t *lock;
+
+    lock = (RWLockPreferReader_t *)malloc(sizeof(RWLockPreferReader_t));
+    if (!lock) {
+        /*
+         *  If the initial malloc fails, just get out.
+         */
+        return NULL;
+    }
+
+    lock->Type = RwPreferReader;
+    
+    lock->ReadCount = 0;
+
+    /*
+     *  Preload these with NULLs to allow simplified error handling.
+     */
+    lock->ReadLock = NULL;
+    lock->ResourceLock = NULL;
+
+
+    lock->ReadLock = xSemaphoreCreateMutex();
+    if (lock->ReadLock == NULL) {
+        goto ERROR;
+    }
+
+    /*
+     *  ResourceLock CANNOT be a mutex. In FreeRTOS, as in most OS's,
+     *  a thread is not allowed to unlock another thread's mutex. But
+     *  the very nature of a Reader Lock allows an arbitrary ordering 
+     *  of unlocks when multiple threads hold the reader lock. 
+     *  Semaphores are not subject to this constraint.
+     */
+    lock->ResourceLock = xSemaphoreCreateBinary();
+    if (lock->ResourceLock == NULL) {
+        goto ERROR;
+    }
+
+    /*
+     *  Initialize it as "full", so it behaves similar to a mutex.
+     */
+    xSemaphoreGive(lock->ResourceLock);
+
+    return (ReadWriteLock_t *)lock;
+
+
+    /*
+     *  Handle most error cases here. This simplifies cleanup
+     *  and is a common pattern in most OSs.
+     */
+ERROR:
+    if (!lock->ReadLock) {
+        vSemaphoreDelete(lock->ReadLock);
+    } 
+
+    if (!lock->ResourceLock) {
+        vSemaphoreDelete(lock->ResourceLock);
+    }
+
+    free(lock);
+    return NULL;
+}
+
+
+ReadWriteLock_t *CreateReadWriteLockPreferWriter(void)
+{
+    RWLockPreferWriter_t *lock;
+
+    lock = (RWLockPreferWriter_t *)malloc(sizeof(RWLockPreferWriter_t));
+    if (!lock) {
+        /*
+         *  If the initial malloc fails, just get out.
+         */
+        return NULL;
+    }
+
+    lock->Type = RwPreferWriter;
+    
+    lock->ReadCount = 0;
+    lock->WriteCount = 0;
+
+    /*
+     *  Preload these with NULLs to allow simplified error handling.
+     */
+    lock->ReadLock = NULL;
+    lock->WriteLock = NULL;
+    lock->ResourceLock = NULL;
+    lock->BlockReadersLock = NULL;
+
+    lock->ReadLock = xSemaphoreCreateMutex();
+    if (lock->ReadLock == NULL) {
+        goto ERROR;
+    }
+
+    lock->WriteLock = xSemaphoreCreateMutex();
+    if (lock->WriteLock == NULL) {
+        goto ERROR;
+    }
+
+    /*
+     *  ResourceLock CANNOT be a mutex. In FreeRTOS, as in most OS's,
+     *  a thread is not allowed to unlock another thread's mutex. But
+     *  the very nature of a Reader Lock allows an arbitrary ordering 
+     *  of unlocks when multiple threads hold the reader lock. 
+     *  Semaphores are not subject to this constraint.
+     */
+    lock->ResourceLock = xSemaphoreCreateBinary();
+    if (lock->ResourceLock == NULL) {
+        goto ERROR;
+    }
+
+    /*
+     *  Initialize it as "full", so it behaves similar to a mutex.
+     */
+    xSemaphoreGive(lock->ResourceLock);
+
+    /*
+     *  BlockReadersLock CANNOT be a mutex. In FreeRTOS, as in most OS's,
+     *  a thread is not allowed to unlock another thread's mutex. But
+     *  the very nature of a Reader Lock allows an arbitrary ordering 
+     *  of unlocks when multiple threads hold the reader lock. 
+     *  Semaphores are not subject to this constraint.
+     */
+    lock->BlockReadersLock = xSemaphoreCreateBinary();
+    if (lock->BlockReadersLock == NULL) {
+        goto ERROR;
+    }
+
+    /*
+     *  Initialize it as "full", so it behaves similar to a mutex.
+     */
+    xSemaphoreGive(lock->BlockReadersLock);
+
+    return (ReadWriteLock_t *)lock;
+
+
+    /*
+     *  Handle most error cases here. This simplifies cleanup
+     *  and is a common pattern in most OSs.
+     */
+ERROR:
+    if (!lock->ReadLock) {
+        vSemaphoreDelete(lock->ReadLock);
+    } 
+
+    if (!lock->WriteLock) {
+        vSemaphoreDelete(lock->WriteLock);
+    }
+
+    if (!lock->ResourceLock) {
+        vSemaphoreDelete(lock->ResourceLock);
+    }
+
+    if (!lock->BlockReadersLock) {
+        vSemaphoreDelete(lock->BlockReadersLock);
+    }
+
+    free(lock);
+    return NULL;
+}
+
+
+void FreeReadWriteLock(ReadWriteLock_t *lock)
+{
+    RWLockPreferReader_t *lockR = (RWLockPreferReader_t *)lock;
+    RWLockPreferWriter_t *lockW = (RWLockPreferWriter_t *)lock;
+
+    configASSERT(lockR != NULL);
+
+    if (lockR->Type == RwPreferReader) {
+        vSemaphoreDelete(lockR->ReadLock);
+        vSemaphoreDelete(lockR->ResourceLock);
+        free(lockR);
+    }
+    else if (lockW->Type == RwPreferWriter) {
+        vSemaphoreDelete(lockW->ReadLock);
+        vSemaphoreDelete(lockW->WriteLock);
+        vSemaphoreDelete(lockW->ResourceLock);
+        vSemaphoreDelete(lockW->BlockReadersLock);
+        free(lockW);
+    }
+    else {
+        configASSERT(!"Bad RW Lock type!");
+    }
+}
+
+
+void ReaderLock(ReadWriteLock_t *lock)
+{
+    RWLockPreferReader_t *lockR = (RWLockPreferReader_t *)lock;
+    RWLockPreferWriter_t *lockW = (RWLockPreferWriter_t *)lock;
+
+    configASSERT(lockR != NULL);
+
+    if (lockR->Type == RwPreferReader) {
+
+        xSemaphoreTake(lockR->ReadLock, portMAX_DELAY);
+
+        lockR->ReadCount++;
+        if (lockR->ReadCount == 1) {
+            xSemaphoreTake(lockR->ResourceLock, portMAX_DELAY);
+        }
+
+        xSemaphoreGive(lockR->ReadLock);
+    }
+    else if (lockW->Type == RwPreferWriter) {
+
+        xSemaphoreTake(lockW->BlockReadersLock, portMAX_DELAY);
+        xSemaphoreTake(lockW->ReadLock, portMAX_DELAY);
+
+        lockW->ReadCount++;
+        if (lockW->ReadCount == 1) {
+            xSemaphoreTake(lockW->ResourceLock, portMAX_DELAY);
+        }
+
+        xSemaphoreGive(lockW->ReadLock);
+        xSemaphoreGive(lockW->BlockReadersLock);
+        
+    }
+    else {
+        configASSERT(!"Bad RW Lock type!");
+    }
+}
+
+
+void ReaderUnlock(ReadWriteLock_t *lock)
+{
+    RWLockPreferReader_t *lockR = (RWLockPreferReader_t *)lock;
+    RWLockPreferWriter_t *lockW = (RWLockPreferWriter_t *)lock;
+
+    configASSERT(lockR != NULL);
+
+    if (lockR->Type == RwPreferReader) {
+
+        xSemaphoreTake(lockR->ReadLock, portMAX_DELAY);
+
+        lockR->ReadCount--;
+        if (lockR->ReadCount == 0) {
+            xSemaphoreGive(lockR->ResourceLock);
+        }
+
+        xSemaphoreGive(lockR->ReadLock);
+    }
+    else if (lockW->Type == RwPreferWriter) {
+
+        xSemaphoreTake(lockW->ReadLock, portMAX_DELAY);
+
+        lockW->ReadCount--;
+        if (lockW->ReadCount == 0) {
+            xSemaphoreGive(lockW->ResourceLock);
+        }
+
+        xSemaphoreGive(lockW->ReadLock);
+
+    }
+    else {
+        configASSERT(!"Bad RW Lock type!");
+    }
+}
+
+
+void WriterLock(ReadWriteLock_t *lock)
+{
+    RWLockPreferReader_t *lockR = (RWLockPreferReader_t *)lock;
+    RWLockPreferWriter_t *lockW = (RWLockPreferWriter_t *)lock;
+
+    configASSERT(lockR != NULL);
+
+    if (lockR->Type == RwPreferReader) {
+    
+        xSemaphoreTake(lockR->ResourceLock, portMAX_DELAY);
+        
+    }
+    else if (lockW->Type == RwPreferWriter) {
+
+        xSemaphoreTake(lockW->WriteLock, portMAX_DELAY);
+
+        lockW->WriteCount++;
+        if (lockW->WriteCount == 1) {
+            xSemaphoreTake(lockW->BlockReadersLock, portMAX_DELAY);
+        }
+
+        xSemaphoreGive(lockW->WriteLock);
+
+        xSemaphoreTake(lockW->ResourceLock, portMAX_DELAY);
+
+    }
+    else {
+        configASSERT(!"Bad RW Lock type!");
+    }
+}
+
+
+void WriterUnlock(ReadWriteLock_t *lock)
+{
+    RWLockPreferReader_t *lockR = (RWLockPreferReader_t *)lock;
+    RWLockPreferWriter_t *lockW = (RWLockPreferWriter_t *)lock;
+
+    configASSERT(lockR != NULL);
+
+    if (lockR->Type == RwPreferReader) {
+
+        xSemaphoreGive(lockR->ResourceLock);
+        
+    }
+    else if (lockW->Type == RwPreferWriter) {
+
+        xSemaphoreGive(lockW->ResourceLock);
+
+        xSemaphoreTake(lockW->WriteLock, portMAX_DELAY);
+
+        lockW->WriteCount--;
+        if (lockW->WriteCount == 0) {
+            xSemaphoreGive(lockW->BlockReadersLock);
+        }
+
+        xSemaphoreGive(lockW->WriteLock);
+            
+    }
+    else {
+        configASSERT(!"Bad RW Lock type!");
+    }
+}
+
+
+

+ 209 - 0
addons/c/slist.c

@@ -0,0 +1,209 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#include <stdlib.h>
+#include "slist.h"
+
+
+void SlAddNodeToTail(   SlNode_t *Head, 
+                        SlNode_t *Node)
+{
+    /********************/
+    SlNode_t *Current;
+    /********************/
+
+    if (Head == NULL)
+        return;
+
+    if (Node == NULL)
+        return;
+
+    Current = Head;
+
+    while (Current->Next != NULL){
+        Current = Current->Next;
+    }
+
+    Current->Next = Node;
+    Node->Next = NULL;
+}
+
+
+void SlInsertNodeAfter( SlNode_t *Marker,
+                        SlNode_t *Node)
+{
+    /********************/
+    SlNode_t *Temp;
+    /********************/
+
+    if (Marker == NULL)
+        return;
+
+    if (Node == NULL)
+        return;
+
+    Temp = Marker->Next;
+    Marker->Next = Node;
+    Node->Next = Temp;
+}
+
+
+void SlInsertNodeBefore(SlNode_t *Head, 
+                        SlNode_t *Marker, 
+                        SlNode_t *Node)
+{
+    /********************/
+    SlNode_t *Current;
+    SlNode_t *Prior;
+    int Found = 0;
+    /********************/
+
+    if (Marker == NULL)
+        return;
+
+    if (Node == NULL)
+        return;
+
+    if (Head == NULL)
+        return;
+
+    Current = Head->Next;
+    Prior = Head;
+
+    while (Current != NULL){
+
+        if (Current == Marker){
+            Found = 1;
+            break;
+        }
+
+        Prior = Current;
+        Current = Current->Next;
+    }
+
+    if (Found) {
+        Prior->Next = Node;
+        Node->Next = Current;
+    }
+}
+
+
+void SlRemoveNode ( SlNode_t *Head, 
+                    SlNode_t *Node)
+{
+    /********************/
+    SlNode_t *Current;
+    SlNode_t *Prior;
+    int Found = 0;
+    /********************/
+
+    if (Head == NULL)
+        return;
+
+    if (Node == NULL)
+        return;
+
+    Current = Head->Next;
+    Prior = Head;
+
+    while (Current != NULL){
+
+        if (Current == Node){
+            Found = 1;
+            break;
+        }
+
+        Prior = Current;
+        Current = Current->Next;
+    }
+
+    if (Found) {
+        Prior->Next = Current->Next;
+    }
+}
+
+
+SlNode_t *SlRemoveNodeFromHead(SlNode_t *Head)
+{
+    /********************/
+    SlNode_t *Node;
+    /********************/
+    
+    if (Head == NULL)
+        return NULL;
+
+    Node = Head->Next;
+
+    if (Node != NULL) {
+        Head->Next = Node->Next;
+    }
+
+    return Node;
+}
+
+
+SlNode_t *SlRemoveNodeFromTail(SlNode_t *Head)
+{
+    /********************/
+    SlNode_t *Current;
+    SlNode_t *Prior;
+    /********************/
+
+    if (Head == NULL)
+        return NULL;
+
+    Current = Head->Next;
+    Prior = Head;
+
+    if (SlIsListEmpty(Head)) {
+        return NULL;
+    }
+
+    while (Current->Next != NULL){
+
+        Prior = Current;
+        Current = Current->Next;
+    }
+
+    Prior->Next = NULL;
+
+    return Current;
+}
+
+

+ 84 - 0
addons/c/stack_simple.c

@@ -0,0 +1,84 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#include <stdlib.h>
+#include "stack_simple.h"
+
+
+void InitStack(Stack_t *Stack)
+{
+    Stack->Count = 0;
+    SlInitHead(&Stack->Head);
+}
+
+
+void PushOnStack(   Stack_t *Stack, 
+                    SlNode_t *Node)
+{
+    if (!Stack)
+        return;
+
+    if (!Node)
+        return;
+
+    SlAddNodeToHead(&Stack->Head, Node);
+    Stack->Count++;
+}
+
+
+SlNode_t *PopOffStack(Stack_t *Stack)
+{
+    SlNode_t *Node;    
+
+    if (!Stack)
+        return NULL;
+
+    if (Stack->Count == 0) {
+        return NULL;
+    }
+    else {
+        Stack->Count--;
+    }
+
+    Node = SlRemoveNodeFromHead(&Stack->Head);
+    
+    return Node;
+}
+
+

+ 384 - 0
addons/c/workqueue.c

@@ -0,0 +1,384 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#include <stdlib.h>
+#include "FreeRTOS.h"
+#include "task.h"
+#include "workqueue.h"
+#include "queue_simple.h"
+
+
+/**
+ *  Work Item, what we actually use internally.
+ */
+typedef struct pvtWorkItem_t_ {
+
+    /**
+     *  How we link into the WorkQueue.
+     */
+    DlNode_t Node;
+
+    /**
+     *  The actual function pointer.
+     */
+    WorkItem_t Function;
+
+    /**
+     *  User supplier data.
+     */
+    void *UserData;
+
+} pvtWorkItem_t;
+
+
+/**
+ *  The internal WorkQueue data structure.
+ */
+typedef struct pvtWorkQueue_t_ {
+
+    /**
+     *  The actual queue.
+     */
+    Queue_t Queue;
+
+    /**
+     *  Wake the work queue thread up, something interesting happened.
+     */
+    SemaphoreHandle_t Event;
+
+    SemaphoreHandle_t Lock;
+
+    TaskHandle_t WorkerThread;
+
+#if (INCLUDE_vTaskDelete == 1)
+    /**
+     *  Flag if we are tearing down the WorkQueue.
+     */    
+    int ExitThread;
+
+#endif
+
+} pvtWorkQueue_t;
+
+
+
+static void WorkerThread(void *parameters)
+{
+    /****************************************/
+    pvtWorkQueue_t *WorkQueue;
+    DlNode_t *Node;
+    pvtWorkItem_t *WorkItem;
+
+#if (INCLUDE_vTaskDelete == 1)
+
+    TaskHandle_t handle;
+    int ExitThread;
+
+#endif
+    /****************************************/
+
+
+    WorkQueue = (pvtWorkQueue_t*)parameters;
+
+
+    while (1) {
+
+        /**
+         *  Wait to be woken.
+         */
+        xSemaphoreTake(WorkQueue->Event, portMAX_DELAY);
+
+        /**
+         *  Lock the queue
+         */
+        xSemaphoreTake(WorkQueue->Lock, portMAX_DELAY);
+
+        /**
+         *  Keep looping until the work items are all done.
+         */
+        while ( !IsQueueEmpty(&WorkQueue->Queue)) {
+            /**
+             *  Dequeue an item.
+             */
+            Node = Dequeue(&WorkQueue->Queue);
+
+            /**
+             *  Unlock the queue, the lock is really only for 
+             *  the Queue struct.
+             */
+            xSemaphoreGive(WorkQueue->Lock);
+
+            /**
+             *  Recover the actual work item pointer.
+             */
+            WorkItem = CONTAINING_RECORD(Node, pvtWorkItem_t, Node);
+
+            /**
+             *  And call the function.
+             */
+            WorkItem->Function(WorkItem->UserData);
+
+            /**
+             *  All done, free it.
+             */
+            free(WorkItem);
+
+            /**
+             *  Lock the queue again so we can check if the 
+             *  Queue is empty yet.
+             */
+            xSemaphoreTake(WorkQueue->Lock, portMAX_DELAY);
+        }
+    
+#if (INCLUDE_vTaskDelete == 1)
+        /**
+         *  Are we being asked to exit? We want to do this while
+         *  holding the lock.
+         */
+        ExitThread = WorkQueue->ExitThread;
+
+#endif
+        /**
+         *  Unlock now
+         */
+        xSemaphoreGive(WorkQueue->Lock);
+
+#if (INCLUDE_vTaskDelete == 1)
+        /**
+         *  If we need to exit, then jump out of the task loop.
+         */
+        if (ExitThread) {
+            break;
+        }
+
+#endif
+    }
+
+#if (INCLUDE_vTaskDelete == 1)
+    
+    /**
+     *  Thread cleanup here.
+     */
+
+    /**
+     *  Lock this work queue.
+     */
+    xSemaphoreTake(WorkQueue->Lock, portMAX_DELAY);
+
+    /**
+     *  Drain the queue and free everything.
+     */
+    while ( !IsQueueEmpty(&WorkQueue->Queue)) {
+        
+        /**
+         *  Dequeue the node
+         */
+        Node = Dequeue(&WorkQueue->Queue);
+
+        /**
+         *  Recover the work item from the node.
+         */
+        WorkItem = CONTAINING_RECORD(Node, pvtWorkItem_t, Node);
+
+        /**
+         *  And free it.
+         */
+        free(WorkItem);
+    }
+
+    /**
+     *  Finally unlock
+     */
+    xSemaphoreGive(WorkQueue->Lock);
+
+    /**
+     *  Free the semaphores
+     */
+    vSemaphoreDelete(WorkQueue->Lock);
+    vSemaphoreDelete(WorkQueue->Event);
+
+    /**
+     *  We need to save a local copy of our handle. 
+     */
+    handle = WorkQueue->WorkerThread;
+
+    /**
+     *  And free the work queue stat structure itself.
+     */
+    free(WorkQueue);
+
+    /**
+     *  Finally delete ourselves, we won't go past this call.
+     */
+    vTaskDelete(handle);
+
+#endif    
+}
+
+
+WorkQueue_t CreateWorkQueueEx(  const char * const Name,
+                                uint16_t StackSize,
+                                UBaseType_t Priority)
+{
+    /****************************/
+    pvtWorkQueue_t *WorkQueue;
+    BaseType_t rc;
+    /****************************/
+    
+    WorkQueue = (pvtWorkQueue_t *)malloc(sizeof(pvtWorkQueue_t));
+
+    if (WorkQueue == NULL)
+        return NULL;
+
+    InitQueue(&WorkQueue->Queue);
+
+    WorkQueue->Event = xSemaphoreCreateBinary();
+
+    if (WorkQueue->Event == NULL) {
+        free(WorkQueue);
+        return NULL;
+    }
+
+    WorkQueue->Lock = xSemaphoreCreateMutex();
+
+    if (WorkQueue->Lock == NULL) {
+        vSemaphoreDelete(WorkQueue->Event);
+        free(WorkQueue);
+        return NULL;
+    }
+
+#if (INCLUDE_vTaskDelete == 1)
+ 
+    WorkQueue->ExitThread = 0;
+
+#endif
+
+    rc = xTaskCreate(   WorkerThread,
+                        Name,
+                        StackSize,
+                        WorkQueue,
+                        Priority,
+                        &WorkQueue->WorkerThread);
+
+    if (rc != pdPASS) {
+        vSemaphoreDelete(WorkQueue->Lock);
+        vSemaphoreDelete(WorkQueue->Event);
+        free(WorkQueue);
+        return NULL;
+    }
+
+    return WorkQueue;
+}
+
+
+#if (INCLUDE_vTaskDelete == 1)
+
+void DestroyWorkQueue(WorkQueue_t wq)
+{
+    /****************************/
+    pvtWorkQueue_t *WorkQueue;
+    /****************************/
+
+    WorkQueue = (pvtWorkQueue_t *)wq;
+
+    /**
+     *  Lock
+     */
+    xSemaphoreTake(WorkQueue->Lock, portMAX_DELAY);
+
+    /**
+     *  Flag we are all done.
+     */
+    WorkQueue->ExitThread = 1;
+    
+    /**
+     *  Signal the Worker thead.
+     */
+    xSemaphoreGive(WorkQueue->Event);
+
+    /**
+     *  Unlock
+     */
+    xSemaphoreGive(WorkQueue->Lock);
+}
+
+#endif
+
+
+int QueueWorkItem(WorkQueue_t wq, WorkItem_t Function, void *UserData)
+{
+    /****************************/
+    pvtWorkQueue_t *WorkQueue;
+    pvtWorkItem_t *WorkItem;
+    /****************************/
+
+    WorkQueue = (pvtWorkQueue_t *)wq;
+
+    WorkItem = (pvtWorkItem_t *)malloc(sizeof(pvtWorkItem_t));
+    if (WorkItem == NULL) {
+        return pdFAIL;
+    }
+
+    WorkItem->Function = Function;
+    WorkItem->UserData = UserData;
+
+    /**
+     *  Lock the queue
+     */
+    xSemaphoreTake(WorkQueue->Lock, portMAX_DELAY);
+
+    /**
+     *  Put the work item on the queue.
+     */
+    Enqueue(&WorkQueue->Queue, &WorkItem->Node);
+    
+    /**
+     *  Wake the Worker thread up.
+     */
+    xSemaphoreGive(WorkQueue->Event);
+
+    /**
+     *  Unlock the queue
+     */
+    xSemaphoreGive(WorkQueue->Lock);
+
+    return pdPASS;
+}
+
+

+ 146 - 0
addons/c/zero_copy_queue.c

@@ -0,0 +1,146 @@
+/****************************************************************************
+ *
+ *  Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
+ *
+ *  This file is part of the FreeRTOS Add-ons project.
+ *
+ *  Source Code:
+ *  https://github.com/michaelbecker/freertos-addons
+ *
+ *  Project Page:
+ *  http://michaelbecker.github.io/freertos-addons/
+ *
+ *  On-line Documentation:
+ *  http://michaelbecker.github.io/freertos-addons/docs/html/index.html
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files
+ *  (the "Software"), to deal in the Software without restriction, including
+ *  without limitation the rights to use, copy, modify, merge, publish,
+ *  distribute, sublicense, and/or sell copies of the Software, and to
+ *  permit persons to whom the Software is furnished to do so,subject to the
+ *  following conditions:
+ *
+ *  + The above copyright notice and this permission notice shall be included
+ *    in all copies or substantial portions of the Software.
+ *  + Credit is appreciated, but not required, if you find this project
+ *    useful enough to include in your application, product, device, etc.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ***************************************************************************/
+
+
+#include <stdlib.h>
+#include "FreeRTOS.h"
+#include "queue.h"
+#include "mem_pool.h"
+#include "zero_copy_queue.h"
+
+
+typedef struct PvtZeroCopyQueue_t_ {
+
+    MemoryPool_t Pool;
+    QueueHandle_t Handle;
+
+} PvtZeroCopyQueue_t;
+
+
+ZeroCopyQueue_t ZcqCreateQueue( int ItemSize,
+                                int ItemCount,
+                                int Alignment)
+{
+    /******************************/
+    PvtZeroCopyQueue_t *zcq;
+    /******************************/
+
+    zcq = (PvtZeroCopyQueue_t *)malloc(sizeof(PvtZeroCopyQueue_t));
+    if (zcq == NULL) {
+        return NULL;
+    }
+    
+    zcq->Handle = xQueueCreate(ItemCount, sizeof(void *));
+    if (zcq->Handle == NULL) {
+        free(zcq);
+        return NULL;
+    }
+
+    zcq->Pool = CreateMemoryPool(ItemSize, ItemCount, Alignment);
+    if (zcq->Pool == NULL) {
+        free(zcq);
+        vQueueDelete(zcq->Handle);
+        return NULL;
+    }
+
+    return (ZeroCopyQueue_t)zcq;
+}
+
+
+void *ZcqAllocateItem(ZeroCopyQueue_t z)
+{
+    /******************************/
+    PvtZeroCopyQueue_t *zcq;
+    void *Item;
+    /******************************/
+
+    zcq = (PvtZeroCopyQueue_t *)z;
+
+    Item = MemoryPoolAllocate(zcq->Pool);
+
+    return Item;
+}
+
+
+void ZcqFreeItem(   ZeroCopyQueue_t z, 
+                    void *Item)
+{
+    /******************************/
+    PvtZeroCopyQueue_t *zcq;
+    /******************************/
+
+    zcq = (PvtZeroCopyQueue_t *)z;
+
+    MemoryPoolFree(zcq->Pool, Item);
+}
+
+
+int ZcqEnqueueItem( ZeroCopyQueue_t z, 
+                    void *Item, 
+                    TickType_t Timeout)
+{
+    /******************************/
+    PvtZeroCopyQueue_t *zcq;
+    BaseType_t success;
+    /******************************/
+
+    zcq = (PvtZeroCopyQueue_t *)z;
+
+    success = xQueueSendToBack(zcq->Handle, &Item, Timeout);
+
+    return success == pdTRUE ? 1 : 0;
+}
+
+
+void *ZcqDequeueItem(   ZeroCopyQueue_t z,
+                        TickType_t Timeout)
+{
+    /******************************/
+    PvtZeroCopyQueue_t *zcq;
+    BaseType_t success;
+    void *Item;
+    /******************************/
+
+    zcq = (PvtZeroCopyQueue_t *)z;
+
+    success = xQueueReceive(zcq->Handle, &Item, Timeout);
+
+    return success == pdTRUE ? Item : NULL;
+}
+
+

+ 0 - 0
changelog.md


+ 0 - 0
event_groups.c → kernel/event_groups.c


+ 0 - 0
fmq.c → kernel/fmq.c


+ 0 - 0
heap.c → kernel/heap.c


+ 0 - 0
include/FreeRTOS.h → kernel/include/FreeRTOS.h


+ 0 - 0
include/StackMacros.h → kernel/include/StackMacros.h


+ 0 - 0
include/croutine.h → kernel/include/croutine.h


+ 0 - 0
include/deprecated_definitions.h → kernel/include/deprecated_definitions.h


+ 0 - 0
include/event_groups.h → kernel/include/event_groups.h


+ 0 - 0
include/list.h → kernel/include/list.h


+ 0 - 0
include/mpu_wrappers.h → kernel/include/mpu_wrappers.h


+ 0 - 0
include/portable.h → kernel/include/portable.h


+ 0 - 0
include/portmacro.h → kernel/include/portmacro.h


+ 0 - 0
include/projdefs.h → kernel/include/projdefs.h


+ 0 - 0
include/queue.h → kernel/include/queue.h


+ 0 - 0
include/semphr.h → kernel/include/semphr.h


+ 0 - 0
include/task.h → kernel/include/task.h


+ 0 - 0
include/timers.h → kernel/include/timers.h


+ 0 - 0
list.c → kernel/list.c


+ 0 - 0
port.c → kernel/port.c


+ 0 - 0
port_tick.c → kernel/port_tick.c


+ 0 - 0
queue.c → kernel/queue.c


+ 0 - 0
tasks.c → kernel/tasks.c


+ 0 - 0
timers.c → kernel/timers.c


+ 3 - 0
readme.md

@@ -0,0 +1,3 @@
+# RT-Thread操作系统的FreeRTOS兼容层
+
+## 让基于FreeRTOS开发的应用层无感地迁移到RT-Thread操作系统