freertos_rust/
queue.rs

1use mem::ManuallyDrop;
2use mem::MaybeUninit;
3
4use crate::base::*;
5use crate::isr::*;
6use crate::prelude::v1::*;
7use crate::shim::*;
8use crate::units::*;
9
10unsafe impl<T: Sized + Send> Send for Queue<T> {}
11unsafe impl<T: Sized + Send> Sync for Queue<T> {}
12
13#[derive(Debug)]
14pub struct SendError<T> {
15    err: FreeRtosError,
16    item: T,
17}
18
19impl<T> SendError<T> {
20    pub fn error(&self) -> FreeRtosError {
21        self.err
22    }
23
24    pub fn into_item(self) -> T {
25        self.item
26    }
27}
28
29/// A queue with a finite size.
30#[derive(Debug)]
31pub struct Queue<T: Sized + Send> {
32    queue: FreeRtosQueueHandle,
33    item_type: PhantomData<T>,
34}
35
36impl<T: Sized + Send> Queue<T> {
37    pub fn new(max_size: usize) -> Result<Queue<T>, FreeRtosError> {
38        let item_size = mem::size_of::<T>();
39
40        let handle = unsafe { freertos_rs_queue_create(max_size as u32, item_size as u32) };
41
42        if handle == 0 as *const _ {
43            return Err(FreeRtosError::OutOfMemory);
44        }
45
46        Ok(Queue {
47            queue: handle,
48            item_type: PhantomData,
49        })
50    }
51
52    /// # Safety
53    ///
54    /// `handle` must be a valid FreeRTOS regular queue handle (not semaphore or mutex).
55    ///
56    /// The item size of the queue must match the size of `T`.
57    #[inline]
58    pub unsafe fn from_raw_handle(handle: FreeRtosQueueHandle) -> Self {
59        Self {
60            queue: handle,
61            item_type: PhantomData,
62        }
63    }
64    #[inline]
65    pub fn raw_handle(&self) -> FreeRtosQueueHandle {
66        self.queue
67    }
68
69    /// Send an item to the end of the queue. Wait for the queue to have empty space for it.
70    pub fn send<D: DurationTicks>(&self, item: T, max_wait: D) -> Result<(), SendError<T>> {
71        let item = ManuallyDrop::new(item);
72        let ptr = &item as *const _ as FreeRtosVoidPtr;
73
74        unsafe {
75            if freertos_rs_queue_send(self.queue, ptr, max_wait.to_ticks()) != 0 {
76                Err(SendError {
77                    err: FreeRtosError::QueueSendTimeout,
78                    item: ManuallyDrop::into_inner(item),
79                })
80            } else {
81                Ok(())
82            }
83        }
84    }
85
86    /// Send an item to the end of the queue, from an interrupt.
87    pub fn send_from_isr(
88        &self,
89        context: &mut InterruptContext,
90        item: T,
91    ) -> Result<(), SendError<T>> {
92        let item = ManuallyDrop::new(item);
93        let ptr = &item as *const _ as FreeRtosVoidPtr;
94
95        unsafe {
96            if freertos_rs_queue_send_isr(self.queue, ptr, context.get_task_field_mut()) != 0 {
97                Err(SendError {
98                    err: FreeRtosError::QueueFull,
99                    item: ManuallyDrop::into_inner(item),
100                })
101            } else {
102                Ok(())
103            }
104        }
105    }
106
107    /// Wait for an item to be available on the queue.
108    pub fn receive<D: DurationTicks>(&self, max_wait: D) -> Result<T, FreeRtosError> {
109        unsafe {
110            // Use `MaybeUninit` to avoid calling drop on
111            // uninitialized struct in case of timeout
112            let mut buff = MaybeUninit::uninit();
113            let r = freertos_rs_queue_receive(
114                self.queue,
115                &mut buff as *mut _ as FreeRtosMutVoidPtr,
116                max_wait.to_ticks(),
117            );
118            if r == 0 {
119                return Ok(buff.assume_init());
120            } else {
121                return Err(FreeRtosError::QueueReceiveTimeout);
122            }
123        }
124    }
125
126    /// Get the number of messages in the queue.
127    pub fn len(&self) -> u32 {
128        unsafe { freertos_rs_queue_messages_waiting(self.queue) }
129    }
130}
131
132impl<T: Sized + Send> Drop for Queue<T> {
133    fn drop(&mut self) {
134        unsafe {
135            freertos_rs_queue_delete(self.queue);
136        }
137    }
138}