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