canadensis_can/queue/
queue_only_driver.rs

1//! A driver that contains frame queues only, and requires external code to actually send and
2//! receive messages
3
4use crate::driver::{ReceiveDriver, TransmitDriver};
5use crate::queue::{ArrayQueue, FrameQueue};
6use crate::types::CanNodeId;
7use crate::Frame;
8use alloc::vec::Vec;
9use canadensis_core::subscription::Subscription;
10use canadensis_core::time::Clock;
11use canadensis_core::{nb, OutOfMemoryError};
12use core::convert::Infallible;
13use fallible_collections::FallibleVec;
14use heapless::Deque;
15
16/// A driver that contains frame queues only, and requires external code to actually send and
17/// receive messages
18///
19/// This may be useful on embedded devices that do not have a hardware-managed queue of incoming
20/// frames. A high-priority interrupt handler can read frames from the CAN peripheral into another
21/// queue, and then pass them to this driver when there are no incoming frames waiting.
22///
23/// To transmit frames, this driver stores an [`ArrayQueue`](ArrayQueue) that lets external code
24/// remove frames and send them to a CAN peripheral.
25///
26/// Type parameters:
27/// * `TC`: The transmit queue capacity, in frames
28/// * `RC`: The receive queue capacity, in frames
29///
30/// ## Filters
31///
32/// When a driver calls `apply_filters()`, this struct stores a `Vec` of the current subscriptions.
33/// External code should get these subscriptions using the `subscriptions()` function and manually
34/// send them to the CAN driver.
35///
36pub struct QueueOnlyDriver<const TC: usize, const RC: usize> {
37    tx_queue: ArrayQueue<TC>,
38    rx_queue: Deque<Frame, RC>,
39    subscriptions: Option<Vec<Subscription>>,
40}
41
42impl<const TC: usize, const RC: usize> QueueOnlyDriver<TC, RC> {
43    /// Creates a driver
44    pub fn new() -> Self {
45        Default::default()
46    }
47
48    /// Pushes a received frame onto the back of the receive queue
49    ///
50    /// The frame can be retrieved using the `receive()` function.
51    pub fn push_rx_frame(&mut self, frame: Frame) -> Result<(), OutOfMemoryError> {
52        self.rx_queue.push_back(frame).map_err(|_| OutOfMemoryError)
53    }
54
55    /// Removes and returns a frame from the front of the transmit queue
56    pub fn pop_tx_frame(&mut self) -> Option<Frame> {
57        self.tx_queue.pop_frame()
58    }
59
60    /// Returns a frame to the front of the transmit queue
61    ///
62    /// The frame will be moved back beyond any other frames already in the queue that have
63    /// higher priority.
64    pub fn return_tx_frame(&mut self, frame: Frame) -> Result<(), OutOfMemoryError> {
65        self.tx_queue.return_frame(frame)
66    }
67
68    /// Returns the subscriptions provided in the last call to `apply_filters()`
69    ///
70    /// This function returns None
71    /// if `empty_filters()` has not been called, was called with no subscriptions, or was called
72    /// but an out-of-memory error occurred while collecting the subscriptions
73    pub fn subscriptions(&self) -> Option<&[Subscription]> {
74        self.subscriptions.as_deref()
75    }
76}
77
78impl<const TC: usize, const RC: usize> Default for QueueOnlyDriver<TC, RC> {
79    fn default() -> Self {
80        QueueOnlyDriver {
81            tx_queue: ArrayQueue::new(),
82            rx_queue: Deque::new(),
83            subscriptions: None,
84        }
85    }
86}
87
88impl<C: Clock, const TC: usize, const RC: usize> TransmitDriver<C> for QueueOnlyDriver<TC, RC> {
89    type Error = Infallible;
90
91    fn try_reserve(&mut self, frames: usize) -> Result<(), OutOfMemoryError> {
92        self.tx_queue.try_reserve(frames)
93    }
94
95    fn transmit(&mut self, frame: Frame, _clock: &mut C) -> nb::Result<Option<Frame>, Self::Error> {
96        self.tx_queue
97            .push_frame(frame)
98            .map(|_oom| None)
99            .map_err(|_oom| nb::Error::WouldBlock)
100    }
101
102    fn flush(&mut self, _clock: &mut C) -> nb::Result<(), Self::Error> {
103        // Can't do anything here. Frames have to be removed externally.
104        Ok(())
105    }
106}
107
108impl<C: Clock, const TC: usize, const RC: usize> ReceiveDriver<C> for QueueOnlyDriver<TC, RC> {
109    type Error = Infallible;
110
111    fn receive(&mut self, _clock: &mut C) -> nb::Result<Frame, Self::Error> {
112        self.rx_queue.pop_front().ok_or(nb::Error::WouldBlock)
113    }
114
115    fn apply_filters<S>(&mut self, _local_node: Option<CanNodeId>, new_subscriptions: S)
116    where
117        S: IntoIterator<Item = Subscription>,
118    {
119        match self.subscriptions.as_mut() {
120            Some(subscriptions) => {
121                subscriptions.clear();
122                for subscription in new_subscriptions {
123                    if FallibleVec::try_push(subscriptions, subscription).is_err() {
124                        // No memory. Remove subscriptions.
125                        self.subscriptions = None;
126                        break;
127                    }
128                }
129            }
130            None => {
131                let mut subscriptions = Vec::new();
132                for subscription in new_subscriptions {
133                    if FallibleVec::try_push(&mut subscriptions, subscription).is_err() {
134                        // No memory. Remove subscriptions.
135                        self.subscriptions = None;
136                        break;
137                    }
138                }
139                self.subscriptions = Some(subscriptions);
140            }
141        }
142    }
143
144    fn apply_accept_all(&mut self) {
145        self.subscriptions = None;
146    }
147}