Skip to content

Commit a7b7d08

Browse files
authored
feat: Add ISR support to semaphores, rewrite docs (#16)
* docs: Update FromISR task_woken doxygen comment * feat: Add ISR support to semaphore interface and implementations * docs: Rewrite docs and bump version
1 parent 8ea1ca6 commit a7b7d08

9 files changed

Lines changed: 568 additions & 265 deletions

README.md

Lines changed: 397 additions & 211 deletions
Large diffs are not rendered by default.

library.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "RTOScppESP32",
3-
"version": "1.1.1",
3+
"version": "1.2.0",
44
"authors": {
55
"name": "Maximiliano Ramirez",
66
"email": "maximiliano.ramirezbravo@gmail.com"

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=RTOScppESP32
2-
version=1.1.1
2+
version=1.2.0
33
author=Maximiliano Ramirez <maximiliano.ramirezbravo@gmail.com>
44
maintainer=Maximiliano Ramirez <maximiliano.ramirezbravo@gmail.com>
55
sentence=FreeRTOS abstraction layer for ESP32 with C++ interface.

src/RTOScppBuffer.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ class IBuffer {
5757
* @brief Send data to the buffer from an ISR.
5858
* @param tx_buffer Data to send.
5959
* @param bytes Number of bytes to send.
60-
* @param task_woken Task woken flag. If true, you need to use portYIELD_FROM_ISR() at the end of
61-
* the ISR.
60+
* @param task_woken Higher priority task woken flag. You need to use
61+
* portYIELD_FROM_ISR(task_woken) at the end of the ISR.
6262
* @return uint32_t Number of bytes sent, 0 if the buffer is not created.
6363
*/
6464
virtual uint32_t sendFromISR(const void* tx_buffer, const uint32_t bytes,
@@ -79,8 +79,8 @@ class IBuffer {
7979
* @brief Receive data from the buffer from an ISR.
8080
* @param rx_buffer Buffer to store the received data.
8181
* @param bytes Number of bytes to receive.
82-
* @param task_woken Task woken flag. If true, you need to use portYIELD_FROM_ISR() at the end of
83-
* the ISR.
82+
* @param task_woken Higher priority task woken flag. You need to use
83+
* portYIELD_FROM_ISR(task_woken) at the end of the ISR.
8484
* @return uint32_t Number of bytes received, 0 if the buffer is not created or failed to receive
8585
* the data.
8686
*/
@@ -336,8 +336,8 @@ class DataBuffer : public IBuffer, public Policy {
336336
* @brief Send data to the buffer from an ISR.
337337
* @param tx_buffer Data to send.
338338
* @param bytes Number of bytes to send.
339-
* @param task_woken Task woken flag. If true, you need to use portYIELD_FROM_ISR() at the end of
340-
* the ISR.
339+
* @param task_woken Higher priority task woken flag. You need to use
340+
* portYIELD_FROM_ISR(task_woken) at the end of the ISR.
341341
* @return uint32_t Number of bytes sent, 0 if the buffer is not created.
342342
*/
343343
uint32_t sendFromISR(const void* tx_buffer, const uint32_t bytes,
@@ -364,8 +364,8 @@ class DataBuffer : public IBuffer, public Policy {
364364
* @brief Receive data from the buffer from an ISR.
365365
* @param rx_buffer Buffer to store the received data.
366366
* @param bytes Number of bytes to receive.
367-
* @param task_woken Task woken flag. If true, you need to use portYIELD_FROM_ISR() at the end of
368-
* the ISR.
367+
* @param task_woken Higher priority task woken flag. You need to use
368+
* portYIELD_FROM_ISR(task_woken) at the end of the ISR.
369369
* @return uint32_t Number of bytes received, 0 if the buffer is not created or failed to receive
370370
* the data.
371371
*/

src/RTOScppLock.h

Lines changed: 121 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,31 @@ inline bool operator==(const QueueSetMemberHandle_t& queue_set_member, const ILo
7070
return queue_set_member == lock.getHandle();
7171
}
7272

73+
// Interface for Semaphore objects, extends ILock with ISR support
74+
class ISemaphore : public ILock {
75+
protected:
76+
ISemaphore() = default;
77+
78+
public:
79+
/**
80+
* @brief Give the semaphore from an ISR.
81+
* @param task_woken Higher priority task woken flag. You need to use
82+
* portYIELD_FROM_ISR(task_woken) at the end of the ISR.
83+
* @return true Semaphore given successfully, false if the semaphore is not created or failed to
84+
* give.
85+
*/
86+
virtual bool giveFromISR(BaseType_t& task_woken) = 0;
87+
88+
/**
89+
* @brief Take the semaphore from an ISR.
90+
* @param task_woken Higher priority task woken flag. You need to use
91+
* portYIELD_FROM_ISR(task_woken) at the end of the ISR.
92+
* @return true Semaphore taken successfully, false if the semaphore is not created or failed to
93+
* take.
94+
*/
95+
virtual bool takeFromISR(BaseType_t& task_woken) = 0;
96+
};
97+
7398
namespace Internal {
7499

75100
// CRTP base policy class
@@ -185,6 +210,17 @@ class SemaphoreBinaryPolicy : public Policy<SemaphoreBinaryPolicy<Derived>> {
185210
}
186211

187212
bool giveImpl() { return xSemaphoreGive(this->_handle); }
213+
214+
public:
215+
bool takeFromISR(BaseType_t& task_woken) {
216+
if (!this->isCreated()) return false;
217+
return xSemaphoreTakeFromISR(this->_handle, &task_woken);
218+
}
219+
220+
bool giveFromISR(BaseType_t& task_woken) {
221+
if (!this->isCreated()) return false;
222+
return xSemaphoreGiveFromISR(this->_handle, &task_woken);
223+
}
188224
};
189225

190226
// Policy for binary semaphore with dynamic memory allocation
@@ -231,6 +267,16 @@ class SemaphoreCountingPolicy : public Policy<SemaphoreCountingPolicy<Derived>>
231267
if (!this->isCreated()) return 0;
232268
return uxSemaphoreGetCount(this->_handle);
233269
}
270+
271+
bool takeFromISR(BaseType_t& task_woken) {
272+
if (!this->isCreated()) return false;
273+
return xSemaphoreTakeFromISR(this->_handle, &task_woken);
274+
}
275+
276+
bool giveFromISR(BaseType_t& task_woken) {
277+
if (!this->isCreated()) return false;
278+
return xSemaphoreGiveFromISR(this->_handle, &task_woken);
279+
}
234280
};
235281

236282
// Policy for counting semaphore with dynamic memory allocation
@@ -311,21 +357,92 @@ class Lock : public ILock, public Policy {
311357
explicit operator bool() const override { return isCreated(); }
312358
};
313359

360+
// Main SemaphoreLock class with ISR support. You need to specify the policy used
361+
template <typename Policy>
362+
class SemaphoreLock : public ISemaphore, public Policy {
363+
public:
364+
using Policy::Policy;
365+
366+
~SemaphoreLock() {
367+
if (Policy::isCreated()) vSemaphoreDelete(Policy::getHandle());
368+
}
369+
370+
/**
371+
* @brief Get the low-level handle of the semaphore. Useful for direct FreeRTOS API calls. Use it
372+
* with caution.
373+
* @return SemaphoreHandle_t Semaphore handle, nullptr if the semaphore is not created.
374+
*/
375+
SemaphoreHandle_t getHandle() const override { return Policy::getHandle(); }
376+
377+
/**
378+
* @brief Get the name of the semaphore. Useful for debugging and logging purposes.
379+
* @return const char* Name of the semaphore. Default is "RtosLock" if no name is provided.
380+
*/
381+
const char* getName() const override { return Policy::getName(); }
382+
383+
/**
384+
* @brief Check if the semaphore is created.
385+
* @return true Semaphore is created.
386+
*/
387+
bool isCreated() const override { return Policy::isCreated(); }
388+
389+
/**
390+
* @brief Take the semaphore.
391+
* @param ticks_to_wait Maximum time to wait for the operation to complete.
392+
* @return true Semaphore taken successfully, false if the semaphore is not created or failed to
393+
* take.
394+
*/
395+
bool take(const TickType_t ticks_to_wait = portMAX_DELAY) override {
396+
return Policy::take(ticks_to_wait);
397+
}
398+
399+
/**
400+
* @brief Give the semaphore.
401+
* @return true Semaphore given successfully, false if the semaphore is not created or failed to
402+
* give.
403+
*/
404+
bool give() override { return Policy::give(); }
405+
406+
/**
407+
* @brief Give the semaphore from an ISR.
408+
* @param task_woken Higher priority task woken flag. You need to use
409+
* portYIELD_FROM_ISR(task_woken) at the end of the ISR.
410+
* @return true Semaphore given successfully, false if the semaphore is not created or failed to
411+
* give.
412+
*/
413+
bool giveFromISR(BaseType_t& task_woken) override { return Policy::giveFromISR(task_woken); }
414+
415+
/**
416+
* @brief Take the semaphore from an ISR.
417+
* @param task_woken Higher priority task woken flag. You need to use
418+
* portYIELD_FROM_ISR(task_woken) at the end of the ISR.
419+
* @return true Semaphore taken successfully, false if the semaphore is not created or failed to
420+
* take.
421+
*/
422+
bool takeFromISR(BaseType_t& task_woken) override { return Policy::takeFromISR(task_woken); }
423+
424+
/**
425+
* @brief Check if the semaphore is created.
426+
* @return true Semaphore is created.
427+
*/
428+
explicit operator bool() const override { return isCreated(); }
429+
};
430+
314431
} // namespace Internal
315432

316433
using MutexDynamic = Internal::Lock<Internal::MutexDynamicPolicy<>>;
317434
using MutexStatic = Internal::Lock<Internal::MutexStaticPolicy<>>;
318435
using MutexRecursiveDynamic = Internal::Lock<Internal::MutexRecursiveDynamicPolicy<>>;
319436
using MutexRecursiveStatic = Internal::Lock<Internal::MutexRecursiveStaticPolicy<>>;
320-
using SemBinaryDynamic = Internal::Lock<Internal::SemaphoreBinaryDynamicPolicy<>>;
321-
using SemBinaryStatic = Internal::Lock<Internal::SemaphoreBinaryStaticPolicy<>>;
437+
using SemBinaryDynamic = Internal::SemaphoreLock<Internal::SemaphoreBinaryDynamicPolicy<>>;
438+
using SemBinaryStatic = Internal::SemaphoreLock<Internal::SemaphoreBinaryStaticPolicy<>>;
322439

323440
template <uint32_t MaxCount, uint32_t InitialCount = 0>
324441
using SemCountingDynamic =
325-
Internal::Lock<Internal::SemaphoreCountingDynamicPolicy<MaxCount, InitialCount>>;
442+
Internal::SemaphoreLock<Internal::SemaphoreCountingDynamicPolicy<MaxCount, InitialCount>>;
326443

327444
template <uint32_t MaxCount, uint32_t InitialCount = 0>
328445
using SemCountingStatic =
329-
Internal::Lock<Internal::SemaphoreCountingStaticPolicy<MaxCount, InitialCount>>;
446+
Internal::SemaphoreLock<Internal::SemaphoreCountingStaticPolicy<MaxCount, InitialCount>>;
330447

331448
} // namespace RTOS::Locks

src/RTOScppQueue.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,8 @@ class Queue : public IQueue, public Policy {
312312
/**
313313
* @brief Push an item to the front of the queue (LIFO order) from an ISR.
314314
* @param item Item to push.
315-
* @param task_woken Task woken flag. If true, you need to use portYIELD_FROM_ISR() at the end of
316-
* the ISR.
315+
* @param task_woken Higher priority task woken flag. You need to use
316+
* portYIELD_FROM_ISR(task_woken) at the end of the ISR.
317317
* @return true Item pushed successfully, false if the queue is not created or the queue is full.
318318
*/
319319
bool pushFromISR(const T& item, BaseType_t& task_woken) const {
@@ -345,8 +345,8 @@ class Queue : public IQueue, public Policy {
345345
/**
346346
* @brief Add an item to the back of the queue (FIFO order) from an ISR.
347347
* @param item Item to add.
348-
* @param task_woken Task woken flag. If true, you need to use portYIELD_FROM_ISR() at the end of
349-
* the ISR.
348+
* @param task_woken Higher priority task woken flag. You need to use
349+
* portYIELD_FROM_ISR(task_woken) at the end of the ISR.
350350
* @return true Item added successfully, false if the queue is not created or the queue is full.
351351
*/
352352
bool addFromISR(const T& item, BaseType_t& task_woken) const {
@@ -373,8 +373,8 @@ class Queue : public IQueue, public Policy {
373373
/**
374374
* @brief Pop (remove) an item from the queue from an ISR.
375375
* @param var Variable to store the item.
376-
* @param task_woken Task woken flag. If true, you need to use portYIELD_FROM_ISR() at the end of
377-
* the ISR.
376+
* @param task_woken Higher priority task woken flag. You need to use
377+
* portYIELD_FROM_ISR(task_woken) at the end of the ISR.
378378
* @return true Item popped successfully, false if the queue is not created or the queue is empty.
379379
*/
380380
bool popFromISR(T& var, BaseType_t& task_woken) const {
@@ -417,8 +417,8 @@ class Queue : public IQueue, public Policy {
417417
/**
418418
* @brief Overwrite an item in the queue from an ISR. Use it only with queues of length 1.
419419
* @param item Item to overwrite.
420-
* @param task_woken Task woken flag. If true, you need to use portYIELD_FROM_ISR() at the end of
421-
* the ISR.
420+
* @param task_woken Higher priority task woken flag. You need to use
421+
* portYIELD_FROM_ISR(task_woken) at the end of the ISR.
422422
* @return true Item overwritten successfully, false if the queue is not created.
423423
*/
424424
bool overwriteFromISR(const T& item, BaseType_t& task_woken) const {

src/RTOScppRingBuffer.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ class Policy {
9898
* @brief Send an item to the ring buffer from an ISR.
9999
* @param item Item to send.
100100
* @param item_size Size of the item to send.
101-
* @param task_woken Task woken flag. If true, you need to use portYIELD_FROM_ISR() at the end of
102-
* the ISR.
101+
* @param task_woken Higher priority task woken flag. You need to use
102+
* portYIELD_FROM_ISR(task_woken) at the end of the ISR.
103103
* @return true Item sent successfully, false if the ring buffer is not created or failed to send
104104
* the item.
105105
*/
@@ -121,8 +121,8 @@ class Policy {
121121
/**
122122
* @brief Return an item to the ring buffer after using it from an ISR.
123123
* @param item Item to return.
124-
* @param task_woken Task woken flag. If true, you need to use portYIELD_FROM_ISR() at the end of
125-
* the ISR.
124+
* @param task_woken Higher priority task woken flag. You need to use
125+
* portYIELD_FROM_ISR(task_woken) at the end of the ISR.
126126
* @return true Item returned successfully, false if the ring buffer is not created.
127127
*/
128128
bool returnItemFromISR(T* const item, BaseType_t& task_woken) const {

src/RTOScppTask.h

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,8 @@ class ITask {
137137
* @brief Notify the task from an ISR.
138138
* @param value Value to notify.
139139
* @param action Action to take.
140-
* @param task_woken Task woken flag. If true, you need to use portYIELD_FROM_ISR() at the end of
141-
* the ISR.
140+
* @param task_woken Higher priority task woken flag. You need to use
141+
* portYIELD_FROM_ISR(task_woken) at the end of the ISR.
142142
* @return true Notification sent successfully, false if the task is not created or failed to send
143143
* the notification.
144144
*/
@@ -161,8 +161,8 @@ class ITask {
161161
* @param value Value to notify.
162162
* @param action Action to take.
163163
* @param old_value Old value.
164-
* @param task_woken Task woken flag. If true, you need to use portYIELD_FROM_ISR() at the end of
165-
* the ISR.
164+
* @param task_woken Higher priority task woken flag. You need to use
165+
* portYIELD_FROM_ISR(task_woken) at the end of the ISR.
166166
* @return true Notification sent successfully, false if the task is not created or failed to send
167167
* the notification.
168168
*/
@@ -180,8 +180,8 @@ class ITask {
180180
* @brief Notify the task from an ISR. This function acts as a counting semaphore, it will
181181
* increment the notification value by 1. The task can wait for the notification using
182182
* notifyTake().
183-
* @param task_woken Task woken flag. If true, you need to use portYIELD_FROM_ISR() at the end of
184-
* the ISR.
183+
* @param task_woken Higher priority task woken flag. You need to use
184+
* portYIELD_FROM_ISR(task_woken) at the end of the ISR.
185185
* @return true Notification sent successfully, false if the task is not created.
186186
*/
187187
virtual bool notifyGiveFromISR(BaseType_t& task_woken) const = 0;
@@ -528,8 +528,8 @@ class Task : public ITask {
528528
* @brief Notify the task from an ISR.
529529
* @param value Value to notify.
530530
* @param action Action to take.
531-
* @param task_woken Task woken flag. If true, you need to use portYIELD_FROM_ISR() at the end of
532-
* the ISR.
531+
* @param task_woken Higher priority task woken flag. You need to use
532+
* portYIELD_FROM_ISR(task_woken) at the end of the ISR.
533533
* @return true Notification sent successfully, false if the task is not created or failed to send
534534
* the notification.
535535
*/
@@ -558,8 +558,8 @@ class Task : public ITask {
558558
* @param value Value to notify.
559559
* @param action Action to take.
560560
* @param old_value Old value.
561-
* @param task_woken Task woken flag. If true, you need to use portYIELD_FROM_ISR() at the end of
562-
* the ISR.
561+
* @param task_woken Higher priority task woken flag. You need to use
562+
* portYIELD_FROM_ISR(task_woken) at the end of the ISR.
563563
* @return true Notification sent successfully, false if the task is not created or failed to send
564564
* the notification.
565565
*/
@@ -583,8 +583,8 @@ class Task : public ITask {
583583
* @brief Notify the task from an ISR. This function acts as a counting semaphore, it will
584584
* increment the notification value by 1. The task can wait for the notification using
585585
* notifyTake().
586-
* @param task_woken Task woken flag. If true, you need to use portYIELD_FROM_ISR() at the end of
587-
* the ISR.
586+
* @param task_woken Higher priority task woken flag. You need to use
587+
* portYIELD_FROM_ISR(task_woken) at the end of the ISR.
588588
* @return true Notification sent successfully, false if the task is not created.
589589
*/
590590
bool notifyGiveFromISR(BaseType_t& task_woken) const override {

0 commit comments

Comments
 (0)