#ifndef FREERTOS_CPP_SYNCHRONIZATION_HPP #define FREERTOS_CPP_SYNCHRONIZATION_HPP #include #include extern "C" { #include "FreeRTOS.h" #include "semphr.h" #include "task.h" } namespace freertos { struct StaticSemaphoreStorage final { StaticSemaphore_t control {}; }; class BinarySemaphore final { public: explicit BinarySemaphore( StaticSemaphoreStorage & storage ) noexcept : handle_ { xSemaphoreCreateBinaryStatic( &storage.control ) } { } ~BinarySemaphore() noexcept { if( handle_ != nullptr ) vSemaphoreDelete( handle_ ); } BinarySemaphore( const BinarySemaphore & ) = delete; BinarySemaphore & operator=( const BinarySemaphore & ) = delete; BinarySemaphore( BinarySemaphore && ) = delete; BinarySemaphore & operator=( BinarySemaphore && ) = delete; [[nodiscard]] bool valid() const noexcept { return handle_ != nullptr; } [[nodiscard]] bool give() noexcept { return handle_ != nullptr && xSemaphoreGive( handle_ ) == pdPASS; } [[nodiscard]] bool take( TickType_t timeout ) noexcept { return handle_ != nullptr && xSemaphoreTake( handle_, timeout ) == pdPASS; } [[nodiscard]] UBaseType_t count() const noexcept { return handle_ == nullptr ? 0U : uxSemaphoreGetCount( handle_ ); } [[nodiscard]] SemaphoreHandle_t native_handle() const noexcept { return handle_; } private: SemaphoreHandle_t handle_ {}; }; template< UBaseType_t Maximum > class CountingSemaphore final { static_assert( Maximum > 0U, "CountingSemaphore maximum must be positive" ); public: CountingSemaphore( StaticSemaphoreStorage & storage, UBaseType_t initial ) noexcept : handle_ { initial <= Maximum ? xSemaphoreCreateCountingStatic( Maximum, initial, &storage.control ) : nullptr } { } ~CountingSemaphore() noexcept { if( handle_ != nullptr ) vSemaphoreDelete( handle_ ); } CountingSemaphore( const CountingSemaphore & ) = delete; CountingSemaphore & operator=( const CountingSemaphore & ) = delete; CountingSemaphore( CountingSemaphore && ) = delete; CountingSemaphore & operator=( CountingSemaphore && ) = delete; [[nodiscard]] bool valid() const noexcept { return handle_ != nullptr; } [[nodiscard]] bool give() noexcept { return handle_ != nullptr && xSemaphoreGive( handle_ ) == pdPASS; } [[nodiscard]] bool take( TickType_t timeout ) noexcept { return handle_ != nullptr && xSemaphoreTake( handle_, timeout ) == pdPASS; } [[nodiscard]] UBaseType_t count() const noexcept { return handle_ == nullptr ? 0U : uxSemaphoreGetCount( handle_ ); } static constexpr UBaseType_t maximum() noexcept { return Maximum; } [[nodiscard]] SemaphoreHandle_t native_handle() const noexcept { return handle_; } private: SemaphoreHandle_t handle_ {}; }; enum class NotificationAction : uint8_t { no_action, set_bits, increment, overwrite, without_overwrite }; class TaskNotification final { public: explicit constexpr TaskNotification( TaskHandle_t target ) noexcept : target_ { target } { } [[nodiscard]] bool valid() const noexcept { return target_ != nullptr; } [[nodiscard]] bool give() const noexcept { return target_ != nullptr && xTaskNotifyGive( target_ ) == pdPASS; } [[nodiscard]] bool notify( uint32_t value, NotificationAction action ) const noexcept { return target_ != nullptr && xTaskNotify( target_, value, raw_action( action ) ) == pdPASS; } [[nodiscard]] static uint32_t take( bool clear_on_exit, TickType_t timeout ) noexcept { return ulTaskNotifyTake( clear_on_exit ? pdTRUE : pdFALSE, timeout ); } [[nodiscard]] static bool wait_value( uint32_t & value, TickType_t timeout, uint32_t clear_on_entry = 0U, uint32_t clear_on_exit = UINT32_MAX ) noexcept { return xTaskNotifyWait( clear_on_entry, clear_on_exit, &value, timeout ) == pdPASS; } [[nodiscard]] TaskHandle_t target() const noexcept { return target_; } private: static eNotifyAction raw_action( NotificationAction action ) noexcept { switch( action ) { case NotificationAction::no_action: return eNoAction; case NotificationAction::set_bits: return eSetBits; case NotificationAction::increment: return eIncrement; case NotificationAction::overwrite: return eSetValueWithOverwrite; case NotificationAction::without_overwrite: return eSetValueWithoutOverwrite; } return eNoAction; } TaskHandle_t target_ {}; }; static_assert( !std::is_copy_constructible< BinarySemaphore >::value ); static_assert( !std::is_move_constructible< CountingSemaphore< 2U > >::value ); static_assert( std::is_trivially_copyable< TaskNotification >::value ); } // namespace freertos #endif