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