osal_rs/freertos/queue.rs
1/***************************************************************************
2 *
3 * osal-rs
4 * Copyright (C) 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//! Queue-based inter-thread communication for FreeRTOS.
21//!
22//! This module provides FIFO queue primitives for safe message passing between threads
23//! and interrupt service routines. Supports both byte-based and typed queues.
24
25use core::ffi::c_void;
26use core::fmt::{Debug, Display};
27use core::marker::PhantomData;
28use core::ops::Deref;
29
30use alloc::vec::Vec;
31
32use super::ffi::{QueueHandle, pdFALSE, vQueueDelete, xQueueCreateCountingSemaphore, xQueueReceive, xQueueReceiveFromISR};
33use super::types::{BaseType, UBaseType, TickType};
34use super::system::System;
35use crate::traits::{ToTick, QueueFn, SystemFn, QueueStreamedFn, BytesHasLen};
36#[cfg(not(feature = "serde"))]
37use crate::traits::{Serialize, Deserialize};
38
39#[cfg(feature = "serde")]
40use osal_rs_serde::{Serialize, Deserialize, to_bytes};
41
42pub trait StructSerde : Serialize + BytesHasLen + Deserialize {}
43
44use crate::utils::{Result, Error};
45use crate::{xQueueSendToBack, xQueueSendToBackFromISR};
46
47
48/// A FIFO queue for byte-based message passing.
49///
50/// Provides a thread-safe queue implementation for sending and receiving
51/// raw byte slices between threads. Supports both blocking and ISR-safe operations.
52///
53/// # Examples
54///
55/// ## Basic queue usage
56///
57/// ```ignore
58/// use osal_rs::os::{Queue, QueueFn};
59/// use core::time::Duration;
60///
61/// // Create a queue with 10 slots, each 32 bytes
62/// let queue = Queue::new(10, 32).unwrap();
63///
64/// // Send data
65/// let data = [1u8, 2, 3, 4];
66/// queue.post_with_to_tick(&data, Duration::from_millis(100)).unwrap();
67///
68/// // Receive data
69/// let mut buffer = [0u8; 4];
70/// queue.fetch_with_to_tick(&mut buffer, Duration::from_millis(100)).unwrap();
71/// assert_eq!(buffer, [1, 2, 3, 4]);
72/// ```
73///
74/// ## Producer-consumer pattern
75///
76/// ```ignore
77/// use osal_rs::os::{Queue, QueueFn, Thread};
78/// use alloc::sync::Arc;
79/// use core::time::Duration;
80///
81/// let queue = Arc::new(Queue::new(5, 4).unwrap());
82/// let queue_clone = queue.clone();
83///
84/// // Consumer thread
85/// let consumer = Thread::new("consumer", 2048, 5, move || {
86/// let mut buffer = [0u8; 4];
87/// loop {
88/// if queue_clone.fetch(&mut buffer, 1000).is_ok() {
89/// println!("Received: {:?}", buffer);
90/// }
91/// }
92/// }).unwrap();
93///
94/// consumer.start().unwrap();
95///
96/// // Producer
97/// let data = [0xAA, 0xBB, 0xCC, 0xDD];
98/// queue.post(&data, 1000).unwrap();
99/// ```
100pub struct Queue (QueueHandle);
101
102unsafe impl Send for Queue {}
103unsafe impl Sync for Queue {}
104
105impl Queue {
106 /// Creates a new queue.
107 ///
108 /// # Parameters
109 ///
110 /// * `size` - Maximum number of messages the queue can hold
111 /// * `message_size` - Size in bytes of each message
112 ///
113 /// # Returns
114 ///
115 /// * `Ok(Self)` - Successfully created queue
116 /// * `Err(Error)` - Creation failed (insufficient memory, etc.)
117 ///
118 /// # Examples
119 ///
120 /// ```ignore
121 /// use osal_rs::os::{Queue, QueueFn};
122 ///
123 /// // Queue for 5 messages of 16 bytes each
124 /// let queue = Queue::new(5, 16).unwrap();
125 /// ```
126 pub fn new (size: UBaseType, message_size: UBaseType) -> Result<Self> {
127 let handle = unsafe { xQueueCreateCountingSemaphore(size, message_size) };
128 if handle.is_null() {
129 Err(Error::OutOfMemory)
130 } else {
131 Ok(Self (handle))
132 }
133 }
134
135 /// Receives data from the queue with a convertible timeout.
136 ///
137 /// This is a convenience method that accepts any type implementing `ToTick`
138 /// (like `Duration`) and converts it to ticks before calling `fetch()`.
139 ///
140 /// # Arguments
141 ///
142 /// * `buffer` - Mutable slice to receive data into
143 /// * `time` - Timeout value (e.g., `Duration::from_millis(100)`)
144 ///
145 /// # Returns
146 ///
147 /// * `Ok(())` - Data successfully received
148 /// * `Err(Error::Timeout)` - No data available within timeout
149 ///
150 /// # Examples
151 ///
152 /// ```ignore
153 /// use osal_rs::os::{Queue, QueueFn};
154 /// use core::time::Duration;
155 ///
156 /// let queue = Queue::new(5, 16).unwrap();
157 /// let mut buffer = [0u8; 16];
158 /// queue.fetch_with_to_tick(&mut buffer, Duration::from_millis(100))?;
159 /// ```
160 #[inline]
161 pub fn fetch_with_to_tick(&self, buffer: &mut [u8], time: impl ToTick) -> Result<()> {
162 self.fetch(buffer, time.to_ticks())
163 }
164
165 /// Sends data to the queue with a convertible timeout.
166 ///
167 /// This is a convenience method that accepts any type implementing `ToTick`
168 /// (like `Duration`) and converts it to ticks before calling `post()`.
169 ///
170 /// # Arguments
171 ///
172 /// * `item` - Slice of data to send
173 /// * `time` - Timeout value (e.g., `Duration::from_millis(100)`)
174 ///
175 /// # Returns
176 ///
177 /// * `Ok(())` - Data successfully sent
178 /// * `Err(Error::Timeout)` - Queue full, could not send within timeout
179 ///
180 /// # Examples
181 ///
182 /// ```ignore
183 /// use osal_rs::os::{Queue, QueueFn};
184 /// use core::time::Duration;
185 ///
186 /// let queue = Queue::new(5, 16).unwrap();
187 /// let data = [1u8, 2, 3, 4];
188 /// queue.post_with_to_tick(&data, Duration::from_millis(100))?;
189 /// ```
190 #[inline]
191 pub fn post_with_to_tick(&self, item: &[u8], time: impl ToTick) -> Result<()> {
192 self.post(item, time.to_ticks())
193 }
194}
195
196impl QueueFn for Queue {
197
198 /// Receives data from the queue, blocking until data is available or timeout.
199 ///
200 /// This function blocks the calling thread until data is available or the
201 /// specified timeout expires.
202 ///
203 /// # Arguments
204 ///
205 /// * `buffer` - Mutable byte slice to receive data into
206 /// * `time` - Timeout in system ticks (0 = no wait, MAX = wait forever)
207 ///
208 /// # Returns
209 ///
210 /// * `Ok(())` - Data successfully received into buffer
211 /// * `Err(Error::Timeout)` - No data available within timeout period
212 ///
213 /// # Examples
214 ///
215 /// ```ignore
216 /// use osal_rs::os::{Queue, QueueFn};
217 ///
218 /// let queue = Queue::new(5, 16).unwrap();
219 /// let mut buffer = [0u8; 16];
220 ///
221 /// // Wait up to 1000 ticks for data
222 /// match queue.fetch(&mut buffer, 1000) {
223 /// Ok(()) => println!("Received data: {:?}", buffer),
224 /// Err(_) => println!("Timeout"),
225 /// }
226 /// ```
227 fn fetch(&self, buffer: &mut [u8], time: TickType) -> Result<()> {
228 let ret = unsafe {
229 xQueueReceive(
230 self.0,
231 buffer.as_mut_ptr() as *mut c_void,
232 time,
233 )
234 };
235 if ret == 0 {
236 Err(Error::Timeout)
237 } else {
238 Ok(())
239 }
240 }
241
242 /// Receives data from the queue in an interrupt service routine (ISR).
243 ///
244 /// This is the ISR-safe version of `fetch()`. It does not block and will
245 /// trigger a context switch if a higher priority task is woken.
246 ///
247 /// # Arguments
248 ///
249 /// * `buffer` - Mutable byte slice to receive data into
250 ///
251 /// # Returns
252 ///
253 /// * `Ok(())` - Data successfully received
254 /// * `Err(Error::Timeout)` - Queue is empty
255 ///
256 /// # Safety
257 ///
258 /// Must only be called from ISR context.
259 ///
260 /// # Examples
261 ///
262 /// ```ignore
263 /// // In interrupt handler
264 /// use osal_rs::os::{Queue, QueueFn};
265 ///
266 /// fn irq_handler(queue: &Queue) {
267 /// let mut buffer = [0u8; 16];
268 /// if queue.fetch_from_isr(&mut buffer).is_ok() {
269 /// // Process received data
270 /// }
271 /// }
272 /// ```
273 fn fetch_from_isr(&self, buffer: &mut [u8]) -> Result<()> {
274
275 let mut task_woken_by_receive: BaseType = pdFALSE;
276
277 let ret = unsafe {
278 xQueueReceiveFromISR(
279 self.0,
280 buffer.as_mut_ptr() as *mut c_void,
281 &mut task_woken_by_receive
282 )
283 };
284 if ret == 0 {
285 Err(Error::Timeout)
286 } else {
287
288 System::yield_from_isr(task_woken_by_receive);
289
290 Ok(())
291 }
292 }
293
294 /// Sends data to the back of the queue, blocking until space is available.
295 ///
296 /// This function blocks the calling thread until space becomes available
297 /// or the timeout expires.
298 ///
299 /// # Arguments
300 ///
301 /// * `item` - Byte slice to send
302 /// * `time` - Timeout in system ticks (0 = no wait, MAX = wait forever)
303 ///
304 /// # Returns
305 ///
306 /// * `Ok(())` - Data successfully sent
307 /// * `Err(Error::Timeout)` - Queue full, could not send within timeout
308 ///
309 /// # Examples
310 ///
311 /// ```ignore
312 /// use osal_rs::os::{Queue, QueueFn};
313 ///
314 /// let queue = Queue::new(5, 16).unwrap();
315 /// let data = [0xAA, 0xBB, 0xCC, 0xDD];
316 ///
317 /// // Wait up to 1000 ticks to send
318 /// queue.post(&data, 1000)?;
319 /// ```
320 fn post(&self, item: &[u8], time: TickType) -> Result<()> {
321 let ret = xQueueSendToBack!(
322 self.0,
323 item.as_ptr() as *const c_void,
324 time
325 );
326
327 if ret == 0 {
328 Err(Error::Timeout)
329 } else {
330 Ok(())
331 }
332 }
333
334 /// Sends data to the queue from an interrupt service routine (ISR).
335 ///
336 /// This is the ISR-safe version of `post()`. It does not block and will
337 /// trigger a context switch if a higher priority task is woken.
338 ///
339 /// # Arguments
340 ///
341 /// * `item` - Byte slice to send
342 ///
343 /// # Returns
344 ///
345 /// * `Ok(())` - Data successfully sent
346 /// * `Err(Error::Timeout)` - Queue is full
347 ///
348 /// # Safety
349 ///
350 /// Must only be called from ISR context.
351 ///
352 /// # Examples
353 ///
354 /// ```ignore
355 /// // In interrupt handler
356 /// use osal_rs::os::{Queue, QueueFn};
357 ///
358 /// fn irq_handler(queue: &Queue) {
359 /// let data = [0x01, 0x02, 0x03];
360 /// queue.post_from_isr(&data).ok();
361 /// }
362 /// ```
363 fn post_from_isr(&self, item: &[u8]) -> Result<()> {
364
365 let mut task_woken_by_receive: BaseType = pdFALSE;
366
367 let ret = xQueueSendToBackFromISR!(
368 self.0,
369 item.as_ptr() as *const c_void,
370 &mut task_woken_by_receive
371 );
372
373 if ret == 0 {
374 Err(Error::Timeout)
375 } else {
376 System::yield_from_isr(task_woken_by_receive);
377
378 Ok(())
379 }
380 }
381
382 /// Deletes the queue and frees its resources.
383 ///
384 /// This function destroys the queue and releases any memory allocated for it.
385 /// After calling this, the queue should not be used. The handle is set to null.
386 ///
387 /// # Safety
388 ///
389 /// Ensure no threads are waiting on this queue before deleting it.
390 ///
391 /// # Examples
392 ///
393 /// ```ignore
394 /// use osal_rs::os::{Queue, QueueFn};
395 ///
396 /// let mut queue = Queue::new(5, 16).unwrap();
397 /// // Use the queue...
398 /// queue.delete();
399 /// ```
400 fn delete(&mut self) {
401 unsafe {
402 vQueueDelete(self.0);
403 self.0 = core::ptr::null_mut();
404 }
405 }
406}
407
408/// Automatically deletes the queue when it goes out of scope.
409///
410/// This ensures proper cleanup of FreeRTOS resources.
411impl Drop for Queue {
412 fn drop(&mut self) {
413 if self.0.is_null() {
414 return;
415 }
416 self.delete();
417 }
418}
419
420/// Allows dereferencing to the underlying FreeRTOS queue handle.
421impl Deref for Queue {
422 type Target = QueueHandle;
423
424 fn deref(&self) -> &Self::Target {
425 &self.0
426 }
427}
428
429/// Formats the queue for debugging purposes.
430impl Debug for Queue {
431 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
432 f.debug_struct("Queue")
433 .field("handle", &self.0)
434 .finish()
435 }
436}
437
438/// Formats the queue for display purposes.
439impl Display for Queue {
440 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
441 write!(f, "Queue {{ handle: {:?} }}", self.0)
442 }
443}
444
445/// A type-safe FIFO queue for message passing.
446///
447/// Unlike [`Queue`], which works with raw byte slices, `QueueStreamed` provides
448/// a type-safe interface for sending and receiving structured data. The type must
449/// implement serialization traits.
450///
451/// # Type Parameters
452///
453/// * `T` - The message type. Must implement `ToBytes`, `BytesHasLen`, and `FromBytes`
454///
455/// # Examples
456///
457/// ## Basic typed queue usage
458///
459/// ```ignore
460/// use osal_rs::os::{QueueStreamed, QueueStreamedFn};
461/// use core::time::Duration;
462///
463/// #[derive(Debug, Clone, Copy)]
464/// struct Message {
465/// id: u32,
466/// value: i16,
467/// }
468///
469/// // Assuming Message implements the required traits
470/// let queue: QueueStreamed<Message> = QueueStreamed::new(10, size_of::<Message>()).unwrap();
471///
472/// // Send a message
473/// let msg = Message { id: 1, value: 42 };
474/// queue.post_with_to_tick(&msg, Duration::from_millis(100)).unwrap();
475///
476/// // Receive a message
477/// let mut received = Message { id: 0, value: 0 };
478/// queue.fetch_with_to_tick(&mut received, Duration::from_millis(100)).unwrap();
479/// assert_eq!(received.id, 1);
480/// assert_eq!(received.value, 42);
481/// ```
482///
483/// ## Command queue pattern
484///
485/// ```ignore
486/// use osal_rs::os::{QueueStreamed, Thread};
487/// use alloc::sync::Arc;
488///
489/// enum Command {
490/// Start,
491/// Stop,
492/// SetValue(u32),
493/// }
494///
495/// let cmd_queue = Arc::new(QueueStreamed::<Command>::new(10, 8).unwrap());
496/// let queue_clone = cmd_queue.clone();
497///
498/// let handler = Thread::new("handler", 2048, 5, move || {
499/// loop {
500/// let mut cmd = Command::Stop;
501/// if queue_clone.fetch(&mut cmd, 1000).is_ok() {
502/// match cmd {
503/// Command::Start => { /* start operation */ },
504/// Command::Stop => { /* stop operation */ },
505/// Command::SetValue(val) => { /* set value */ },
506/// }
507/// }
508/// }
509/// }).unwrap();
510/// ```
511pub struct QueueStreamed<T: StructSerde> (Queue, PhantomData<T>);
512
513unsafe impl<T: StructSerde> Send for QueueStreamed<T> {}
514unsafe impl<T: StructSerde> Sync for QueueStreamed<T> {}
515
516impl<T> QueueStreamed<T>
517where
518 T: StructSerde {
519 /// Creates a new type-safe queue.
520 ///
521 /// # Parameters
522 ///
523 /// * `size` - Maximum number of messages
524 /// * `message_size` - Size of each message (typically `size_of::<T>()`)
525 ///
526 /// # Returns
527 ///
528 /// * `Ok(Self)` - Successfully created queue
529 /// * `Err(Error)` - Creation failed
530 #[inline]
531 pub fn new (size: UBaseType, message_size: UBaseType) -> Result<Self> {
532 Ok(Self (Queue::new(size, message_size)?, PhantomData))
533 }
534
535 /// Receives a typed message with a convertible timeout.
536 ///
537 /// This is a convenience method that accepts any type implementing `ToTick`.
538 ///
539 /// # Arguments
540 ///
541 /// * `buffer` - Mutable reference to receive the message into
542 /// * `time` - Timeout value (e.g., `Duration::from_millis(100)`)
543 ///
544 /// # Returns
545 ///
546 /// * `Ok(())` - Message successfully received and deserialized
547 /// * `Err(Error)` - Timeout or deserialization error
548 ///
549 /// # Examples
550 ///
551 /// ```ignore
552 /// use osal_rs::os::QueueStreamed;
553 /// use core::time::Duration;
554 ///
555 /// let queue: QueueStreamed<MyMessage> = QueueStreamed::new(5, size_of::<MyMessage>()).unwrap();
556 /// let mut msg = MyMessage::default();
557 /// queue.fetch_with_to_tick(&mut msg, Duration::from_millis(100))?;
558 /// ```
559 #[inline]
560 fn fetch_with_to_tick(&self, buffer: &mut T, time: impl ToTick) -> Result<()> {
561 self.fetch(buffer, time.to_ticks())
562 }
563
564 /// Sends a typed message with a convertible timeout.
565 ///
566 /// This is a convenience method that accepts any type implementing `ToTick`.
567 ///
568 /// # Arguments
569 ///
570 /// * `item` - Reference to the message to send
571 /// * `time` - Timeout value (e.g., `Duration::from_millis(100)`)
572 ///
573 /// # Returns
574 ///
575 /// * `Ok(())` - Message successfully serialized and sent
576 /// * `Err(Error)` - Timeout or serialization error
577 ///
578 /// # Examples
579 ///
580 /// ```ignore
581 /// use osal_rs::os::QueueStreamed;
582 /// use core::time::Duration;
583 ///
584 /// let queue: QueueStreamed<MyMessage> = QueueStreamed::new(5, size_of::<MyMessage>()).unwrap();
585 /// let msg = MyMessage { id: 1, value: 42 };
586 /// queue.post_with_to_tick(&msg, Duration::from_millis(100))?;
587 /// ```
588 #[inline]
589 fn post_with_to_tick(&self, item: &T, time: impl ToTick) -> Result<()> {
590 self.post(item, time.to_ticks())
591 }
592}
593
594#[cfg(not(feature = "serde"))]
595impl<T> QueueStreamedFn<T> for QueueStreamed<T>
596where
597 T: StructSerde {
598
599 /// Receives a typed message from the queue (without serde feature).
600 ///
601 /// Deserializes the message from bytes using the custom serialization traits.
602 ///
603 /// # Arguments
604 ///
605 /// * `buffer` - Mutable reference to receive the deserialized message
606 /// * `time` - Timeout in system ticks
607 ///
608 /// # Returns
609 ///
610 /// * `Ok(())` - Message successfully received and deserialized
611 /// * `Err(Error::Timeout)` - Queue empty or timeout
612 /// * `Err(Error)` - Deserialization error
613 fn fetch(&self, buffer: &mut T, time: TickType) -> Result<()> {
614 let mut buf_bytes = Vec::with_capacity(buffer.len());
615
616 if let Ok(()) = self.0.fetch(&mut buf_bytes, time) {
617 *buffer = T::from_bytes(&buf_bytes)?;
618 Ok(())
619 } else {
620 Err(Error::Timeout)
621 }
622 }
623
624 /// Receives a typed message from ISR context (without serde feature).
625 ///
626 /// ISR-safe version that does not block. Deserializes the message from bytes.
627 ///
628 /// # Arguments
629 ///
630 /// * `buffer` - Mutable reference to receive the deserialized message
631 ///
632 /// # Returns
633 ///
634 /// * `Ok(())` - Message successfully received and deserialized
635 /// * `Err(Error::Timeout)` - Queue is empty
636 /// * `Err(Error)` - Deserialization error
637 ///
638 /// # Safety
639 ///
640 /// Must only be called from ISR context.
641 fn fetch_from_isr(&self, buffer: &mut T) -> Result<()> {
642 let mut buf_bytes = Vec::with_capacity(buffer.len());
643
644 if let Ok(()) = self.0.fetch_from_isr(&mut buf_bytes) {
645 *buffer = T::from_bytes(&buf_bytes)?;
646 Ok(())
647 } else {
648 Err(Error::Timeout)
649 }
650 }
651
652 /// Sends a typed message to the queue (without serde feature).
653 ///
654 /// Serializes the message to bytes using the custom serialization traits.
655 ///
656 /// # Arguments
657 ///
658 /// * `item` - Reference to the message to send
659 /// * `time` - Timeout in system ticks
660 ///
661 /// # Returns
662 ///
663 /// * `Ok(())` - Message successfully serialized and sent
664 /// * `Err(Error::Timeout)` - Queue full
665 /// * `Err(Error)` - Serialization error
666 #[inline]
667 fn post(&self, item: &T, time: TickType) -> Result<()> {
668 self.0.post(&item.to_bytes(), time)
669 }
670
671 /// Sends a typed message from ISR context (without serde feature).
672 ///
673 /// ISR-safe version that does not block. Serializes the message to bytes.
674 ///
675 /// # Arguments
676 ///
677 /// * `item` - Reference to the message to send
678 ///
679 /// # Returns
680 ///
681 /// * `Ok(())` - Message successfully serialized and sent
682 /// * `Err(Error::Timeout)` - Queue is full
683 /// * `Err(Error)` - Serialization error
684 ///
685 /// # Safety
686 ///
687 /// Must only be called from ISR context.
688 #[inline]
689 fn post_from_isr(&self, item: &T) -> Result<()> {
690 self.0.post_from_isr(&item.to_bytes())
691 }
692
693 /// Deletes the typed queue.
694 ///
695 /// Delegates to the underlying byte queue's delete method.
696 #[inline]
697 fn delete(&mut self) {
698 self.0.delete()
699 }
700}
701
702#[cfg(feature = "serde")]
703impl<T> QueueStreamedFn<T> for QueueStreamed<T>
704where
705 T: StructSerde {
706
707 /// Receives a typed message from the queue (with serde feature).
708 ///
709 /// Deserializes the message from bytes using the serde framework.
710 ///
711 /// # Arguments
712 ///
713 /// * `buffer` - Mutable reference to receive the deserialized message
714 /// * `time` - Timeout in system ticks
715 ///
716 /// # Returns
717 ///
718 /// * `Ok(())` - Message successfully received and deserialized
719 /// * `Err(Error::Timeout)` - Queue empty or timeout
720 /// * `Err(Error::Unhandled)` - Deserialization error
721 fn fetch(&self, buffer: &mut T, time: TickType) -> Result<()> {
722 let mut buf_bytes = Vec::with_capacity(buffer.len());
723
724 if let Ok(()) = self.0.fetch(&mut buf_bytes, time) {
725
726 to_bytes(buffer, &mut buf_bytes).map_err(|_| Error::Unhandled("Deserializiation error"))?;
727
728 Ok(())
729 } else {
730 Err(Error::Timeout)
731 }
732 }
733
734 /// Receives a typed message from ISR context (with serde feature).
735 ///
736 /// ISR-safe version that does not block. Deserializes using serde.
737 ///
738 /// # Arguments
739 ///
740 /// * `buffer` - Mutable reference to receive the deserialized message
741 ///
742 /// # Returns
743 ///
744 /// * `Ok(())` - Message successfully received and deserialized
745 /// * `Err(Error::Timeout)` - Queue is empty
746 /// * `Err(Error::Unhandled)` - Deserialization error
747 ///
748 /// # Safety
749 ///
750 /// Must only be called from ISR context.
751 fn fetch_from_isr(&self, buffer: &mut T) -> Result<()> {
752 let mut buf_bytes = Vec::with_capacity(buffer.len());
753
754 if let Ok(()) = self.0.fetch_from_isr(&mut buf_bytes) {
755 to_bytes(buffer, &mut buf_bytes).map_err(|_| Error::Unhandled("Deserializiation error"))?;
756 Ok(())
757 } else {
758 Err(Error::Timeout)
759 }
760 }
761
762 /// Sends a typed message to the queue (with serde feature).
763 ///
764 /// Serializes the message to bytes using the serde framework.
765 ///
766 /// # Arguments
767 ///
768 /// * `item` - Reference to the message to send
769 /// * `time` - Timeout in system ticks
770 ///
771 /// # Returns
772 ///
773 /// * `Ok(())` - Message successfully serialized and sent
774 /// * `Err(Error::Timeout)` - Queue full
775 /// * `Err(Error::Unhandled)` - Serialization error
776 fn post(&self, item: &T, time: TickType) -> Result<()> {
777
778
779 let mut buf_bytes = Vec::with_capacity(item.len());
780
781 to_bytes(item, &mut buf_bytes).map_err(|_| Error::Unhandled("Deserializiation error"))?;
782
783 self.0.post(&buf_bytes, time)
784 }
785
786 /// Sends a typed message from ISR context (with serde feature).
787 ///
788 /// ISR-safe version that does not block. Serializes using serde.
789 ///
790 /// # Arguments
791 ///
792 /// * `item` - Reference to the message to send
793 ///
794 /// # Returns
795 ///
796 /// * `Ok(())` - Message successfully serialized and sent
797 /// * `Err(Error::Timeout)` - Queue is full
798 /// * `Err(Error::Unhandled)` - Serialization error
799 ///
800 /// # Safety
801 ///
802 /// Must only be called from ISR context.
803 fn post_from_isr(&self, item: &T) -> Result<()> {
804
805 let mut buf_bytes = Vec::with_capacity(item.len());
806
807 to_bytes(item, &mut buf_bytes).map_err(|_| Error::Unhandled("Deserializiation error"))?;
808
809 self.0.post_from_isr(&buf_bytes)
810 }
811
812 /// Deletes the typed queue (serde version).
813 ///
814 /// Delegates to the underlying byte queue's delete method.
815 #[inline]
816 fn delete(&mut self) {
817 self.0.delete()
818 }
819}
820
821/// Allows dereferencing to the underlying FreeRTOS queue handle.
822impl<T> Deref for QueueStreamed<T>
823where
824 T: StructSerde {
825 type Target = QueueHandle;
826
827 fn deref(&self) -> &Self::Target {
828 &self.0.0
829 }
830}
831
832/// Formats the typed queue for debugging purposes.
833impl<T> Debug for QueueStreamed<T>
834where
835 T: StructSerde {
836 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
837 f.debug_struct("QueueStreamed")
838 .field("handle", &self.0.0)
839 .finish()
840 }
841}
842
843/// Formats the typed queue for display purposes.
844impl<T> Display for QueueStreamed<T>
845where
846 T: StructSerde {
847 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
848 write!(f, "QueueStreamed {{ handle: {:?} }}", self.0.0)
849 }
850}
851