1use alloc::collections::VecDeque as Queue;
2
3use esp_hal::{handler, interrupt::Priority, peripherals::IEEE802154};
4use esp_phy::{PhyClockGuard, PhyInitGuard};
5use esp_sync::NonReentrantMutex;
6
7use super::{
8 frame::{
9 FRAME_SIZE,
10 FRAME_VERSION_1,
11 FRAME_VERSION_2,
12 frame_get_version,
13 frame_is_ack_required,
14 },
15 hal::*,
16 pib::*,
17};
18use crate::{
19 radio_clocks::{clocks_ll::enable_ieee802154, init_radio_clocks},
20 sys::include::{
21 ieee802154_coex_event_t,
22 ieee802154_coex_event_t_IEEE802154_IDLE,
23 ieee802154_coex_event_t_IEEE802154_LOW,
24 ieee802154_coex_event_t_IEEE802154_MIDDLE,
25 },
26};
27
28const PHY_ENABLE_VERSION_PRINT: u8 = 1;
29
30const ACK_TIMEOUT_US: u32 = 200_000;
33
34static mut RX_BUFFER: [u8; FRAME_SIZE] = [0u8; FRAME_SIZE];
35
36struct PendingTx {
37 frame: *const u8,
38 cca: bool,
39}
40
41unsafe impl Send for PendingTx {}
44
45struct IeeeState {
46 state: Ieee802154State,
47 rx_queue: Queue<RawReceived>,
48 rx_queue_size: usize,
49 pending_tx: Option<PendingTx>,
50 ack_frame: Option<RawReceived>,
54}
55
56static STATE: NonReentrantMutex<IeeeState> = NonReentrantMutex::new(IeeeState {
57 state: Ieee802154State::Idle,
58 rx_queue: Queue::new(),
59 rx_queue_size: 10,
60 pending_tx: None,
61 ack_frame: None,
62});
63
64unsafe extern "C" {
65 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); fn esp_coex_ieee802154_coex_break_notify(); }
75
76#[derive(Debug, Clone, Copy, PartialEq)]
77enum Ieee802154State {
78 Idle,
79 Receive,
80 Transmit,
81 TxAck,
82 RxAck,
83 TxEnhAck,
84}
85
86#[allow(unused)]
87#[derive(Debug, Clone, Copy, PartialEq)]
88enum Ieee802154TxRxScene {
89 Idle,
90 Tx,
91 Rx,
92 TxAt,
93 RxAt,
94}
95
96#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
98#[cfg_attr(feature = "defmt", derive(defmt::Format))]
99#[instability::unstable]
100pub struct RawReceived {
101 pub data: [u8; FRAME_SIZE],
103 pub channel: u8,
105}
106
107pub(crate) fn esp_ieee802154_enable(
108 radio: IEEE802154<'_>,
109) -> (PhyClockGuard<'_>, PhyInitGuard<'_>) {
110 init_radio_clocks();
111 let phy_clock_guard = esp_phy::enable_phy_clock();
112 enable_ieee802154(true);
113
114 let phy_init_guard = esp_phy::enable_phy();
115
116 esp_btbb_enable();
117 ieee802154_mac_init(radio);
118
119 info!("date={:x}", mac_date());
120 (phy_clock_guard, phy_init_guard)
121}
122
123fn esp_btbb_enable() {
124 unsafe { bt_bb_v2_init_cmplx(PHY_ENABLE_VERSION_PRINT) };
125}
126
127fn ieee802154_mac_init(radio: IEEE802154<'_>) {
128 #[cfg(any(esp32c6, esp32c5))]
129 unsafe {
130 unsafe extern "C" {
131 static mut coex_pti_tab_ptr: u32;
132 static coex_pti_tab: u8;
133 }
134
135 core::ptr::addr_of_mut!(coex_pti_tab_ptr).write_volatile(&coex_pti_tab as *const _ as u32);
137 }
138
139 ieee802154_pib_init();
140
141 enable_events(Event::mask());
142 disable_events(Event::Timer0Overflow | Event::Timer1Overflow);
143
144 enable_tx_abort_events(
145 TxAbortReason::RxAckTimeout
146 | TxAbortReason::TxCoexBreak
147 | TxAbortReason::TxSecurityError
148 | TxAbortReason::CcaFailed
149 | TxAbortReason::CcaBusy,
150 );
151 enable_rx_abort_events(RxAbortReason::TxAckTimeout | RxAbortReason::TxAckCoexBreak);
152
153 set_ed_sample_mode(EdSampleMode::Avg);
154
155 unsafe { esp_coex_ieee802154_ack_pti_set(ieee802154_coex_event_t_IEEE802154_MIDDLE) };
156 ieee802154_set_txrx_pti(Ieee802154TxRxScene::Idle);
157
158 unsafe {
159 bt_bb_set_zb_tx_on_delay(50); }
161 set_rx_on_delay(50);
162
163 radio.bind_mac_interrupt(zb_mac_handler);
167}
168
169fn ieee802154_set_txrx_pti(txrx_scene: Ieee802154TxRxScene) {
170 match txrx_scene {
171 Ieee802154TxRxScene::Idle => {
172 unsafe { esp_coex_ieee802154_txrx_pti_set(ieee802154_coex_event_t_IEEE802154_IDLE) };
173 }
174 Ieee802154TxRxScene::Tx | Ieee802154TxRxScene::Rx => {
175 unsafe { esp_coex_ieee802154_txrx_pti_set(ieee802154_coex_event_t_IEEE802154_LOW) };
176 }
177 Ieee802154TxRxScene::TxAt | Ieee802154TxRxScene::RxAt => {
178 unsafe { esp_coex_ieee802154_txrx_pti_set(ieee802154_coex_event_t_IEEE802154_MIDDLE) };
179 }
180 }
181}
182
183fn tx_init(state: &mut IeeeState, frame: *const u8) {
184 stop_current_operation_inner(state);
185
186 ieee802154_pib_update();
187 set_transmit_security(false);
188
189 state.ack_frame = None;
190
191 set_tx_addr(frame);
192
193 if frame_is_ack_required(unsafe { core::slice::from_raw_parts(frame.add(1), *frame as usize) })
194 {
195 set_next_rx_buffer();
197 }
198}
199
200pub(crate) fn set_queue_size(rx_queue_size: usize) {
201 STATE.with(|state| {
202 state.rx_queue_size = rx_queue_size;
203 });
204}
205
206static mut TX_FRAME: *const u8 = core::ptr::null();
208
209pub fn ieee802154_transmit(frame: *const u8, cca: bool) -> i32 {
210 STATE.with(|state| {
211 if state.state == Ieee802154State::TxAck
214 || state.state == Ieee802154State::TxEnhAck
215 || (state.state == Ieee802154State::Receive && is_current_rx_frame())
216 {
217 state.pending_tx = Some(PendingTx { frame, cca });
220 enable_rx_abort_events(RxAbortReason::all());
221 return;
222 }
223
224 state.pending_tx = None;
225 transmit_internal(state, frame, cca);
226 });
227
228 0 }
230
231fn transmit_internal(state: &mut IeeeState, frame: *const u8, cca: bool) {
232 unsafe { TX_FRAME = frame };
233
234 tx_init(state, frame);
235
236 ieee802154_set_txrx_pti(Ieee802154TxRxScene::Tx);
237
238 if cca {
239 set_cmd(Command::CcaTxStart);
240 } else {
241 set_cmd(Command::TxStart);
242 }
243 state.state = Ieee802154State::Transmit;
244}
245
246pub fn ieee802154_receive() -> i32 {
247 STATE.with(|state| {
248 if state.state == Ieee802154State::Receive || state.state == Ieee802154State::TxAck {
249 return;
251 }
252
253 rx_init(state);
254 enable_rx();
255
256 state.state = Ieee802154State::Receive;
257 });
258
259 0 }
261
262pub fn ieee802154_poll() -> Option<RawReceived> {
263 STATE.with(|state| state.rx_queue.pop_front())
264}
265
266pub fn get_ack_frame() -> Option<RawReceived> {
271 STATE.with(|state| state.ack_frame)
272}
273
274fn rx_init(state: &mut IeeeState) {
275 stop_current_operation_inner(state);
276 ieee802154_pib_update();
277}
278
279fn enable_rx() {
280 set_next_rx_buffer();
281 ieee802154_set_txrx_pti(Ieee802154TxRxScene::Rx);
282
283 set_cmd(Command::RxStart);
284
285 }
287
288fn stop_current_operation_inner(state: &mut IeeeState) {
289 event_end_process();
290 match state.state {
291 Ieee802154State::Idle => {
292 set_cmd(Command::Stop);
293 }
294 Ieee802154State::Receive => {
295 stop_rx(state);
296 }
297 Ieee802154State::TxAck => {
298 stop_tx_ack();
299 }
300 Ieee802154State::Transmit | Ieee802154State::TxEnhAck => {
301 stop_tx(state);
302 }
303 Ieee802154State::RxAck => {
304 stop_rx_ack(state);
305 }
306 }
307}
308
309fn stop_rx(state: &mut IeeeState) {
310 set_cmd(Command::Stop);
311
312 let evts = events();
313 if evts & Event::RxDone != 0 {
314 receive_done(state);
315 }
316
317 clear_events(Event::RxDone | Event::RxAbort | Event::RxSfdDone);
318}
319
320fn stop_tx_ack() {
321 set_cmd(Command::Stop);
322
323 clear_events(Event::AckTxDone | Event::RxAbort | Event::TxSfdDone);
327}
328
329fn stop_tx(state: &mut IeeeState) {
330 set_cmd(Command::Stop);
331
332 let evts = events();
333
334 if state.state == Ieee802154State::TxEnhAck {
335 clear_events(Event::AckTxDone as u16);
337 } else if (evts & Event::TxDone != 0)
338 && (!frame_is_ack_required(unsafe {
339 core::slice::from_raw_parts(TX_FRAME.add(1), *TX_FRAME as usize)
340 }) || !rx_auto_ack())
341 {
342 super::tx_done();
344 } else {
345 super::tx_failed();
346 }
347
348 clear_events(Event::TxDone | Event::TxAbort | Event::TxSfdDone);
349}
350
351fn stop_rx_ack(state: &mut IeeeState) {
352 set_cmd(Command::Stop);
353
354 let evts = events();
355
356 timer0_stop();
357 disable_events(Event::Timer0Overflow as u16);
358
359 if evts & Event::AckRxDone != 0 {
360 state.ack_frame = Some(RawReceived {
362 data: unsafe { RX_BUFFER },
363 channel: freq_to_channel(freq()),
364 });
365 super::tx_done();
366 } else {
367 super::tx_failed();
368 }
369
370 clear_events(Event::AckRxDone | Event::RxSfdDone | Event::TxAbort);
371}
372
373fn receive_done(state: &mut IeeeState) {
374 unsafe {
375 if state.rx_queue.len() < state.rx_queue_size {
376 let item = RawReceived {
377 data: RX_BUFFER,
378 channel: freq_to_channel(freq()),
379 };
380 state.rx_queue.push_back(item);
381 } else {
382 warn!("Receive queue full");
383 }
384 }
385}
386
387fn set_next_rx_buffer() {
388 set_rx_addr(core::ptr::addr_of_mut!(RX_BUFFER).cast());
389}
390
391pub fn set_promiscuous(enable: bool) {
392 ieee802154_pib_set_promiscuous(enable);
393}
394
395pub fn set_auto_ack_tx(enable: bool) {
396 ieee802154_pib_set_auto_ack_tx(enable);
397}
398
399pub fn set_auto_ack_rx(enable: bool) {
400 ieee802154_pib_set_auto_ack_rx(enable);
401}
402
403pub fn set_enhance_ack_tx(enable: bool) {
404 ieee802154_pib_set_enhance_ack_tx(enable);
405}
406
407pub fn set_coordinator(enable: bool) {
408 ieee802154_pib_set_coordinator(enable);
409}
410
411pub fn set_rx_when_idle(enable: bool) {
412 ieee802154_pib_set_rx_when_idle(enable);
413}
414
415pub fn set_tx_power(power: i8) {
416 ieee802154_pib_set_tx_power(power);
417}
418
419pub fn set_channel(channel: u8) {
420 ieee802154_pib_set_channel(channel);
421}
422
423#[allow(unused)]
424pub fn set_pending_mode(mode: PendingMode) {
425 ieee802154_pib_set_pending_mode(mode);
426}
427
428#[allow(unused)]
429pub fn set_multipan_enable(mask: u8) {
430 set_multipan_enable_mask(mask);
431}
432
433pub fn set_short_address(index: u8, address: u16) {
434 ieee802154_pib_set_short_address(index, address);
435}
436
437pub fn set_extended_address(index: u8, address: [u8; IEEE802154_FRAME_EXT_ADDR_SIZE]) {
438 ieee802154_pib_set_extended_address(index, address);
439}
440
441pub fn set_cca_theshold(cca_threshold: i8) {
442 ieee802154_pib_set_cca_theshold(cca_threshold);
443}
444
445pub fn set_cca_mode(mode: CcaMode) {
446 ieee802154_pib_set_cca_mode(mode);
447}
448
449pub fn set_panid(index: u8, id: u16) {
450 ieee802154_pib_set_panid(index, id);
451}
452
453#[inline(always)]
456fn event_end_process() {
457 set_transmit_security(false);
458 timer0_stop();
459 }
461
462fn next_operation_inner(state: &mut IeeeState) {
463 state.state = Ieee802154State::Idle;
468
469 if let Some(pending) = state.pending_tx.take() {
470 disable_rx_abort_events(RxAbortReason::all());
472 enable_rx_abort_events(RxAbortReason::TxAckTimeout | RxAbortReason::TxAckCoexBreak);
473 clear_events(Event::RxAbort as u16);
475 transmit_internal(state, pending.frame, pending.cca);
476 } else if ieee802154_pib_get_rx_when_idle() {
477 enable_rx();
478 state.state = Ieee802154State::Receive;
479 }
480 }
482
483fn next_operation() {
484 STATE.with(next_operation_inner);
485}
486
487pub(crate) fn ensure_receive_enabled() {
489 STATE.with(|state| {
492 if state.state == Ieee802154State::Receive {
493 set_cmd(Command::RxStart);
494 }
495 });
496}
497
498#[handler(priority = Priority::Priority1)]
499fn zb_mac_handler() {
500 trace!("ZB_MAC interrupt");
501
502 let events = events();
503 let rx_abort_reason = get_rx_abort_reason();
504 let tx_abort_reason = get_tx_abort_reason();
505
506 clear_events(events);
507
508 trace!("events = {:032b}", events);
509
510 let mut needs_next_operation = false;
511
512 if events & Event::RxAbort != 0 {
514 trace!("RxAbort phase 1");
515 isr_handle_rx_phase_rx_abort(rx_abort_reason, &mut needs_next_operation);
516 }
517
518 if events & Event::RxSfdDone != 0 {
519 trace!("rx sfd done");
520 }
521
522 if events & Event::TxSfdDone != 0 {
523 trace!("tx sfd done");
524 }
525
526 if events & Event::TxDone != 0 {
527 trace!("tx done");
528 isr_handle_tx_done(&mut needs_next_operation);
529 }
530
531 if events & Event::RxDone != 0 {
532 trace!("rx done");
533 isr_handle_rx_done(&mut needs_next_operation);
534 }
535
536 if events & Event::AckTxDone != 0 {
537 trace!("AckTxDone");
538 isr_handle_ack_tx_done(&mut needs_next_operation);
539 }
540
541 if events & Event::AckRxDone != 0 {
542 trace!("AckRxDone");
543 isr_handle_ack_rx_done(&mut needs_next_operation);
544 }
545
546 if events & Event::RxAbort != 0 {
548 trace!("RxAbort phase 2");
549 isr_handle_tx_ack_phase_rx_abort(rx_abort_reason, &mut needs_next_operation);
550 }
551
552 if events & Event::TxAbort != 0 {
553 trace!("TxAbort");
554 isr_handle_tx_abort(tx_abort_reason, &mut needs_next_operation);
555 }
556
557 if events & Event::Timer0Overflow != 0 {
558 trace!("Timer0Overflow");
559 isr_handle_timer0_done(&mut needs_next_operation);
560 }
561
562 if needs_next_operation {
563 next_operation();
564 }
565}
566
567fn isr_handle_tx_done(needs_next_op: &mut bool) {
569 event_end_process();
570
571 STATE.with(|state| {
572 if state.state == Ieee802154State::Transmit {
573 let tx_frame = unsafe { TX_FRAME };
574 let frame_data =
575 unsafe { core::slice::from_raw_parts(tx_frame.add(1), *tx_frame as usize) };
576
577 if frame_is_ack_required(frame_data) && rx_auto_ack() {
578 state.state = Ieee802154State::RxAck;
580 receive_ack_timeout_timer_start(ACK_TIMEOUT_US);
581 *needs_next_op = false;
582 } else {
583 super::tx_done();
585 *needs_next_op = true;
586 }
587 }
588 });
589}
590
591fn isr_handle_rx_done(needs_next_op: &mut bool) {
593 event_end_process();
594 unsafe {
595 trace!(
596 "Received raw {:?}",
597 crate::fmt::Bytes(&*core::ptr::addr_of!(RX_BUFFER))
598 );
599
600 STATE.with(|state| {
601 let frm = if RX_BUFFER[0] >= FRAME_SIZE as u8 {
602 warn!("RX_BUFFER[0] {} is larger than frame size", RX_BUFFER[0]);
603 &RX_BUFFER[1..][..FRAME_SIZE - 1]
604 } else {
605 &RX_BUFFER[1..][..RX_BUFFER[0] as usize]
606 };
607
608 receive_done(state);
613
614 if will_auto_send_ack(frm) {
615 state.state = Ieee802154State::TxAck;
619 *needs_next_op = false;
620 } else if should_send_enhanced_ack(frm) {
621 state.state = Ieee802154State::TxEnhAck;
624 *needs_next_op = false;
625 } else {
626 super::rx_available();
628 *needs_next_op = true;
629 }
630 });
631 }
632}
633
634fn isr_handle_ack_tx_done(needs_next_op: &mut bool) {
636 super::rx_available();
639 *needs_next_op = true;
640}
641
642fn isr_handle_ack_rx_done(needs_next_op: &mut bool) {
644 timer0_stop();
645 disable_events(Event::Timer0Overflow as u16);
646 STATE.with(|state| {
648 state.ack_frame = Some(RawReceived {
649 data: unsafe { RX_BUFFER },
650 channel: freq_to_channel(freq()),
651 });
652 });
653 super::tx_done();
655 *needs_next_op = true;
656}
657
658fn isr_handle_rx_phase_rx_abort(rx_abort_reason: u32, needs_next_op: &mut bool) {
661 event_end_process();
662 match rx_abort_reason {
663 r if r == RxAbortReason::RxStop as u32
665 || r == RxAbortReason::TxAckStop as u32
666 || r == RxAbortReason::EdStop as u32 => {}
667
668 r if r == RxAbortReason::SfdTimeout as u32
670 || r == RxAbortReason::CrcError as u32
671 || r == RxAbortReason::InvalidLen as u32
672 || r == RxAbortReason::FilterFail as u32
673 || r == RxAbortReason::NoRss as u32
674 || r == RxAbortReason::UnexpectedAck as u32
675 || r == RxAbortReason::RxRestart as u32
676 || r == RxAbortReason::CoexBreak as u32 =>
677 {
678 *needs_next_op = true;
679 }
680 r if r == RxAbortReason::TxAckTimeout as u32
682 || r == RxAbortReason::TxAckCoexBreak as u32
683 || r == RxAbortReason::EnhackSecurityError as u32 => {}
684
685 _ => {
686 warn!("Unexpected rx abort reason: {}", rx_abort_reason);
687 *needs_next_op = true;
688 }
689 }
690}
691
692fn isr_handle_tx_ack_phase_rx_abort(rx_abort_reason: u32, needs_next_op: &mut bool) {
695 event_end_process();
696
697 match rx_abort_reason {
698 r if r == RxAbortReason::TxAckStop as u32
700 || r == RxAbortReason::RxStop as u32
701 || r == RxAbortReason::EdStop as u32
702 || r == RxAbortReason::SfdTimeout as u32
703 || r == RxAbortReason::CrcError as u32
704 || r == RxAbortReason::InvalidLen as u32
705 || r == RxAbortReason::FilterFail as u32
706 || r == RxAbortReason::NoRss as u32
707 || r == RxAbortReason::UnexpectedAck as u32
708 || r == RxAbortReason::RxRestart as u32
709 || r == RxAbortReason::CoexBreak as u32
710 || r == RxAbortReason::EdAbort as u32
711 || r == RxAbortReason::EdCoexReject as u32 => {}
712
713 r if r == RxAbortReason::TxAckTimeout as u32
715 || r == RxAbortReason::TxAckCoexBreak as u32 =>
716 {
717 super::rx_available();
719 *needs_next_op = true;
720 }
721 r if r == RxAbortReason::EnhackSecurityError as u32 => {
723 super::rx_available();
725 *needs_next_op = true;
726 }
727 _ => {
728 warn!(
729 "Unexpected rx abort reason in tx_ack phase: {}",
730 rx_abort_reason
731 );
732 }
733 }
734}
735
736fn isr_handle_timer0_done(needs_next_op: &mut bool) {
739 timer0_stop();
741 disable_events(Event::Timer0Overflow as u16);
742 super::tx_failed();
743 *needs_next_op = true;
744}
745
746fn isr_handle_tx_abort(tx_abort_reason: u32, needs_next_op: &mut bool) {
748 event_end_process();
749
750 match tx_abort_reason {
751 r if r == TxAbortReason::RxAckStop as u32 || r == TxAbortReason::TxStop as u32 => {
753 }
755 r if r == TxAbortReason::RxAckSfdTimeout as u32
757 || r == TxAbortReason::RxAckCrcError as u32
758 || r == TxAbortReason::RxAckInvalidLen as u32
759 || r == TxAbortReason::RxAckFilterFail as u32
760 || r == TxAbortReason::RxAckNoRss as u32
761 || r == TxAbortReason::RxAckCoexBreak as u32
762 || r == TxAbortReason::RxAckTypeNotAck as u32
763 || r == TxAbortReason::RxAckRestart as u32 =>
764 {
765 super::tx_failed();
766 *needs_next_op = true;
767 }
768 r if r == TxAbortReason::RxAckTimeout as u32 => {
770 timer0_stop();
771 disable_events(Event::Timer0Overflow as u16);
772 super::tx_failed();
773 *needs_next_op = true;
774 }
775 r if r == TxAbortReason::TxCoexBreak as u32 => {
777 unsafe { esp_coex_ieee802154_coex_break_notify() };
778 super::tx_failed();
779 *needs_next_op = true;
780 }
781 r if r == TxAbortReason::TxSecurityError as u32 => {
783 super::tx_failed();
784 *needs_next_op = true;
785 }
786 r if r == TxAbortReason::CcaFailed as u32 => {
788 super::tx_failed();
789 *needs_next_op = true;
790 }
791 r if r == TxAbortReason::CcaBusy as u32 => {
793 super::tx_failed();
794 *needs_next_op = true;
795 }
796 _ => {
797 warn!("Unexpected tx abort reason: {}", tx_abort_reason);
798 }
799 }
800}
801
802fn freq_to_channel(freq: u8) -> u8 {
803 (freq - 3) / 5 + 11
804}
805
806fn will_auto_send_ack(frame: &[u8]) -> bool {
807 frame_is_ack_required(frame) && frame_get_version(frame) <= FRAME_VERSION_1 && tx_auto_ack()
808}
809
810fn should_send_enhanced_ack(frame: &[u8]) -> bool {
811 frame_is_ack_required(frame) && frame_get_version(frame) <= FRAME_VERSION_2 && tx_enhance_ack()
812}
813
814fn receive_ack_timeout_timer_start(duration: u32) {
817 enable_events(Event::Timer0Overflow as u16);
818 timer0_set_threshold(duration);
819 timer0_start();
820}