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 ieee802154_poll()
174 }
175
176 pub fn received(&mut self) -> Option<Result<ReceivedFrame, Error>> {
178 if let Some(raw) = ieee802154_poll() {
179 let maybe_decoded = if raw.data[0] as usize > raw.data.len() {
180 mac::Frame::try_read(&raw.data[1..][..raw.data.len()], FooterMode::Explicit)
182 } else {
183 mac::Frame::try_read(&raw.data[1..][..raw.data[0] as usize], FooterMode::Explicit)
184 };
185
186 let result = match maybe_decoded {
187 Ok((decoded, _)) => {
188 let rssi = if (raw.data[0] as usize > raw.data.len()) || (raw.data[0] == 0) {
190 raw.data[raw.data.len() - 1] as i8
191 } else {
192 raw.data[raw.data[0] as usize - 1] as i8
193 };
194
195 Ok(ReceivedFrame {
196 frame: Frame {
197 header: decoded.header,
198 content: decoded.content,
199 payload: decoded.payload.to_vec(),
200 footer: decoded.footer,
201 },
202 channel: raw.channel,
203 rssi,
204 lqi: rssi_to_lqi(rssi),
205 })
206 }
207 Err(err) => Err(err.into()),
208 };
209
210 Some(result)
211 } else {
212 None
213 }
214 }
215
216 pub fn transmit(&mut self, frame: &Frame) -> Result<(), Error> {
218 let frm = mac::Frame {
219 header: frame.header,
220 content: frame.content,
221 payload: &frame.payload,
222 footer: frame.footer,
223 };
224
225 let mut offset = 1usize;
226 self.transmit_buffer
227 .write_with(
228 &mut offset,
229 frm,
230 &mut FrameSerDesContext::no_security(FooterMode::Explicit),
231 )
232 .unwrap();
233 self.transmit_buffer[0] = (offset - 1) as u8;
234
235 ieee802154_transmit(self.transmit_buffer.as_ptr(), false); Ok(())
238 }
239
240 pub fn transmit_raw(&mut self, frame: &[u8]) -> Result<(), Error> {
242 self.transmit_buffer[1..][..frame.len()].copy_from_slice(frame);
243 self.transmit_buffer[0] = frame.len() as u8;
244
245 ieee802154_transmit(self.transmit_buffer.as_ptr(), false); Ok(())
248 }
249
250 pub fn set_tx_done_callback(&mut self, callback: &'a mut (dyn FnMut() + Send)) {
252 CALLBACKS.with(|cbs| {
253 let cb: &'static mut (dyn FnMut() + Send) = unsafe { core::mem::transmute(callback) };
254 cbs.tx_done = Some(cb);
255 });
256 }
257
258 pub fn clear_tx_done_callback(&mut self) {
260 CALLBACKS.with(|cbs| cbs.tx_done = None);
261 }
262
263 pub fn set_rx_available_callback(&mut self, callback: &'a mut (dyn FnMut() + Send)) {
265 CALLBACKS.with(|cbs| {
266 let cb: &'static mut (dyn FnMut() + Send) = unsafe { core::mem::transmute(callback) };
267 cbs.rx_available = Some(cb);
268 });
269 }
270
271 pub fn clear_rx_available_callback(&mut self) {
273 CALLBACKS.with(|cbs| cbs.rx_available = None);
274 }
275
276 pub fn set_tx_done_callback_fn(&mut self, callback: fn()) {
278 CALLBACKS.with(|cbs| cbs.tx_done_fn = Some(callback));
279 }
280
281 pub fn clear_tx_done_callback_fn(&mut self) {
283 CALLBACKS.with(|cbs| cbs.tx_done_fn = None);
284 }
285
286 pub fn set_rx_available_callback_fn(&mut self, callback: fn()) {
288 CALLBACKS.with(|cbs| cbs.rx_available_fn = Some(callback));
289 }
290
291 pub fn clear_rx_available_callback_fn(&mut self) {
293 CALLBACKS.with(|cbs| cbs.rx_available_fn = None);
294 }
295}
296
297impl Drop for Ieee802154<'_> {
298 fn drop(&mut self) {
299 self.clear_tx_done_callback();
300 self.clear_tx_done_callback_fn();
301 self.clear_rx_available_callback();
302 self.clear_rx_available_callback_fn();
303 }
304}
305
306pub fn rssi_to_lqi(rssi: i8) -> u8 {
312 if rssi < -80 {
313 0
314 } else if rssi > -30 {
315 0xff
316 } else {
317 let lqi_convert = ((rssi as u32).wrapping_add(80)) * 255;
318 (lqi_convert / 50) as u8
319 }
320}
321
322struct Callbacks {
323 tx_done: Option<&'static mut (dyn FnMut() + Send)>,
324 rx_available: Option<&'static mut (dyn FnMut() + Send)>,
325 tx_done_fn: Option<fn()>,
327 rx_available_fn: Option<fn()>,
328}
329
330impl Callbacks {
331 fn call_tx_done(&mut self) {
332 if let Some(cb) = self.tx_done.as_mut() {
333 cb();
334 }
335 if let Some(cb) = self.tx_done_fn.as_mut() {
336 cb();
337 }
338 }
339
340 fn call_rx_available(&mut self) {
341 if let Some(cb) = self.rx_available.as_mut() {
342 cb();
343 }
344 if let Some(cb) = self.rx_available_fn.as_mut() {
345 cb();
346 }
347 }
348}
349
350static CALLBACKS: NonReentrantMutex<Callbacks> = NonReentrantMutex::new(Callbacks {
351 tx_done: None,
352 rx_available: None,
353 tx_done_fn: None,
354 rx_available_fn: None,
355});
356
357fn tx_done() {
358 trace!("tx_done callback");
359
360 CALLBACKS.with(|cbs| cbs.call_tx_done());
361}
362
363fn rx_available() {
364 trace!("rx available callback");
365
366 CALLBACKS.with(|cbs| cbs.call_rx_available());
367}