Skip to main content

ove/
eventgroup.rs

1// Copyright (C) 2026 Kamil Lulko <kamil.lulko@gmail.com>
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4//
5// This file is part of oveRTOS.
6
7//! Event group (bitfield synchronization) for oveRTOS.
8//!
9//! An [`EventGroup`] holds a set of bits that any thread or ISR can set or clear.
10//! Other threads can block until specific bit patterns appear, enabling fine-grained
11//! inter-task signalling without dedicated queues.
12
13use core::cell::UnsafeCell;
14use core::mem::MaybeUninit;
15
16use crate::bindings;
17use crate::error::{Error, Result};
18
19// SAFETY (module-wide contract for the `unsafe { bindings::ove_*(...) }` FFI
20// calls below): any handle passed to the C API is non-null and refers to a
21// live RTOS object — wrapper constructors establish validity via
22// `Error::from_code`, and `Drop` (or an explicit `deinit`) is the only place
23// a handle is released. Pointer and slice arguments reference caller-owned
24// memory valid for the duration of the call; the C side copies whatever it
25// retains and does not alias them past return (verified against the
26// signatures in `include/ove/*.h`). Blocks that deviate — `transmute`, raw
27// pointer casts from user data, slice reconstruction via `from_raw_parts`,
28// or storing a callback across the FFI boundary — carry their own
29// `// SAFETY:` comment.
30
31/// Flags controlling [`EventGroup::wait_bits`] behavior.
32///
33/// Flags can be combined with the `|` operator.
34#[derive(Clone, Copy, Debug, Default)]
35pub struct WaitFlags(u32);
36
37impl WaitFlags {
38    /// No flags — wait for any bit, don't clear on exit.
39    pub const NONE: Self = Self(0);
40    /// Wait for ALL specified bits (vs any).
41    pub const WAIT_ALL: Self = Self(0x01);
42    /// Clear matched bits on successful wait.
43    pub const CLEAR_ON_EXIT: Self = Self(0x02);
44}
45
46impl core::ops::BitOr for WaitFlags {
47    type Output = Self;
48    fn bitor(self, rhs: Self) -> Self {
49        Self(self.0 | rhs.0)
50    }
51}
52
53/// Deprecated alias for [`WaitFlags::WAIT_ALL`].
54#[deprecated(note = "use WaitFlags::WAIT_ALL instead")]
55pub const EG_WAIT_ALL: WaitFlags = WaitFlags::WAIT_ALL;
56/// Deprecated alias for [`WaitFlags::CLEAR_ON_EXIT`].
57#[deprecated(note = "use WaitFlags::CLEAR_ON_EXIT instead")]
58pub const EG_CLEAR_ON_EXIT: WaitFlags = WaitFlags::CLEAR_ON_EXIT;
59
60/// Caller-owned storage for an [`EventGroup`] in zero-heap mode (see
61/// [`crate::MutexStorage`]).
62#[allow(dead_code)]
63pub struct EventGroupStorage {
64    storage: UnsafeCell<MaybeUninit<bindings::ove_eventgroup_storage_t>>,
65}
66
67impl EventGroupStorage {
68    /// Zero-initialised storage.  `const` so it can initialise a `static`.
69    #[inline]
70    pub const fn new() -> Self {
71        Self {
72            storage: UnsafeCell::new(MaybeUninit::zeroed()),
73        }
74    }
75}
76
77impl Default for EventGroupStorage {
78    fn default() -> Self {
79        Self::new()
80    }
81}
82
83// SAFETY: see crate::MutexStorage.
84unsafe impl Sync for EventGroupStorage {}
85
86/// Event group — a set of named bits that can be set, cleared, and waited on.
87pub struct EventGroup {
88    handle: bindings::ove_eventgroup_t,
89}
90
91impl EventGroup {
92    /// Create a new event group via heap allocation (only in heap mode).
93    #[cfg(not(zero_heap))]
94    pub fn new() -> Result<Self> {
95        let mut handle: bindings::ove_eventgroup_t = core::ptr::null_mut();
96        let rc = unsafe { bindings::ove_eventgroup_create(&mut handle) };
97        Error::from_code(rc)?;
98        Ok(Self { handle })
99    }
100
101    /// Create from caller-provided static storage.
102    ///
103    /// # Safety
104    /// Caller must ensure `storage` outlives the `EventGroup`.
105    #[cfg(zero_heap)]
106    pub unsafe fn from_static(storage: *mut bindings::ove_eventgroup_storage_t) -> Result<Self> {
107        let mut handle: bindings::ove_eventgroup_t = core::ptr::null_mut();
108        let rc = unsafe { bindings::ove_eventgroup_init(&mut handle, storage) };
109        Error::from_code(rc)?;
110        Ok(Self { handle })
111    }
112
113    /// Mode-agnostic constructor (see [`crate::Mutex::create`]).
114    pub fn create(storage: &'static EventGroupStorage) -> Result<Self> {
115        #[cfg(not(zero_heap))]
116        {
117            let _ = storage;
118            Self::new()
119        }
120        #[cfg(zero_heap)]
121        {
122            let ptr = UnsafeCell::raw_get(&storage.storage).cast();
123            unsafe { Self::from_static(ptr) }
124        }
125    }
126
127    /// Set bits in the event group. Returns the bits value after setting.
128    #[inline]
129    pub fn set_bits(&self, bits: u32) -> u32 {
130        unsafe { bindings::ove_eventgroup_set_bits(self.handle, bits) }
131    }
132
133    /// Clear bits in the event group. Returns the bits value before clearing.
134    #[inline]
135    pub fn clear_bits(&self, bits: u32) -> u32 {
136        unsafe { bindings::ove_eventgroup_clear_bits(self.handle, bits) }
137    }
138
139    /// Wait indefinitely for the specified bits to be set.  Returns
140    /// the bits value at the moment the wait condition was satisfied.
141    ///
142    /// `flags` is a combination of [`WaitFlags::WAIT_ALL`] and
143    /// [`WaitFlags::CLEAR_ON_EXIT`].
144    #[inline]
145    pub fn wait_bits(&self, bits: u32, flags: WaitFlags) -> Result<u32> {
146        self.wait_bits_with_timeout(bits, flags, u64::MAX)
147    }
148
149    /// Non-blocking check for the specified bits.
150    ///
151    /// # Errors
152    /// Returns [`Error::Timeout`] if the bits are not currently set.
153    #[inline]
154    pub fn try_wait_bits(&self, bits: u32, flags: WaitFlags) -> Result<u32> {
155        self.wait_bits_with_timeout(bits, flags, 0)
156    }
157
158    /// Wait up to `d` for the specified bits.
159    #[inline]
160    pub fn wait_bits_for(
161        &self,
162        bits: u32,
163        flags: WaitFlags,
164        d: core::time::Duration,
165    ) -> Result<u32> {
166        self.wait_bits_with_timeout(bits, flags, crate::time::dur_to_ns(d))
167    }
168
169    /// Wait by the given deadline.  Use
170    /// [`Instant::FOREVER`](crate::time::Instant::FOREVER) for an
171    /// indefinite wait.
172    #[inline]
173    pub fn wait_bits_until(
174        &self,
175        bits: u32,
176        flags: WaitFlags,
177        deadline: crate::time::Instant,
178    ) -> Result<u32> {
179        self.wait_bits_with_timeout(bits, flags, crate::time::deadline_to_timeout_ns(deadline))
180    }
181
182    #[inline]
183    fn wait_bits_with_timeout(&self, bits: u32, flags: WaitFlags, timeout_ns: u64) -> Result<u32> {
184        let mut result: u32 = 0;
185        let rc = unsafe {
186            bindings::ove_eventgroup_wait_bits(self.handle, bits, flags.0, timeout_ns, &mut result)
187        };
188        Error::from_code(rc)?;
189        Ok(result)
190    }
191
192    /// Set bits from an ISR context. Returns the bits value after setting.
193    #[inline]
194    pub fn set_bits_from_isr(&self, bits: u32) -> u32 {
195        unsafe { bindings::ove_eventgroup_set_bits_from_isr(self.handle, bits) }
196    }
197
198    /// Get current bits value.
199    #[inline]
200    pub fn get_bits(&self) -> u32 {
201        unsafe { bindings::ove_eventgroup_get_bits(self.handle) }
202    }
203
204    /// Register a notify callback fired after every successful set_bits.
205    /// Wraps the C-level `ove_eventgroup_set_notify`.
206    ///
207    /// # Safety
208    /// Same as [`crate::Stream::set_notify`]: `user_data` must remain
209    /// valid for as long as the callback may fire, and `cb` must be
210    /// ISR-safe (the C-side invokes it from whatever context the set
211    /// ran in, thread or ISR).
212    #[cfg(has_async)]
213    #[inline]
214    pub unsafe fn set_notify(
215        &self,
216        cb: Option<unsafe extern "C" fn(*mut core::ffi::c_void)>,
217        user_data: *mut core::ffi::c_void,
218    ) -> Result<()> {
219        let rc = unsafe { bindings::ove_eventgroup_set_notify(self.handle, cb, user_data) };
220        Error::from_code(rc)
221    }
222}
223
224crate::ove_handle_impl!(EventGroup, ove_eventgroup_destroy, ove_eventgroup_deinit);