Skip to main content

osal_rs/freertos/
event_group.rs

1/***************************************************************************
2 *
3 * osal-rs
4 * Copyright (C) 2023/2026 Antonio Salsi <passy.linux@zresa.it>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 *
18 ***************************************************************************/
19
20//! Event group synchronization primitives for FreeRTOS.
21//!
22//! Event groups allow threads to synchronize on multiple events simultaneously.
23//! Each event group contains a set of event bits (flags) that can be set, cleared,
24//! and waited upon. This is useful for complex synchronization scenarios where
25//! multiple conditions must be met.
26
27use core::fmt::{Debug, Display, Formatter};
28use core::ops::Deref;
29use core::ptr::null_mut;
30
31use super::ffi::{EventGroupHandle, pdFAIL, pdFALSE, vEventGroupDelete, xEventGroupClearBits, xEventGroupClearBitsFromISR, xEventGroupCreate, xEventGroupGetBitsFromISR, xEventGroupSetBits, xEventGroupSetBitsFromISR};
32use super::system::System;
33use super::types::{BaseType, EventBits, TickType};
34use crate::traits::{ToTick, EventGroupFn, SystemFn};
35use crate::utils::{Result, Error};
36use crate::xEventGroupGetBits;
37
38/// A set of event flags for thread synchronization.
39///
40/// Event groups contain multiple event bits (typically 24 bits) that can be
41/// manipulated independently. Threads can wait for specific combinations of bits
42/// to be set, making them ideal for complex synchronization scenarios.
43///
44/// # Examples
45///
46/// ## Basic event signaling
47///
48/// ```ignore
49/// use osal_rs::os::{EventGroup, EventGroupFn};
50/// use core::time::Duration;
51/// 
52/// const EVENT_A: u32 = 0b0001;
53/// const EVENT_B: u32 = 0b0010;
54/// const EVENT_C: u32 = 0b0100;
55/// 
56/// let events = EventGroup::new().unwrap();
57/// 
58/// // Set event A
59/// events.set(EVENT_A);
60/// 
61/// // Check if event A is set
62/// let current = events.get();
63/// if current & EVENT_A != 0 {
64///     println!("Event A is set");
65/// }
66/// 
67/// // Clear event A
68/// events.clear(EVENT_A);
69/// ```
70///
71/// ## Waiting for multiple events
72///
73/// ```ignore
74/// use osal_rs::os::{EventGroup, EventGroupFn, Thread};
75/// use alloc::sync::Arc;
76/// use core::time::Duration;
77/// 
78/// const READY: u32 = 0b0001;
79/// const DATA_AVAILABLE: u32 = 0b0010;
80/// const STOP: u32 = 0b0100;
81/// 
82/// let events = Arc::new(EventGroup::new().unwrap());
83/// let events_clone = events.clone();
84/// 
85/// // Worker thread waits for events
86/// let worker = Thread::new("worker", 2048, 5, move || {
87///     loop {
88///         // Wait for either READY or STOP
89///         let bits = events_clone.wait_with_to_tick(
90///             READY | STOP,
91///             Duration::from_secs(1)
92///         );
93///         
94///         if bits & STOP != 0 {
95///             println!("Stopping...");
96///             break;
97///         }
98///         
99///         if bits & READY != 0 {
100///             println!("Ready to work!");
101///         }
102///     }
103/// }).unwrap();
104/// 
105/// worker.start().unwrap();
106/// 
107/// // Signal events
108/// events.set(READY);
109/// Duration::from_secs(2).sleep();
110/// events.set(STOP);
111/// ```
112///
113/// ## State machine synchronization
114///
115/// ```ignore
116/// use osal_rs::os::{EventGroup, EventGroupFn};
117/// use core::time::Duration;
118/// 
119/// const INIT_COMPLETE: u32 = 1 << 0;
120/// const CONFIG_LOADED: u32 = 1 << 1;
121/// const NETWORK_UP: u32 = 1 << 2;
122/// const READY_TO_RUN: u32 = INIT_COMPLETE | CONFIG_LOADED | NETWORK_UP;
123/// 
124/// let state = EventGroup::new().unwrap();
125/// 
126/// // Different subsystems set their bits
127/// state.set(INIT_COMPLETE);
128/// state.set(CONFIG_LOADED);
129/// state.set(NETWORK_UP);
130/// 
131/// // Wait for all systems to be ready
132/// let current = state.wait_with_to_tick(READY_TO_RUN, Duration::from_secs(5));
133/// 
134/// if (current & READY_TO_RUN) == READY_TO_RUN {
135///     println!("All systems ready!");
136/// }
137/// ```
138///
139/// ## ISR to thread signaling
140///
141/// ```ignore
142/// use osal_rs::os::{EventGroup, EventGroupFn, Thread};
143/// use alloc::sync::Arc;
144/// 
145/// const IRQ_EVENT: u32 = 1 << 0;
146/// 
147/// let events = Arc::new(EventGroup::new().unwrap());
148/// let events_isr = events.clone();
149/// 
150/// // In interrupt handler:
151/// // events_isr.set_from_isr(IRQ_EVENT).ok();
152/// 
153/// // Handler thread
154/// let handler = Thread::new("handler", 2048, 5, move || {
155///     loop {
156///         let bits = events.wait(IRQ_EVENT, 1000);
157///         if bits & IRQ_EVENT != 0 {
158///             println!("Handling interrupt event");
159///             events.clear(IRQ_EVENT);
160///         }
161///     }
162/// }).unwrap();
163/// ```
164pub struct EventGroup (EventGroupHandle);
165
166unsafe impl Send for EventGroup {}
167unsafe impl Sync for EventGroup {}
168
169impl EventGroup {
170    pub fn wait_with_to_tick(&self, mask: EventBits, timeout_ticks: impl ToTick) -> EventBits {
171        self.wait(mask, timeout_ticks.to_ticks())
172    }
173}
174
175
176impl EventGroup {
177    /// Creates a new event group.
178    ///
179    /// # Returns
180    ///
181    /// * `Ok(Self)` - Successfully created event group
182    /// * `Err(Error)` - Creation failed (out of memory, etc.)
183    ///
184    /// # Examples
185    ///
186    /// ```ignore
187    /// use osal_rs::os::{EventGroup, EventGroupFn};
188    /// 
189    /// let events = EventGroup::new().unwrap();
190    /// ```
191    pub fn new() -> Result<Self> {
192        let handle = unsafe { xEventGroupCreate() };
193        if handle.is_null() {
194            Err(Error::OutOfMemory)
195        } else {
196            Ok(Self (handle))
197        }
198    }
199
200}
201impl EventGroupFn for EventGroup {
202
203    fn set(&self, bits: EventBits) -> EventBits {
204        unsafe { xEventGroupSetBits(self.0, bits) }
205    }
206
207    fn set_from_isr(&self, bits: EventBits) -> Result<()> {
208
209        let mut higher_priority_task_woken: BaseType = pdFALSE;
210
211        let ret = unsafe { xEventGroupSetBitsFromISR(self.0, bits, &mut higher_priority_task_woken) };
212        if ret != pdFAIL {
213
214            System::yield_from_isr(higher_priority_task_woken);
215            
216            Ok(())
217        } else {
218            Err(Error::QueueFull)
219        }
220    }
221
222    fn get(&self) -> EventBits {
223        xEventGroupGetBits!(self.0) 
224    }
225
226    fn get_from_isr(&self) -> EventBits {
227        unsafe { xEventGroupGetBitsFromISR(self.0) }
228    }
229
230
231    fn clear(&self, bits: EventBits) -> EventBits {
232        unsafe { xEventGroupClearBits(self.0, bits) }
233    }
234
235    fn clear_from_isr(&self, bits: EventBits) -> Result<()> {
236        let ret = unsafe { xEventGroupClearBitsFromISR(self.0, bits) };
237        if ret != pdFAIL {
238            Ok(())
239        } else {
240            Err(Error::QueueFull)
241        }
242    }
243
244    fn wait(&self, mask: EventBits, timeout_ticks: TickType) -> EventBits {
245        unsafe {
246            crate::freertos::ffi::xEventGroupWaitBits(
247                self.0,
248                mask,
249                pdFALSE, 
250                pdFALSE, 
251                timeout_ticks,
252            )
253        }
254    }
255
256    fn delete(&mut self) {
257        unsafe {
258            vEventGroupDelete(self.0);
259            self.0 = null_mut();
260        }
261    }
262}
263
264impl Drop for EventGroup {
265    fn drop(&mut self) {
266        if self.0.is_null() {
267            return;
268        }
269        self.delete();
270    }
271}
272
273impl Deref for EventGroup {
274    type Target = EventGroupHandle;
275
276    fn deref(&self) -> &Self::Target {
277        &self.0
278    }
279}
280
281impl Debug for EventGroup {
282    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
283        write!(f, "EventGroup {{ handle: {:?} }}", self.0)
284    }
285}
286
287impl Display for EventGroup {
288    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
289        write!(f, "EventGroup {{ handle: {:?} }}", self.0)
290    }
291}