1use defmt_or_log::warn;
3use zencan_common::{
4 messages::{CanId, CanMessage, SyncObject},
5 AtomicCell,
6};
7
8use crate::{
9 lss_slave::LssReceiver, pdo::Pdo, priority_queue::PriorityQueue, sdo_server::SdoComms,
10};
11
12pub trait CanMessageQueue: Send + Sync {
13 fn push(&self, msg: CanMessage) -> Result<(), CanMessage>;
14
15 fn pop(&self) -> Option<CanMessage>;
16}
17
18impl<const N: usize> CanMessageQueue for PriorityQueue<N, CanMessage> {
19 fn push(&self, msg: CanMessage) -> Result<(), CanMessage> {
20 let prio = msg.id().raw();
21 self.push(prio, msg)
22 }
23
24 fn pop(&self) -> Option<CanMessage> {
25 self.pop()
26 }
27}
28
29#[allow(missing_debug_implementations)]
34pub struct NodeMbox {
35 rx_pdos: &'static [Pdo<'static>],
36 tx_pdos: &'static [Pdo<'static>],
37 sdo_tx_cob_id: AtomicCell<Option<CanId>>,
39 sdo_rx_cob_id: AtomicCell<Option<CanId>>,
41 sdo_comms: SdoComms,
42 nmt_mbox: AtomicCell<Option<CanMessage>>,
43 lss_receiver: LssReceiver,
44 sync_flag: AtomicCell<Option<SyncObject>>,
45 process_notify_cb: AtomicCell<Option<&'static (dyn Fn() + Sync)>>,
46 transmit_notify_cb: AtomicCell<Option<&'static (dyn Fn() + Sync)>>,
47 tx_queue: &'static dyn CanMessageQueue,
48}
49
50impl NodeMbox {
51 pub const fn new(
57 rx_pdos: &'static [Pdo],
58 tx_pdos: &'static [Pdo],
59 tx_queue: &'static dyn CanMessageQueue,
60 sdo_buffer: &'static mut [u8],
61 ) -> Self {
62 let sdo_rx_cob_id = AtomicCell::new(None);
63 let sdo_tx_cob_id = AtomicCell::new(None);
64 let sdo_comms = SdoComms::new(sdo_buffer);
65 let nmt_mbox = AtomicCell::new(None);
66 let lss_receiver = LssReceiver::new();
67 let sync_flag = AtomicCell::new(None);
68 let process_notify_cb = AtomicCell::new(None);
69 let transmit_notify_cb = AtomicCell::new(None);
70 Self {
71 rx_pdos,
72 tx_pdos,
73 sdo_rx_cob_id,
74 sdo_tx_cob_id,
75 sdo_comms,
76 nmt_mbox,
77 lss_receiver,
78 sync_flag,
79 process_notify_cb,
80 transmit_notify_cb,
81 tx_queue,
82 }
83 }
84
85 pub fn set_process_notify_callback(&self, callback: &'static (dyn Fn() + Sync)) {
90 self.process_notify_cb.store(Some(callback));
91 }
92
93 fn process_notify(&self) {
94 if let Some(notify_cb) = self.process_notify_cb.load() {
95 notify_cb();
96 }
97 }
98
99 pub fn set_transmit_notify_callback(&self, callback: &'static (dyn Fn() + Sync)) {
103 self.transmit_notify_cb.store(Some(callback));
104 }
105
106 pub(crate) fn transmit_notify(&self) {
107 if let Some(notify_cb) = self.transmit_notify_cb.load() {
108 notify_cb();
109 }
110 }
111
112 pub(crate) fn set_sdo_rx_cob_id(&self, cob_id: Option<CanId>) {
113 self.sdo_rx_cob_id.store(cob_id);
114 }
115
116 pub(crate) fn set_sdo_tx_cob_id(&self, cob_id: Option<CanId>) {
117 self.sdo_tx_cob_id.store(cob_id);
118 }
119
120 pub(crate) fn sdo_comms(&self) -> &SdoComms {
121 &self.sdo_comms
122 }
123
124 pub(crate) fn read_nmt_mbox(&self) -> Option<CanMessage> {
125 self.nmt_mbox.take()
126 }
127
128 pub(crate) fn lss_receiver(&self) -> &LssReceiver {
129 &self.lss_receiver
130 }
131
132 pub(crate) fn read_sync_flag(&self) -> Option<SyncObject> {
133 self.sync_flag.take()
134 }
135
136 pub fn store_message(&self, msg: CanMessage) -> Result<(), CanMessage> {
138 let id = msg.id();
139 if id == zencan_common::messages::NMT_CMD_ID {
140 self.nmt_mbox.store(Some(msg));
141 self.process_notify();
142 return Ok(());
143 }
144
145 if id == zencan_common::messages::SYNC_ID {
146 let sync_object = SyncObject::from(msg);
147 self.sync_flag.store(Some(sync_object));
148 self.process_notify();
149 return Ok(());
150 }
151
152 if id == zencan_common::messages::LSS_REQ_ID {
153 if let Ok(lss_req) = msg.data().try_into() {
154 if self.lss_receiver.handle_req(lss_req) {
155 self.process_notify();
156 }
157 } else {
158 warn!("Invalid LSS request");
159 return Err(msg);
160 }
161 return Ok(());
162 }
163
164 for rpdo in self.rx_pdos {
165 if !rpdo.valid() {
166 continue;
167 }
168 if id == rpdo.cob_id() {
169 let mut data = [0u8; 8];
170 data[0..msg.data().len()].copy_from_slice(msg.data());
171 rpdo.buffered_value.store(Some(data));
172 return Ok(());
173 }
174 }
175
176 if let Some(cob_id) = self.sdo_rx_cob_id.load() {
177 if id == cob_id {
178 self.sdo_comms.handle_req(msg.data());
179 }
180 }
181
182 Err(msg)
183 }
184
185 pub fn next_transmit_message(&self) -> Option<CanMessage> {
193 for pdo in self.tx_pdos.iter() {
194 if let Some(buf) = pdo.buffered_value.take() {
195 return Some(CanMessage::new(pdo.cob_id(), &buf));
196 }
197 }
198
199 if let Some(msg) = self.tx_queue.pop() {
200 return Some(msg);
201 }
202
203 if let Some(msg) = self.sdo_comms.next_transmit_message() {
204 if let Some(id) = self.sdo_tx_cob_id.load() {
205 return Some(CanMessage::new(id, &msg));
206 }
207 }
208
209 None
210 }
211
212 pub fn queue_transmit_message(&self, msg: CanMessage) -> Result<(), CanMessage> {
214 self.tx_queue.push(msg)
215 }
216}