diff --git a/binary_semaphore.h b/binary_semaphore.h new file mode 100644 index 0000000..56b9d5e --- /dev/null +++ b/binary_semaphore.h @@ -0,0 +1,33 @@ +#pragma once + +// espressif includes +#include +#include +#include + +// local includes +#include "esputils.h" + +namespace espcpputils { +class binary_semaphore +{ + ESP_DISABLE_COPY_MOVE(binary_semaphore) + +public: + binary_semaphore() : + handle{xSemaphoreCreateBinary()} + {} + + ~binary_semaphore() { if (handle) vSemaphoreDelete(handle); } + + TaskHandle_t getMutexHolder() const { return xSemaphoreGetMutexHolder(handle); } + + UBaseType_t getCount() const { return uxSemaphoreGetCount(handle); } + + bool take(TickType_t xTicksToWait) { return xSemaphoreTake(handle, xTicksToWait); } + + bool give() { return xSemaphoreGive(handle); } + + const SemaphoreHandle_t handle; +}; +} // namespace espcpputils diff --git a/counting_semaphore.h b/counting_semaphore.h new file mode 100644 index 0000000..9c7d408 --- /dev/null +++ b/counting_semaphore.h @@ -0,0 +1,33 @@ +#pragma once + +// espressif includes +#include +#include +#include + +// local includes +#include "esputils.h" + +namespace espcpputils { +class counting_semaphore +{ + ESP_DISABLE_COPY_MOVE(counting_semaphore) + +public: + counting_semaphore(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount) : + handle{xSemaphoreCreateCounting(uxMaxCount, uxInitialCount)} + {} + + ~counting_semaphore() { if (handle) vSemaphoreDelete(handle); } + + TaskHandle_t getMutexHolder() const { return xSemaphoreGetMutexHolder(handle); } + + UBaseType_t getCount() const { return uxSemaphoreGetCount(handle); } + + bool take(TickType_t xTicksToWait) { return xSemaphoreTake(handle, xTicksToWait); } + + bool give() { return xSemaphoreGive(handle); } + + const SemaphoreHandle_t handle; +}; +} // namespace espcpputils diff --git a/esputils.h b/esputils.h index 8e63d5c..e6f1b0f 100644 --- a/esputils.h +++ b/esputils.h @@ -106,6 +106,4 @@ public: private: std::vector m_slots; }; - - } // namespace espcpputils diff --git a/lockhelper.h b/lockhelper.h new file mode 100644 index 0000000..a2e0e2b --- /dev/null +++ b/lockhelper.h @@ -0,0 +1,52 @@ +#pragma once + +// espressif includes +#include +#include + +// local includes +#include "esputils.h" + +namespace espcpputils { +class LockHelper +{ + ESP_DISABLE_COPY_MOVE(LockHelper) + +public: + LockHelper(QueueHandle_t _xMutex, TickType_t xTicksToWait=portMAX_DELAY) : + xMutex{_xMutex} + { + locked = xSemaphoreTakeRecursive(xMutex, xTicksToWait); + } + + ~LockHelper() + { + if (locked) + xSemaphoreGiveRecursive(xMutex); + } + + bool lock(TickType_t xTicksToWait=portMAX_DELAY) + { + if (locked) + return false; + + locked = xSemaphoreTakeRecursive(xMutex, xTicksToWait); + + return locked; + } + + bool unlock() + { + if (!locked) + return false; + + locked = !xSemaphoreGiveRecursive(xMutex); + + return locked; + } + +private: + const QueueHandle_t xMutex; + bool locked; +}; +} // namespace espcpputils diff --git a/lockingqueue.h b/lockingqueue.h new file mode 100644 index 0000000..3273737 --- /dev/null +++ b/lockingqueue.h @@ -0,0 +1,71 @@ +#pragma once + +// system includes +#include + +// espressif includes +#include +#include + +// local includes +#include "esputils.h" +#include "delayedconstruction.h" +#include "recursive_mutex_semaphore.h" +#include "recursivelockhelper.h" + +namespace espcpputils { +template +class LockingQueue +{ +public: + void push(const T &val); + void push(T &&val); + + std::optional tryPop(); + + void clear(); + + std::size_t size() const { return m_size; } + +private: + espcpputils::recursive_mutex_semaphore m_lock; + std::vector m_queue; + std::size_t m_size{}; // double-buffered to allow for reading without taking a lock +}; + +template +void LockingQueue::push(const T &val) +{ + RecursiveLockHelper helper{m_lock.handle}; + m_queue.push_back(val); + m_size = m_queue.size(); +} + +template +void LockingQueue::push(T &&val) +{ + RecursiveLockHelper helper{m_lock.handle}; + m_queue.emplace_back(std::move(val)); + m_size = m_queue.size(); +} + +template +std::optional LockingQueue::tryPop() +{ + RecursiveLockHelper helper{m_lock.handle}; + if (m_queue.empty()) + return std::nullopt; + + std::optional temp = std::move(m_queue.front()); + m_queue.erase(std::begin(m_queue)); + m_size = m_queue.size(); + return temp; +} + +template +void LockingQueue::clear() +{ + RecursiveLockHelper helper{m_lock.handle}; + m_queue.clear(); +} +} // namespace espcpputils diff --git a/mutex_semaphore.h b/mutex_semaphore.h new file mode 100644 index 0000000..a72008e --- /dev/null +++ b/mutex_semaphore.h @@ -0,0 +1,33 @@ +#pragma once + +// espressif includes +#include +#include +#include + +// local includes +#include "esputils.h" + +namespace espcpputils { +class mutex_semaphore +{ + ESP_DISABLE_COPY_MOVE(mutex_semaphore) + +public: + mutex_semaphore() : + handle{xSemaphoreCreateMutex()} + {} + + ~mutex_semaphore() { if (handle) vSemaphoreDelete(handle); } + + TaskHandle_t getMutexHolder() const { return xSemaphoreGetMutexHolder(handle); } + + UBaseType_t getCount() const { return uxSemaphoreGetCount(handle); } + + bool take(TickType_t xTicksToWait) { return xSemaphoreTake(handle, xTicksToWait); } + + bool give() { return xSemaphoreGive(handle); } + + const SemaphoreHandle_t handle; +}; +} // namespace espcpputils diff --git a/recursive_mutex_semaphore.h b/recursive_mutex_semaphore.h new file mode 100644 index 0000000..a6a34ba --- /dev/null +++ b/recursive_mutex_semaphore.h @@ -0,0 +1,33 @@ +#pragma once + +// espressif includes +#include +#include +#include + +// local includes +#include "esputils.h" + +namespace espcpputils { +class recursive_mutex_semaphore +{ + ESP_DISABLE_COPY_MOVE(recursive_mutex_semaphore) + +public: + recursive_mutex_semaphore() : + handle{xSemaphoreCreateRecursiveMutex()} + {} + + ~recursive_mutex_semaphore() { if (handle) vSemaphoreDelete(handle); } + + TaskHandle_t getMutexHolder() const { return xSemaphoreGetMutexHolder(handle); } + + UBaseType_t getCount() const { return uxSemaphoreGetCount(handle); } + + bool takeRecursive(TickType_t xTicksToWait) { return xSemaphoreTakeRecursive(handle, xTicksToWait); } + + bool giveRecursive() { return xSemaphoreGiveRecursive(handle); } + + const SemaphoreHandle_t handle; +}; +} // namespace espcpputils diff --git a/recursivelockhelper.h b/recursivelockhelper.h new file mode 100644 index 0000000..c522c88 --- /dev/null +++ b/recursivelockhelper.h @@ -0,0 +1,52 @@ +#pragma once + +// espressif includes +#include +#include + +// local includes +#include "esputils.h" + +namespace espcpputils { +class RecursiveLockHelper +{ + ESP_DISABLE_COPY_MOVE(RecursiveLockHelper) + +public: + RecursiveLockHelper(QueueHandle_t _xMutex, TickType_t xTicksToWait=portMAX_DELAY) : + xMutex{_xMutex} + { + locked = xSemaphoreTakeRecursive(xMutex, xTicksToWait); + } + + ~RecursiveLockHelper() + { + if (locked) + xSemaphoreGiveRecursive(xMutex); + } + + bool lock(TickType_t xTicksToWait=portMAX_DELAY) + { + if (locked) + return false; + + locked = xSemaphoreTakeRecursive(xMutex, xTicksToWait); + + return locked; + } + + bool unlock() + { + if (!locked) + return false; + + locked = !xSemaphoreGiveRecursive(xMutex); + + return locked; + } + +private: + const QueueHandle_t xMutex; + bool locked; +}; +} // namespace espcpputils