diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..b4d9259 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/SimplyAtomic"] + path = src/SimplyAtomic + url = https://github.com/wizard97/SimplyAtomic diff --git a/README.md b/README.md index c815ade..8f5f01f 100644 --- a/README.md +++ b/README.md @@ -53,14 +53,27 @@ Creates a new RingBuf object that can buffer up to MaxElements of type Type. ## Methods -### add() +### add() / append() / push() ```c++ bool add(Type &obj); +bool append(Type &obj); +bool push(Type &obj); ``` Append an element to the buffer. Return true on success, false on a full buffer. +All three methods are identical, except for their name. + +### prepend() + +```c++ +bool prepend(Type &obj); +``` + +Prepend an element to the buffer. Return true on success, false on a full buffer. + + ### peek() ```c++ @@ -72,11 +85,20 @@ Peek at the num'th element in the buffer. Returns a pointer to the location of t ### pull() ```c++ -bool pull(Type *dest); +bool pull(Type *dest = nullptr); +bool pull(Type &dest); ``` -Pull the first element out of the buffer. The first element is copied into the location pointed to by dest. Returns false if the buffer is empty, otherwise returns true on success. +Pull the first element out of the buffer. If a non-null pointer is passed, the removed element is copied into the location pointed to or referenced by dest. Returns false if the buffer is empty, otherwise returns true on success. + +### pop() + +```c++ +bool pop(Type *dest = nullptr); +bool pop(Type &dest); +``` +Pop the last element out of the buffer. If a non-null pointer is passed, the removed element is copied into the location pointed to or referenced by dest. Returns false if the buffer is empty, otherwise returns true on success. ### numElements() ```c++ diff --git a/RingBufCPP.h b/RingBufCPP.h deleted file mode 100644 index c00534e..0000000 --- a/RingBufCPP.h +++ /dev/null @@ -1,159 +0,0 @@ -#ifndef EM_RINGBUF_CPP_H -#define EM_RINGBUF_CPP_H - -#include "RingBufHelpers.h" - -template -class RingBufCPP -{ -public: - -RingBufCPP() -{ - RB_ATOMIC_START - { - _numElements = 0; - - _head = 0; - } - RB_ATOMIC_END -} - -/** -* Add element obj to the buffer -* Return: true on success -*/ -bool add(const Type &obj) -{ - bool ret = false; - RB_ATOMIC_START - { - if (!isFull()) { - _buf[_head] = obj; - _head = (_head + 1)%MaxElements; - _numElements++; - - ret = true; - } - } - RB_ATOMIC_END - - return ret; -} - - -/** -* Remove last element from buffer, and copy it to dest -* Return: true on success -*/ -bool pull(Type *dest) -{ - bool ret = false; - size_t tail; - - RB_ATOMIC_START - { - if (!isEmpty()) { - tail = getTail(); - *dest = _buf[tail]; - _numElements--; - - ret = true; - } - } - RB_ATOMIC_END - - return ret; -} - - -/** -* Peek at num'th element in the buffer -* Return: a pointer to the num'th element -*/ -Type* peek(size_t num) const -{ - Type *ret = NULL; - - RB_ATOMIC_START - { - if (num < _numElements) //make sure not out of bounds - ret = &_buf[(getTail() + num)%MaxElements]; - } - RB_ATOMIC_END - - return ret; -} - - -/** -* Return: true if buffer is full -*/ -bool isFull() const -{ - bool ret; - - RB_ATOMIC_START - { - ret = _numElements >= MaxElements; - } - RB_ATOMIC_END - - return ret; -} - - -/** -* Return: number of elements in buffer -*/ -size_t numElements() const -{ - size_t ret; - - RB_ATOMIC_START - { - ret = _numElements; - } - RB_ATOMIC_END - - return ret; -} - - -/** -* Return: true if buffer is empty -*/ -bool isEmpty() const -{ - bool ret; - - RB_ATOMIC_START - { - ret = !_numElements; - } - RB_ATOMIC_END - - return ret; -} - -protected: -/** -* Calculates the index in the array of the oldest element -* Return: index in array of element -*/ -size_t getTail() const -{ - return (_head + (MaxElements - _numElements))%MaxElements; -} - - -// underlying array -Type _buf[MaxElements]; - -size_t _head; -size_t _numElements; -private: - -}; - -#endif diff --git a/RingBufHelpers.h b/RingBufHelpers.h deleted file mode 100644 index cb4e77d..0000000 --- a/RingBufHelpers.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef EM_RINGBUF_HELPERS_CPP_H -#define EM_RINGBUF_HELPERS_CPP_H - -// TODO fix this -#ifndef NULL - #define NULL (void *)(0) -#endif - -#ifdef ARDUINO - #include -#else - #include -#endif - -#ifdef ARDUINO - - #if defined(ARDUINO_ARCH_AVR) - #include - #define RB_ATOMIC_START ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - #define RB_ATOMIC_END } - - - #elif defined(ARDUINO_ARCH_ESP8266) - #ifndef __STRINGIFY - #define __STRINGIFY(a) #a - #endif - - #ifndef xt_rsil - #define xt_rsil(level) (__extension__({uint32_t state; __asm__ __volatile__("rsil %0," __STRINGIFY(level) : "=a" (state)); state;})) - #endif - - #ifndef xt_wsr_ps - #define xt_wsr_ps(state) __asm__ __volatile__("wsr %0,ps; isync" :: "a" (state) : "memory") - #endif - - #define RB_ATOMIC_START do { uint32_t _savedIS = xt_rsil(15) ; - #define RB_ATOMIC_END xt_wsr_ps(_savedIS); } while(0); - - #else - #define RB_ATOMIC_START { - #define RB_ATOMIC_END } - #warning “This library only fully supports AVR and ESP8266 Boards.” - #warning "Operations on the buffer in ISRs are not safe!" - #endif - -#else - #define RB_ATOMIC_START { - #define RB_ATOMIC_END } - #warning "Operations on the buffer in ISRs are not safe!" - #warning "Impliment RB_ATOMIC_START and RB_ATOMIC_END macros for safe ISR operation!" -#endif - -#endif diff --git a/library.properties b/library.properties index 04d5fe6..ace39ac 100644 --- a/library.properties +++ b/library.properties @@ -2,8 +2,8 @@ name=RingBufCPP version=1.1 author=D. Aaron Wisner (daw268@cornell.edu) maintainer=D. Aaron Wisner (daw268@cornell.edu) -sentence=A library for buffering items into a ring (circular/FIFO) buffer +sentence=A library for buffering items into a ring (circular/FIFO) buffer, using C++ and templates paragraph=This library is perfect for capturing pin states, timestamps, etc.. during an ISR. Then in void loop(), the buffer can be asynchronously processed whenever your program has free time. category=Data Storage -url=https://github.com/wizard97/ArduinoRingBuffer -architectures=avr,esp8266 +url=https://github.com/wizard97/Embedded_RingBuf_CPP +architectures=* diff --git a/src/RingBufCPP.h b/src/RingBufCPP.h new file mode 100644 index 0000000..361844a --- /dev/null +++ b/src/RingBufCPP.h @@ -0,0 +1,251 @@ +/* +The MIT License (MIT) + +Copyright (c) 2015 D. Aaron Wisner + +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. + +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 EM_RINGBUF_CPP_H +#define EM_RINGBUF_CPP_H + +#include "SimplyAtomic/SimplyAtomic.h" + +template +class RingBufCPP +{ +public: + +RingBufCPP() +{ + ATOMIC() + { + _numElements = 0; + + _head = 0; + } +} + +/** +* Append element obj to the buffer +* Return: true on success +*/ +bool add(const Type &obj) +{ + bool ret = false; + + ATOMIC() + { + if (!isFull()) { + _buf[_head] = obj; + _head = (_head + 1)%MaxElements; + _numElements++; + + ret = true; + } + } + + return ret; +} + +/** +* Convenience alias of add. +*/ +bool push(const Type &obj) { return add(obj); } + +/** +* Convenience alias of add. +*/ +bool append(const Type &obj) { return add(obj); } + +/** +* Prepend element obj to the buffer +* Return: true on success +*/ +bool prepend(const Type &obj) +{ + bool ret = false; + size_t tail; + ATOMIC() + { + if (!isFull()) { + _numElements++; + tail = getTail(); + _buf[tail] = obj; + + ret = true; + } + } + + return ret; +} + +/** +* Remove first element from buffer, and copy it to dest. This is the +* inverse of prepend. +* Return: true on success +*/ +bool pull(Type *dest = nullptr) +{ + bool ret = false; + size_t tail; + + ATOMIC() + { + if (!isEmpty()) { + tail = getTail(); + if (dest) + *dest = _buf[tail]; + _numElements--; + + ret = true; + } + } + + return ret; +} + + +/** +* Remove first element from buffer, and copy it to dest. This is the +* inverse of prepend. +* Return: true on success +*/ +bool pull(Type &dest) { return pull(&dest); } + + +/** +* Remove last element from buffer, and copy it to dest. This is the +* inverse of push/add/append. +* Return: true on success +*/ +bool pop(Type *dest = nullptr) +{ + bool ret = false; + + ATOMIC() + { + if (!isEmpty()) { + if (dest) + *dest = _buf[_head]; + _head = (_head + MaxElements - 1)%MaxElements; + _numElements--; + + ret = true; + } + } + + return ret; +} + + +/** +* Remove last element from buffer, and copy it to dest. This is the +* inverse of push/add/append. +* Return: true on success +*/ +bool pop(Type &dest) { return pop(&dest); } + + +/** +* Peek at num'th element in the buffer +* Return: a pointer to the num'th element +*/ +Type* peek(size_t num) const +{ + Type *ret = NULL; + + ATOMIC() + { + if (num < _numElements) //make sure not out of bounds + ret = &_buf[(getTail() + num)%MaxElements]; + } + + return ret; +} + + +/** +* Return: true if buffer is full +*/ +bool isFull() const +{ + bool ret; + + ATOMIC() + { + ret = _numElements >= MaxElements; + } + + return ret; +} + + +/** +* Return: number of elements in buffer +*/ +size_t numElements() const +{ + size_t ret; + + ATOMIC() + { + ret = _numElements; + } + + return ret; +} + + +/** +* Return: true if buffer is empty +*/ +bool isEmpty() const +{ + bool ret; + + ATOMIC() + { + ret = !_numElements; + } + + return ret; +} + +protected: +/** +* Calculates the index in the array of the oldest element +* Return: index in array of element +*/ +size_t getTail() const +{ + return (_head + (MaxElements - _numElements))%MaxElements; +} + + +// underlying array +Type _buf[MaxElements]; + +size_t _head; +size_t _numElements; +private: + +}; + +#endif diff --git a/src/SimplyAtomic b/src/SimplyAtomic new file mode 160000 index 0000000..e5113f6 --- /dev/null +++ b/src/SimplyAtomic @@ -0,0 +1 @@ +Subproject commit e5113f65f4212b271eff58a6fba9659dea8b8534