@@ -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+
7398namespace 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
316433using MutexDynamic = Internal::Lock<Internal::MutexDynamicPolicy<>>;
317434using MutexStatic = Internal::Lock<Internal::MutexStaticPolicy<>>;
318435using MutexRecursiveDynamic = Internal::Lock<Internal::MutexRecursiveDynamicPolicy<>>;
319436using 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
323440template <uint32_t MaxCount, uint32_t InitialCount = 0 >
324441using SemCountingDynamic =
325- Internal::Lock <Internal::SemaphoreCountingDynamicPolicy<MaxCount, InitialCount>>;
442+ Internal::SemaphoreLock <Internal::SemaphoreCountingDynamicPolicy<MaxCount, InitialCount>>;
326443
327444template <uint32_t MaxCount, uint32_t InitialCount = 0 >
328445using SemCountingStatic =
329- Internal::Lock <Internal::SemaphoreCountingStaticPolicy<MaxCount, InitialCount>>;
446+ Internal::SemaphoreLock <Internal::SemaphoreCountingStaticPolicy<MaxCount, InitialCount>>;
330447
331448} // namespace RTOS::Locks
0 commit comments