1use defmt_or_log::warn;
3use zencan_common::{
4 messages::{CanId, CanMessage},
5 AtomicCell,
6};
7
8use crate::{lss_slave::LssReceiver, pdo::Pdo, sdo_server::SdoReceiver};
9
10#[allow(missing_debug_implementations)]
15pub struct NodeMbox {
16 rx_pdos: &'static [Pdo],
17 sdo_cob_id: AtomicCell<Option<CanId>>,
18 sdo_receiver: SdoReceiver,
19 nmt_mbox: AtomicCell<Option<CanMessage>>,
20 lss_receiver: LssReceiver,
21 sync_flag: AtomicCell<bool>,
22 notify_cb: AtomicCell<Option<&'static (dyn Fn() + Sync)>>,
23}
24
25impl NodeMbox {
26 pub const fn new(rx_pdos: &'static [Pdo], sdo_buffer: &'static mut [u8]) -> Self {
32 let sdo_cob_id = AtomicCell::new(None);
33 let sdo_receiver = SdoReceiver::new(sdo_buffer);
34 let nmt_mbox = AtomicCell::new(None);
35 let lss_receiver = LssReceiver::new();
36 let sync_flag = AtomicCell::new(false);
37 let notify_cb = AtomicCell::new(None);
38 Self {
39 rx_pdos,
40 sdo_cob_id,
41 sdo_receiver,
42 nmt_mbox,
43 lss_receiver,
44 sync_flag,
45 notify_cb,
46 }
47 }
48
49 pub fn set_process_notify_callback(&self, callback: &'static (dyn Fn() + Sync)) {
54 self.notify_cb.store(Some(callback));
55 }
56
57 fn notify(&self) {
58 if let Some(notify_cb) = self.notify_cb.load() {
59 notify_cb();
60 }
61 }
62
63 pub(crate) fn set_sdo_cob_id(&self, cob_id: Option<CanId>) {
64 self.sdo_cob_id.store(cob_id);
65 }
66
67 pub(crate) fn sdo_receiver(&self) -> &SdoReceiver {
68 &self.sdo_receiver
69 }
70
71 pub(crate) fn read_nmt_mbox(&self) -> Option<CanMessage> {
72 self.nmt_mbox.take()
73 }
74
75 pub(crate) fn lss_receiver(&self) -> &LssReceiver {
76 &self.lss_receiver
77 }
78
79 pub(crate) fn read_sync_flag(&self) -> bool {
80 self.sync_flag.take()
81 }
82
83 pub fn store_message(&self, msg: CanMessage) -> Result<(), CanMessage> {
85 let id = msg.id();
86 if id == zencan_common::messages::NMT_CMD_ID {
87 self.nmt_mbox.store(Some(msg));
88 self.notify();
89 return Ok(());
90 }
91
92 if id == zencan_common::messages::SYNC_ID {
93 self.sync_flag.store(true);
94 self.notify();
95 return Ok(());
96 }
97
98 if id == zencan_common::messages::LSS_REQ_ID {
99 if let Ok(lss_req) = msg.data().try_into() {
100 if self.lss_receiver.handle_req(lss_req) {
101 self.notify();
102 }
103 } else {
104 warn!("Invalid LSS request");
105 return Err(msg);
106 }
107 return Ok(());
108 }
109
110 for rpdo in self.rx_pdos {
111 if !rpdo.valid() {
112 continue;
113 }
114 if id == rpdo.cob_id() {
115 let mut data = [0u8; 8];
116 data[0..msg.data().len()].copy_from_slice(msg.data());
117 rpdo.buffered_value.store(Some(data));
118 return Ok(());
119 }
120 }
121
122 if let Some(cob_id) = self.sdo_cob_id.load() {
123 if id == cob_id {
124 self.sdo_receiver.handle_req(msg.data());
125 }
126 }
127
128 Err(msg)
129 }
130}