1#![allow(missing_docs)]
19
20use byte::{BytesExt, TryRead};
21use docsplay::Display;
22use esp_hal::peripherals::IEEE802154;
23use esp_phy::{PhyClockGuard, PhyInitGuard};
24use esp_sync::NonReentrantMutex;
25use ieee802154::mac::{self, FooterMode, FrameSerDesContext};
26
27use self::{
28 frame::FRAME_SIZE,
29 pib::{CONFIG_IEEE802154_CCA_THRESHOLD, IEEE802154_FRAME_EXT_ADDR_SIZE},
30 raw::*,
31};
32pub use self::{
33 frame::{Frame, ReceivedFrame},
34 pib::{CcaMode, PendingMode},
35 raw::RawReceived,
36};
37mod frame;
38mod hal;
39mod pib;
40mod raw;
41
42#[derive(Display, Debug, Clone, Copy, PartialEq, Eq)]
44#[cfg_attr(feature = "defmt", derive(defmt::Format))]
45#[instability::unstable]
46pub enum Error {
47 Incomplete,
50
51 BadInput,
53}
54
55impl core::error::Error for Error {}
56
57impl From<byte::Error> for Error {
58 fn from(err: byte::Error) -> Self {
59 match err {
60 byte::Error::Incomplete | byte::Error::BadOffset(_) => Error::Incomplete,
61 byte::Error::BadInput { .. } => Error::BadInput,
62 }
63 }
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68#[cfg_attr(feature = "defmt", derive(defmt::Format))]
69#[instability::unstable]
70pub struct Config {
71 pub auto_ack_tx: bool,
72 pub auto_ack_rx: bool,
73 pub enhance_ack_tx: bool,
74 pub promiscuous: bool,
75 pub coordinator: bool,
76 pub rx_when_idle: bool,
77 pub txpower: i8,
78 pub channel: u8,
79 pub cca_threshold: i8,
80 pub cca_mode: CcaMode,
81 pub pan_id: Option<u16>,
82 pub short_addr: Option<u16>,
83 pub ext_addr: Option<u64>,
84 pub rx_queue_size: usize,
85}
86
87impl Default for Config {
88 fn default() -> Self {
89 Self {
90 auto_ack_tx: Default::default(),
91 auto_ack_rx: Default::default(),
92 enhance_ack_tx: Default::default(),
93 promiscuous: Default::default(),
94 coordinator: Default::default(),
95 rx_when_idle: Default::default(),
96 txpower: 20,
97 channel: 15,
98 cca_threshold: CONFIG_IEEE802154_CCA_THRESHOLD,
99 cca_mode: CcaMode::Ed,
100 pan_id: None,
101 short_addr: None,
102 ext_addr: None,
103 rx_queue_size: 10,
104 }
105 }
106}
107
108#[derive(Debug)]
110#[cfg_attr(feature = "defmt", derive(defmt::Format))]
111#[instability::unstable]
112pub struct Ieee802154<'a> {
113 _align: u32,
114 transmit_buffer: [u8; FRAME_SIZE],
115 _phy_clock_guard: PhyClockGuard<'a>,
116 _phy_init_guard: PhyInitGuard<'a>,
117}
118
119impl<'a> Ieee802154<'a> {
120 #[instability::unstable]
125 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 #[instability::unstable]
137 pub fn set_config(&mut self, cfg: Config) {
138 set_auto_ack_tx(cfg.auto_ack_tx);
139 set_auto_ack_rx(cfg.auto_ack_rx);
140 set_enhance_ack_tx(cfg.enhance_ack_tx);
141 set_promiscuous(cfg.promiscuous);
142 set_coordinator(cfg.coordinator);
143 set_rx_when_idle(cfg.rx_when_idle);
144 set_tx_power(cfg.txpower);
145 set_channel(cfg.channel);
146 set_cca_theshold(cfg.cca_threshold);
147 set_cca_mode(cfg.cca_mode);
148
149 if let Some(pan_id) = cfg.pan_id {
150 set_panid(0, pan_id);
151 }
152
153 if let Some(short_addr) = cfg.short_addr {
154 set_short_address(0, short_addr);
155 }
156
157 if let Some(ext_addr) = cfg.ext_addr {
158 let mut address = [0u8; IEEE802154_FRAME_EXT_ADDR_SIZE];
159 address.copy_from_slice(&ext_addr.to_le_bytes());
160
161 set_extended_address(0, address);
162 }
163
164 raw::set_queue_size(cfg.rx_queue_size);
165 }
166
167 #[instability::unstable]
169 pub fn start_receive(&mut self) {
170 ieee802154_receive();
171 }
172
173 #[instability::unstable]
175 pub fn raw_received(&mut self) -> Option<RawReceived> {
176 raw::ensure_receive_enabled();
177 ieee802154_poll()
178 }
179
180 #[instability::unstable]
192 pub fn get_ack_frame(&self) -> Option<RawReceived> {
193 raw::get_ack_frame()
194 }
195
196 #[instability::unstable]
198 pub fn received(&mut self) -> Option<Result<ReceivedFrame, Error>> {
199 raw::ensure_receive_enabled();
200 if let Some(raw) = ieee802154_poll() {
201 let maybe_decoded = if raw.data[0] as usize > raw.data.len() {
202 mac::Frame::try_read(&raw.data[1..][..raw.data.len()], FooterMode::Explicit)
204 } else {
205 mac::Frame::try_read(&raw.data[1..][..raw.data[0] as usize], FooterMode::Explicit)
206 };
207
208 let result = match maybe_decoded {
209 Ok((decoded, _)) => {
210 let rssi = if (raw.data[0] as usize > raw.data.len()) || (raw.data[0] == 0) {
212 raw.data[raw.data.len() - 1] as i8
213 } else {
214 raw.data[raw.data[0] as usize - 1] as i8
215 };
216
217 Ok(ReceivedFrame {
218 frame: Frame {
219 header: decoded.header,
220 content: decoded.content,
221 payload: decoded.payload.to_vec(),
222 footer: decoded.footer,
223 },
224 channel: raw.channel,
225 rssi,
226 lqi: rssi_to_lqi(rssi),
227 })
228 }
229 Err(err) => Err(err.into()),
230 };
231
232 Some(result)
233 } else {
234 None
235 }
236 }
237
238 #[instability::unstable]
243 pub fn transmit(&mut self, frame: &Frame, cca: bool) -> Result<(), Error> {
244 let frm = mac::Frame {
245 header: frame.header,
246 content: frame.content,
247 payload: &frame.payload,
248 footer: frame.footer,
249 };
250
251 let mut offset = 1usize;
252 self.transmit_buffer
253 .write_with(
254 &mut offset,
255 frm,
256 &mut FrameSerDesContext::no_security(FooterMode::Explicit),
257 )
258 .unwrap();
259 self.transmit_buffer[0] = (offset - 1) as u8;
260
261 ieee802154_transmit(self.transmit_buffer.as_ptr(), cca);
262
263 Ok(())
264 }
265
266 #[instability::unstable]
271 pub fn transmit_raw(&mut self, frame: &[u8], cca: bool) -> Result<(), Error> {
272 self.transmit_buffer[1..][..frame.len()].copy_from_slice(frame);
273 self.transmit_buffer[0] = frame.len() as u8;
274
275 ieee802154_transmit(self.transmit_buffer.as_ptr(), cca);
276
277 Ok(())
278 }
279
280 #[instability::unstable]
282 pub fn set_tx_done_callback(&mut self, callback: &'a mut (dyn FnMut() + Send)) {
283 CALLBACKS.with(|cbs| {
284 let cb: &'static mut (dyn FnMut() + Send) = unsafe { core::mem::transmute(callback) };
285 cbs.tx_done = Some(cb);
286 });
287 }
288
289 #[instability::unstable]
291 pub fn clear_tx_done_callback(&mut self) {
292 CALLBACKS.with(|cbs| cbs.tx_done = None);
293 }
294
295 #[instability::unstable]
297 pub fn set_rx_available_callback(&mut self, callback: &'a mut (dyn FnMut() + Send)) {
298 CALLBACKS.with(|cbs| {
299 let cb: &'static mut (dyn FnMut() + Send) = unsafe { core::mem::transmute(callback) };
300 cbs.rx_available = Some(cb);
301 });
302 }
303
304 #[instability::unstable]
306 pub fn clear_rx_available_callback(&mut self) {
307 CALLBACKS.with(|cbs| cbs.rx_available = None);
308 }
309
310 #[instability::unstable]
312 pub fn set_tx_done_callback_fn(&mut self, callback: fn()) {
313 CALLBACKS.with(|cbs| cbs.tx_done_fn = Some(callback));
314 }
315
316 #[instability::unstable]
318 pub fn clear_tx_done_callback_fn(&mut self) {
319 CALLBACKS.with(|cbs| cbs.tx_done_fn = None);
320 }
321
322 #[instability::unstable]
324 pub fn set_rx_available_callback_fn(&mut self, callback: fn()) {
325 CALLBACKS.with(|cbs| cbs.rx_available_fn = Some(callback));
326 }
327
328 #[instability::unstable]
330 pub fn clear_rx_available_callback_fn(&mut self) {
331 CALLBACKS.with(|cbs| cbs.rx_available_fn = None);
332 }
333
334 #[instability::unstable]
336 pub fn set_tx_failed_callback(&mut self, callback: &'a mut (dyn FnMut() + Send)) {
337 CALLBACKS.with(|cbs| {
338 let cb: &'static mut (dyn FnMut() + Send) = unsafe { core::mem::transmute(callback) };
339 cbs.tx_failed = Some(cb);
340 });
341 }
342
343 #[instability::unstable]
345 pub fn clear_tx_failed_callback(&mut self) {
346 CALLBACKS.with(|cbs| cbs.tx_failed = None);
347 }
348
349 #[instability::unstable]
351 pub fn set_tx_failed_callback_fn(&mut self, callback: fn()) {
352 CALLBACKS.with(|cbs| cbs.tx_failed_fn = Some(callback));
353 }
354
355 #[instability::unstable]
357 pub fn clear_tx_failed_callback_fn(&mut self) {
358 CALLBACKS.with(|cbs| cbs.tx_failed_fn = None);
359 }
360}
361
362impl Drop for Ieee802154<'_> {
363 fn drop(&mut self) {
364 self.clear_tx_done_callback();
365 self.clear_tx_done_callback_fn();
366 self.clear_rx_available_callback();
367 self.clear_rx_available_callback_fn();
368 self.clear_tx_failed_callback();
369 self.clear_tx_failed_callback_fn();
370 }
371}
372
373#[instability::unstable]
379pub fn rssi_to_lqi(rssi: i8) -> u8 {
380 if rssi < -80 {
381 0
382 } else if rssi > -30 {
383 0xff
384 } else {
385 let lqi_convert = ((rssi as u32).wrapping_add(80)) * 255;
386 (lqi_convert / 50) as u8
387 }
388}
389
390struct Callbacks {
391 tx_done: Option<&'static mut (dyn FnMut() + Send)>,
392 rx_available: Option<&'static mut (dyn FnMut() + Send)>,
393 tx_failed: Option<&'static mut (dyn FnMut() + Send)>,
394 tx_done_fn: Option<fn()>,
396 rx_available_fn: Option<fn()>,
397 tx_failed_fn: Option<fn()>,
398}
399
400impl Callbacks {
401 fn call_tx_done(&mut self) {
402 if let Some(cb) = self.tx_done.as_mut() {
403 cb();
404 }
405 if let Some(cb) = self.tx_done_fn.as_mut() {
406 cb();
407 }
408 }
409
410 fn call_rx_available(&mut self) {
411 if let Some(cb) = self.rx_available.as_mut() {
412 cb();
413 }
414 if let Some(cb) = self.rx_available_fn.as_mut() {
415 cb();
416 }
417 }
418
419 fn call_tx_failed(&mut self) {
420 if let Some(cb) = self.tx_failed.as_mut() {
421 cb();
422 }
423 if let Some(cb) = self.tx_failed_fn.as_mut() {
424 cb();
425 }
426 }
427}
428
429static CALLBACKS: NonReentrantMutex<Callbacks> = NonReentrantMutex::new(Callbacks {
430 tx_done: None,
431 rx_available: None,
432 tx_failed: None,
433 tx_done_fn: None,
434 rx_available_fn: None,
435 tx_failed_fn: None,
436});
437
438fn tx_done() {
439 trace!("tx_done callback");
440
441 CALLBACKS.with(|cbs| cbs.call_tx_done());
442}
443
444fn tx_failed() {
445 trace!("tx_failed callback");
446
447 CALLBACKS.with(|cbs| cbs.call_tx_failed());
448}
449
450fn rx_available() {
451 trace!("rx available callback");
452
453 CALLBACKS.with(|cbs| cbs.call_rx_available());
454}