1use byte::{BytesExt, TryRead};
19use esp_hal::{clock::PhyClockGuard, peripherals::IEEE802154};
20use esp_phy::PhyInitGuard;
21use esp_sync::NonReentrantMutex;
22use ieee802154::mac::{self, FooterMode, FrameSerDesContext};
23
24use self::{
25 frame::FRAME_SIZE,
26 pib::{CONFIG_IEEE802154_CCA_THRESHOLD, IEEE802154_FRAME_EXT_ADDR_SIZE},
27 raw::*,
28};
29pub use self::{
30 frame::{Frame, ReceivedFrame},
31 pib::{CcaMode, PendingMode},
32 raw::RawReceived,
33};
34
35mod frame;
36mod hal;
37mod pib;
38mod raw;
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42pub enum Error {
43 Incomplete,
46
47 BadInput,
49}
50
51impl core::fmt::Display for Error {
52 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
53 match self {
54 Error::Incomplete => write!(f, "Incomplete data."),
55 Error::BadInput => write!(f, "Bad input data."),
56 }
57 }
58}
59
60impl core::error::Error for Error {}
61
62impl From<byte::Error> for Error {
63 fn from(err: byte::Error) -> Self {
64 match err {
65 byte::Error::Incomplete | byte::Error::BadOffset(_) => Error::Incomplete,
66 byte::Error::BadInput { .. } => Error::BadInput,
67 }
68 }
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
73pub struct Config {
74 pub auto_ack_tx: bool,
75 pub auto_ack_rx: bool,
76 pub enhance_ack_tx: bool,
77 pub promiscuous: bool,
78 pub coordinator: bool,
79 pub rx_when_idle: bool,
80 pub txpower: i8,
81 pub channel: u8,
82 pub cca_threshold: i8,
83 pub cca_mode: CcaMode,
84 pub pan_id: Option<u16>,
85 pub short_addr: Option<u16>,
86 pub ext_addr: Option<u64>,
87 pub rx_queue_size: usize,
88}
89
90impl Default for Config {
91 fn default() -> Self {
92 Self {
93 auto_ack_tx: Default::default(),
94 auto_ack_rx: Default::default(),
95 enhance_ack_tx: Default::default(),
96 promiscuous: Default::default(),
97 coordinator: Default::default(),
98 rx_when_idle: Default::default(),
99 txpower: 10,
100 channel: 15,
101 cca_threshold: CONFIG_IEEE802154_CCA_THRESHOLD,
102 cca_mode: CcaMode::Ed,
103 pan_id: None,
104 short_addr: None,
105 ext_addr: None,
106 rx_queue_size: 10,
107 }
108 }
109}
110
111#[derive(Debug)]
113pub struct Ieee802154<'a> {
114 _align: u32,
115 transmit_buffer: [u8; FRAME_SIZE],
116 _phy_clock_guard: PhyClockGuard<'a>,
117 _phy_init_guard: PhyInitGuard<'a>,
118}
119
120impl<'a> Ieee802154<'a> {
121 pub fn new(radio: IEEE802154<'a>) -> Self {
126 let (_phy_clock_guard, _phy_init_guard) = esp_ieee802154_enable(radio);
127 Self {
128 _align: 0,
129 transmit_buffer: [0u8; FRAME_SIZE],
130 _phy_clock_guard,
131 _phy_init_guard,
132 }
133 }
134
135 pub fn set_config(&mut self, cfg: Config) {
137 set_auto_ack_tx(cfg.auto_ack_tx);
138 set_auto_ack_rx(cfg.auto_ack_rx);
139 set_enhance_ack_tx(cfg.enhance_ack_tx);
140 set_promiscuous(cfg.promiscuous);
141 set_coordinator(cfg.coordinator);
142 set_rx_when_idle(cfg.rx_when_idle);
143 set_tx_power(cfg.txpower);
144 set_channel(cfg.channel);
145 set_cca_theshold(cfg.cca_threshold);
146 set_cca_mode(cfg.cca_mode);
147
148 if let Some(pan_id) = cfg.pan_id {
149 set_panid(0, pan_id);
150 }
151
152 if let Some(short_addr) = cfg.short_addr {
153 set_short_address(0, short_addr);
154 }
155
156 if let Some(ext_addr) = cfg.ext_addr {
157 let mut address = [0u8; IEEE802154_FRAME_EXT_ADDR_SIZE];
158 address.copy_from_slice(&ext_addr.to_be_bytes()); set_extended_address(0, address);
161 }
162
163 raw::set_queue_size(cfg.rx_queue_size);
164 }
165
166 pub fn start_receive(&mut self) {
168 ieee802154_receive();
169 }
170
171 pub fn raw_received(&mut self) -> Option<RawReceived> {
173 raw::ensure_receive_enabled();
174 ieee802154_poll()
175 }
176
177 pub fn received(&mut self) -> Option<Result<ReceivedFrame, Error>> {
179 raw::ensure_receive_enabled();
180 if let Some(raw) = ieee802154_poll() {
181 let maybe_decoded = if raw.data[0] as usize > raw.data.len() {
182 mac::Frame::try_read(&raw.data[1..][..raw.data.len()], FooterMode::Explicit)
184 } else {
185 mac::Frame::try_read(&raw.data[1..][..raw.data[0] as usize], FooterMode::Explicit)
186 };
187
188 let result = match maybe_decoded {
189 Ok((decoded, _)) => {
190 let rssi = if (raw.data[0] as usize > raw.data.len()) || (raw.data[0] == 0) {
192 raw.data[raw.data.len() - 1] as i8
193 } else {
194 raw.data[raw.data[0] as usize - 1] as i8
195 };
196
197 Ok(ReceivedFrame {
198 frame: Frame {
199 header: decoded.header,
200 content: decoded.content,
201 payload: decoded.payload.to_vec(),
202 footer: decoded.footer,
203 },
204 channel: raw.channel,
205 rssi,
206 lqi: rssi_to_lqi(rssi),
207 })
208 }
209 Err(err) => Err(err.into()),
210 };
211
212 Some(result)
213 } else {
214 None
215 }
216 }
217
218 pub fn transmit(&mut self, frame: &Frame) -> Result<(), Error> {
220 let frm = mac::Frame {
221 header: frame.header,
222 content: frame.content,
223 payload: &frame.payload,
224 footer: frame.footer,
225 };
226
227 let mut offset = 1usize;
228 self.transmit_buffer
229 .write_with(
230 &mut offset,
231 frm,
232 &mut FrameSerDesContext::no_security(FooterMode::Explicit),
233 )
234 .unwrap();
235 self.transmit_buffer[0] = (offset - 1) as u8;
236
237 ieee802154_transmit(self.transmit_buffer.as_ptr(), false); Ok(())
240 }
241
242 pub fn transmit_raw(&mut self, frame: &[u8]) -> Result<(), Error> {
244 self.transmit_buffer[1..][..frame.len()].copy_from_slice(frame);
245 self.transmit_buffer[0] = frame.len() as u8;
246
247 ieee802154_transmit(self.transmit_buffer.as_ptr(), false); Ok(())
250 }
251
252 pub fn set_tx_done_callback(&mut self, callback: &'a mut (dyn FnMut() + Send)) {
254 CALLBACKS.with(|cbs| {
255 let cb: &'static mut (dyn FnMut() + Send) = unsafe { core::mem::transmute(callback) };
256 cbs.tx_done = Some(cb);
257 });
258 }
259
260 pub fn clear_tx_done_callback(&mut self) {
262 CALLBACKS.with(|cbs| cbs.tx_done = None);
263 }
264
265 pub fn set_rx_available_callback(&mut self, callback: &'a mut (dyn FnMut() + Send)) {
267 CALLBACKS.with(|cbs| {
268 let cb: &'static mut (dyn FnMut() + Send) = unsafe { core::mem::transmute(callback) };
269 cbs.rx_available = Some(cb);
270 });
271 }
272
273 pub fn clear_rx_available_callback(&mut self) {
275 CALLBACKS.with(|cbs| cbs.rx_available = None);
276 }
277
278 pub fn set_tx_done_callback_fn(&mut self, callback: fn()) {
280 CALLBACKS.with(|cbs| cbs.tx_done_fn = Some(callback));
281 }
282
283 pub fn clear_tx_done_callback_fn(&mut self) {
285 CALLBACKS.with(|cbs| cbs.tx_done_fn = None);
286 }
287
288 pub fn set_rx_available_callback_fn(&mut self, callback: fn()) {
290 CALLBACKS.with(|cbs| cbs.rx_available_fn = Some(callback));
291 }
292
293 pub fn clear_rx_available_callback_fn(&mut self) {
295 CALLBACKS.with(|cbs| cbs.rx_available_fn = None);
296 }
297}
298
299impl Drop for Ieee802154<'_> {
300 fn drop(&mut self) {
301 self.clear_tx_done_callback();
302 self.clear_tx_done_callback_fn();
303 self.clear_rx_available_callback();
304 self.clear_rx_available_callback_fn();
305 }
306}
307
308pub fn rssi_to_lqi(rssi: i8) -> u8 {
314 if rssi < -80 {
315 0
316 } else if rssi > -30 {
317 0xff
318 } else {
319 let lqi_convert = ((rssi as u32).wrapping_add(80)) * 255;
320 (lqi_convert / 50) as u8
321 }
322}
323
324struct Callbacks {
325 tx_done: Option<&'static mut (dyn FnMut() + Send)>,
326 rx_available: Option<&'static mut (dyn FnMut() + Send)>,
327 tx_done_fn: Option<fn()>,
329 rx_available_fn: Option<fn()>,
330}
331
332impl Callbacks {
333 fn call_tx_done(&mut self) {
334 if let Some(cb) = self.tx_done.as_mut() {
335 cb();
336 }
337 if let Some(cb) = self.tx_done_fn.as_mut() {
338 cb();
339 }
340 }
341
342 fn call_rx_available(&mut self) {
343 if let Some(cb) = self.rx_available.as_mut() {
344 cb();
345 }
346 if let Some(cb) = self.rx_available_fn.as_mut() {
347 cb();
348 }
349 }
350}
351
352static CALLBACKS: NonReentrantMutex<Callbacks> = NonReentrantMutex::new(Callbacks {
353 tx_done: None,
354 rx_available: None,
355 tx_done_fn: None,
356 rx_available_fn: None,
357});
358
359fn tx_done() {
360 trace!("tx_done callback");
361
362 CALLBACKS.with(|cbs| cbs.call_tx_done());
363}
364
365fn rx_available() {
366 trace!("rx available callback");
367
368 CALLBACKS.with(|cbs| cbs.call_rx_available());
369}