esp_radio/ieee802154/
raw.rs1use alloc::collections::VecDeque as Queue;
2
3use esp_hal::{
4 clock::{ModemClockController, PhyClockGuard, init_radio_clocks},
5 handler,
6 interrupt::Priority,
7 peripherals::IEEE802154,
8};
9use esp_phy::{PhyController, PhyInitGuard};
10use esp_sync::NonReentrantMutex;
11use esp_wifi_sys::include::{
12 ieee802154_coex_event_t,
13 ieee802154_coex_event_t_IEEE802154_IDLE,
14 ieee802154_coex_event_t_IEEE802154_LOW,
15 ieee802154_coex_event_t_IEEE802154_MIDDLE,
16};
17
18use super::{
19 frame::{
20 FRAME_SIZE,
21 FRAME_VERSION_1,
22 FRAME_VERSION_2,
23 frame_get_version,
24 frame_is_ack_required,
25 },
26 hal::*,
27 pib::*,
28};
29
30const PHY_ENABLE_VERSION_PRINT: u8 = 1;
31
32static mut RX_BUFFER: [u8; FRAME_SIZE] = [0u8; FRAME_SIZE];
33
34struct IeeeState {
35 state: Ieee802154State,
36 rx_queue: Queue<RawReceived>,
37 rx_queue_size: usize,
38}
39
40static STATE: NonReentrantMutex<IeeeState> = NonReentrantMutex::new(IeeeState {
41 state: Ieee802154State::Idle,
42 rx_queue: Queue::new(),
43 rx_queue_size: 10,
44});
45
46unsafe extern "C" {
47 fn bt_bb_v2_init_cmplx(print_version: u8); fn bt_bb_set_zb_tx_on_delay(time: u16); fn esp_coex_ieee802154_ack_pti_set(event: ieee802154_coex_event_t); fn esp_coex_ieee802154_txrx_pti_set(event: ieee802154_coex_event_t); }
55
56#[derive(Debug, Clone, Copy, PartialEq)]
57enum Ieee802154State {
58 Idle,
59 Receive,
60 Transmit,
61 TxAck,
62}
63
64#[allow(unused)]
65#[derive(Debug, Clone, Copy, PartialEq)]
66enum Ieee802154TxRxScene {
67 Idle,
68 Tx,
69 Rx,
70 TxAt,
71 RxAt,
72}
73
74#[derive(Debug, Clone, Copy, PartialEq, Eq)]
76pub struct RawReceived {
77 pub data: [u8; FRAME_SIZE],
79 pub channel: u8,
81}
82
83pub(crate) fn esp_ieee802154_enable(
84 mut radio: IEEE802154<'_>,
85) -> (PhyClockGuard<'_>, PhyInitGuard<'_>) {
86 init_radio_clocks();
87 let phy_clock_guard = radio.enable_phy_clock();
88 radio.enable_modem_clock(true);
89
90 let phy_init_guard = radio.enable_phy();
91
92 esp_btbb_enable();
93 ieee802154_mac_init();
94
95 info!("date={:x}", mac_date());
96 (phy_clock_guard, phy_init_guard)
97}
98
99fn esp_btbb_enable() {
100 unsafe { bt_bb_v2_init_cmplx(PHY_ENABLE_VERSION_PRINT) };
101}
102
103fn ieee802154_mac_init() {
104 #[cfg(feature = "esp32c6")]
105 unsafe {
106 unsafe extern "C" {
107 static mut coex_pti_tab_ptr: u32;
108 static coex_pti_tab: u8;
109 }
110
111 core::ptr::addr_of_mut!(coex_pti_tab_ptr).write_volatile(&coex_pti_tab as *const _ as u32);
113 }
114
115 ieee802154_pib_init();
116
117 enable_events(Event::mask());
118 disable_events(Event::Timer0Overflow | Event::Timer1Overflow);
119
120 enable_tx_abort_events(
121 TxAbortReason::RxAckTimeout
122 | TxAbortReason::TxCoexBreak
123 | TxAbortReason::TxSecurityError
124 | TxAbortReason::CcaFailed
125 | TxAbortReason::CcaBusy
126 | TxAbortReason::TxStop,
127 );
128 enable_rx_abort_events(
129 RxAbortReason::TxAckTimeout | RxAbortReason::TxAckCoexBreak | RxAbortReason::RxStop,
130 );
131
132 set_ed_sample_mode(EdSampleMode::Avg);
133
134 unsafe { esp_coex_ieee802154_ack_pti_set(ieee802154_coex_event_t_IEEE802154_MIDDLE) };
135 ieee802154_set_txrx_pti(Ieee802154TxRxScene::Idle);
136
137 unsafe {
138 bt_bb_set_zb_tx_on_delay(50); }
140 set_rx_on_delay(50);
141
142 unsafe {
146 esp_hal::interrupt::bind_interrupt(
147 esp_hal::peripherals::Interrupt::ZB_MAC,
148 zb_mac_handler.handler(),
149 );
150 }
151 esp_hal::interrupt::enable(
152 esp_hal::peripherals::Interrupt::ZB_MAC,
153 zb_mac_handler.priority(),
154 )
155 .unwrap();
156}
157
158fn ieee802154_set_txrx_pti(txrx_scene: Ieee802154TxRxScene) {
159 match txrx_scene {
160 Ieee802154TxRxScene::Idle => {
161 unsafe { esp_coex_ieee802154_txrx_pti_set(ieee802154_coex_event_t_IEEE802154_IDLE) };
162 }
163 Ieee802154TxRxScene::Tx | Ieee802154TxRxScene::Rx => {
164 unsafe { esp_coex_ieee802154_txrx_pti_set(ieee802154_coex_event_t_IEEE802154_LOW) };
165 }
166 Ieee802154TxRxScene::TxAt | Ieee802154TxRxScene::RxAt => {
167 unsafe { esp_coex_ieee802154_txrx_pti_set(ieee802154_coex_event_t_IEEE802154_MIDDLE) };
168 }
169 }
170}
171
172pub fn tx_init(frame: *const u8) {
173 let tx_frame = frame;
174 stop_current_operation();
175 ieee802154_pib_update();
176 ieee802154_sec_update();
177
178 set_tx_addr(tx_frame);
179
180 if true
181 {
183 set_next_rx_buffer();
185 }
186}
187
188pub(crate) fn set_queue_size(rx_queue_size: usize) {
189 STATE.with(|state| {
190 state.rx_queue_size = rx_queue_size;
191 });
192}
193
194pub fn ieee802154_transmit(frame: *const u8, cca: bool) -> i32 {
195 STATE.with(|state| {
196 tx_init(frame);
197
198 ieee802154_set_txrx_pti(Ieee802154TxRxScene::Tx);
199
200 if cca {
201 } else {
205 set_cmd(Command::TxStart);
206 state.state = Ieee802154State::Transmit;
212 }
214 });
215
216 0 }
218
219pub fn ieee802154_receive() -> i32 {
220 STATE.with(|state| {
221 if state.state == Ieee802154State::Receive {
222 return;
223 }
224
225 rx_init();
226 enable_rx();
227
228 state.state = Ieee802154State::Receive;
229 });
230
231 0 }
233
234pub fn ieee802154_poll() -> Option<RawReceived> {
235 STATE.with(|state| state.rx_queue.pop_front())
236}
237
238fn rx_init() {
239 stop_current_operation();
240 ieee802154_pib_update();
241}
242
243fn enable_rx() {
244 set_next_rx_buffer();
245 ieee802154_set_txrx_pti(Ieee802154TxRxScene::Rx);
246
247 set_cmd(Command::RxStart);
248
249 }
251
252fn stop_current_operation() {
253 let events = events();
254 set_cmd(Command::Stop);
255 clear_events(events);
256}
257
258fn set_next_rx_buffer() {
259 set_rx_addr(core::ptr::addr_of_mut!(RX_BUFFER).cast());
260}
261
262pub fn set_promiscuous(enable: bool) {
263 ieee802154_pib_set_promiscuous(enable);
264}
265
266pub fn set_auto_ack_tx(enable: bool) {
267 ieee802154_pib_set_auto_ack_tx(enable);
268}
269
270pub fn set_auto_ack_rx(enable: bool) {
271 ieee802154_pib_set_auto_ack_rx(enable);
272}
273
274pub fn set_enhance_ack_tx(enable: bool) {
275 ieee802154_pib_set_enhance_ack_tx(enable);
276}
277
278pub fn set_coordinator(enable: bool) {
279 ieee802154_pib_set_coordinator(enable);
280}
281
282pub fn set_rx_when_idle(enable: bool) {
283 ieee802154_pib_set_rx_when_idle(enable);
284}
285
286pub fn set_tx_power(power: i8) {
287 ieee802154_pib_set_tx_power(power);
288}
289
290pub fn set_channel(channel: u8) {
291 ieee802154_pib_set_channel(channel);
292}
293
294#[allow(unused)]
295pub fn set_pending_mode(mode: PendingMode) {
296 ieee802154_pib_set_pending_mode(mode);
297}
298
299#[allow(unused)]
300pub fn set_multipan_enable(mask: u8) {
301 set_multipan_enable_mask(mask);
302}
303
304pub fn set_short_address(index: u8, address: u16) {
305 ieee802154_pib_set_short_address(index, address);
306}
307
308pub fn set_extended_address(index: u8, address: [u8; IEEE802154_FRAME_EXT_ADDR_SIZE]) {
309 ieee802154_pib_set_extended_address(index, address);
310}
311
312pub fn set_cca_theshold(cca_threshold: i8) {
313 ieee802154_pib_set_cca_theshold(cca_threshold);
314}
315
316pub fn set_cca_mode(mode: CcaMode) {
317 ieee802154_pib_set_cca_mode(mode);
318}
319
320pub fn set_panid(index: u8, id: u16) {
321 ieee802154_pib_set_panid(index, id);
322}
323
324#[inline(always)]
325fn ieee802154_sec_update() {
326 let is_security = false;
327 set_transmit_security(is_security);
328 }
330
331fn next_operation_inner(state: &mut IeeeState) -> Ieee802154State {
332 let prev_state = state.state;
333 state.state = if ieee802154_pib_get_rx_when_idle() {
334 enable_rx();
335 Ieee802154State::Receive
336 } else {
337 Ieee802154State::Idle
338 };
339
340 prev_state
341}
342
343fn notify_state(state: Ieee802154State) {
344 match state {
345 Ieee802154State::Receive => super::rx_available(),
346 Ieee802154State::Transmit => super::tx_done(),
347 Ieee802154State::TxAck => super::tx_done(),
348 _ => (),
349 }
350}
351
352fn next_operation() {
353 let previous_operation = STATE.with(next_operation_inner);
354
355 notify_state(previous_operation)
356}
357
358#[handler(priority = Priority::Priority1)]
359fn zb_mac_handler() {
360 trace!("ZB_MAC interrupt");
361
362 let events = events();
363 clear_events(events);
364
365 trace!("events = {:032b}", events);
366
367 if events & Event::RxSfdDone != 0 {
368 trace!("rx sfd done");
371 }
372
373 if events & Event::TxSfdDone != 0 {
374 trace!("tx sfd done");
377 }
378
379 if events & Event::TxDone != 0 {
380 trace!("tx done");
381 next_operation();
382 }
383
384 if events & Event::RxDone != 0 {
385 trace!("rx done");
386 unsafe {
387 trace!(
388 "Received raw {:?}",
389 crate::fmt::Bytes(&*core::ptr::addr_of!(RX_BUFFER))
390 );
391 let mut state_for_notify = Ieee802154State::Idle;
392 STATE.with(|state| {
393 if state.rx_queue.len() <= state.rx_queue_size {
394 let item = RawReceived {
395 data: RX_BUFFER,
396 channel: freq_to_channel(freq()),
397 };
398 state.rx_queue.push_back(item);
399 } else {
400 warn!("Receive queue full");
401 }
402
403 let frm = if RX_BUFFER[0] >= FRAME_SIZE as u8 {
404 warn!("RX_BUFFER[0] {} is larger than frame size", RX_BUFFER[0]);
405 &RX_BUFFER[1..][..FRAME_SIZE - 1]
406 } else {
407 &RX_BUFFER[1..][..RX_BUFFER[0] as usize]
408 };
409 if will_auto_send_ack(frm) {
410 state.state = Ieee802154State::TxAck;
411 } else if should_send_enhanced_ack(frm) {
412 } else {
414 state_for_notify = next_operation_inner(state)
415 }
417 });
418
419 notify_state(state_for_notify)
420 }
421 }
422
423 if events & Event::AckRxDone != 0 {
424 trace!("EventAckRxDone");
425 }
426
427 if events & Event::AckTxDone != 0 {
428 trace!("EventAckTxDone");
429 next_operation();
430 }
431
432 if events & Event::TxAbort != 0 {
433 trace!("TxAbort");
434 abort_tx();
435 }
436
437 if events & Event::RxAbort != 0 {
438 trace!("RxAbort");
439 abort_rx();
440 }
441}
442
443fn freq_to_channel(freq: u8) -> u8 {
444 (freq - 3) / 5 + 11
445}
446
447fn will_auto_send_ack(frame: &[u8]) -> bool {
448 frame_is_ack_required(frame) && frame_get_version(frame) <= FRAME_VERSION_1 && tx_auto_ack()
449}
450
451fn should_send_enhanced_ack(frame: &[u8]) -> bool {
452 frame_is_ack_required(frame) && frame_get_version(frame) <= FRAME_VERSION_2 && tx_enhance_ack()
453}