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, deinit_radio_clocks, 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
107#[derive(Debug)]
113#[cfg_attr(feature = "defmt", derive(defmt::Format))]
114pub(crate) struct RadioClockGuard;
115
116impl Drop for RadioClockGuard {
117 fn drop(&mut self) {
118 enable_ieee802154(false);
119 deinit_radio_clocks();
120 }
121}
122
123pub(crate) fn esp_ieee802154_enable(
124 radio: IEEE802154<'_>,
125) -> (PhyClockGuard<'_>, PhyInitGuard<'_>, RadioClockGuard) {
126 init_radio_clocks();
127 let phy_clock_guard = esp_phy::enable_phy_clock();
128 enable_ieee802154(true);
129
130 let phy_init_guard = esp_phy::enable_phy();
131
132 esp_btbb_enable();
133 ieee802154_mac_init(radio);
134
135 info!("date={:x}", mac_date());
136 (phy_clock_guard, phy_init_guard, RadioClockGuard)
137}
138
139fn esp_btbb_enable() {
140 unsafe { bt_bb_v2_init_cmplx(PHY_ENABLE_VERSION_PRINT) };
141}
142
143fn ieee802154_mac_init(radio: IEEE802154<'_>) {
144 #[cfg(soc_has_wifi)]
145 unsafe {
146 unsafe extern "C" {
147 static mut coex_pti_tab_ptr: u32;
148 static coex_pti_tab: u8;
149 }
150
151 core::ptr::addr_of_mut!(coex_pti_tab_ptr).write_volatile(&coex_pti_tab as *const _ as u32);
153 }
154
155 ieee802154_pib_init();
156
157 enable_events(Event::mask());
158 disable_events(Event::Timer0Overflow | Event::Timer1Overflow);
159
160 enable_tx_abort_events(
161 TxAbortReason::RxAckTimeout
162 | TxAbortReason::TxCoexBreak
163 | TxAbortReason::TxSecurityError
164 | TxAbortReason::CcaFailed
165 | TxAbortReason::CcaBusy,
166 );
167 enable_rx_abort_events(RxAbortReason::TxAckTimeout | RxAbortReason::TxAckCoexBreak);
168
169 set_ed_sample_mode(EdSampleMode::Avg);
170
171 unsafe { esp_coex_ieee802154_ack_pti_set(ieee802154_coex_event_t_IEEE802154_MIDDLE) };
172 ieee802154_set_txrx_pti(Ieee802154TxRxScene::Idle);
173
174 unsafe {
175 bt_bb_set_zb_tx_on_delay(50); }
177 set_rx_on_delay(50);
178
179 radio.bind_mac_interrupt(zb_mac_handler);
183}
184
185fn ieee802154_set_txrx_pti(txrx_scene: Ieee802154TxRxScene) {
186 match txrx_scene {
187 Ieee802154TxRxScene::Idle => {
188 unsafe { esp_coex_ieee802154_txrx_pti_set(ieee802154_coex_event_t_IEEE802154_IDLE) };
189 }
190 Ieee802154TxRxScene::Tx | Ieee802154TxRxScene::Rx => {
191 unsafe { esp_coex_ieee802154_txrx_pti_set(ieee802154_coex_event_t_IEEE802154_LOW) };
192 }
193 Ieee802154TxRxScene::TxAt | Ieee802154TxRxScene::RxAt => {
194 unsafe { esp_coex_ieee802154_txrx_pti_set(ieee802154_coex_event_t_IEEE802154_MIDDLE) };
195 }
196 }
197}
198
199fn tx_init(state: &mut IeeeState, frame: *const u8) {
200 stop_current_operation_inner(state);
201
202 ieee802154_pib_update();
203 set_transmit_security(false);
204
205 state.ack_frame = None;
206
207 set_tx_addr(frame);
208
209 if frame_is_ack_required(unsafe { core::slice::from_raw_parts(frame.add(1), *frame as usize) })
210 {
211 set_next_rx_buffer();
213 }
214}
215
216pub(crate) fn set_queue_size(rx_queue_size: usize) {
217 STATE.with(|state| {
218 state.rx_queue_size = rx_queue_size;
219 });
220}
221
222static mut TX_FRAME: *const u8 = core::ptr::null();
224
225pub fn ieee802154_transmit(frame: *const u8, cca: bool) -> i32 {
226 STATE.with(|state| {
227 if state.state == Ieee802154State::TxAck
230 || state.state == Ieee802154State::TxEnhAck
231 || (state.state == Ieee802154State::Receive && is_current_rx_frame())
232 {
233 state.pending_tx = Some(PendingTx { frame, cca });
236 enable_rx_abort_events(RxAbortReason::all());
237 return;
238 }
239
240 state.pending_tx = None;
241 transmit_internal(state, frame, cca);
242 });
243
244 0 }
246
247fn transmit_internal(state: &mut IeeeState, frame: *const u8, cca: bool) {
248 unsafe { TX_FRAME = frame };
249
250 tx_init(state, frame);
251
252 ieee802154_set_txrx_pti(Ieee802154TxRxScene::Tx);
253
254 if cca {
255 set_cmd(Command::CcaTxStart);
256 } else {
257 set_cmd(Command::TxStart);
258 }
259 state.state = Ieee802154State::Transmit;
260}
261
262pub fn ieee802154_receive() -> i32 {
263 STATE.with(|state| {
264 if state.state == Ieee802154State::Receive || state.state == Ieee802154State::TxAck {
265 return;
267 }
268
269 rx_init(state);
270 enable_rx();
271
272 state.state = Ieee802154State::Receive;
273 });
274
275 0 }
277
278pub fn ieee802154_poll() -> Option<RawReceived> {
279 STATE.with(|state| state.rx_queue.pop_front())
280}
281
282pub fn get_ack_frame() -> Option<RawReceived> {
287 STATE.with(|state| state.ack_frame)
288}
289
290fn rx_init(state: &mut IeeeState) {
291 stop_current_operation_inner(state);
292 ieee802154_pib_update();
293}
294
295fn enable_rx() {
296 set_next_rx_buffer();
297 ieee802154_set_txrx_pti(Ieee802154TxRxScene::Rx);
298
299 set_cmd(Command::RxStart);
300
301 }
303
304fn stop_current_operation_inner(state: &mut IeeeState) {
305 event_end_process();
306 match state.state {
307 Ieee802154State::Idle => {
308 set_cmd(Command::Stop);
309 }
310 Ieee802154State::Receive => {
311 stop_rx(state);
312 }
313 Ieee802154State::TxAck => {
314 stop_tx_ack();
315 }
316 Ieee802154State::Transmit | Ieee802154State::TxEnhAck => {
317 stop_tx(state);
318 }
319 Ieee802154State::RxAck => {
320 stop_rx_ack(state);
321 }
322 }
323}
324
325fn stop_rx(state: &mut IeeeState) {
326 set_cmd(Command::Stop);
327
328 let evts = events();
329 if evts & Event::RxDone != 0 {
330 receive_done(state);
331 }
332
333 clear_events(Event::RxDone | Event::RxAbort | Event::RxSfdDone);
334}
335
336fn stop_tx_ack() {
337 set_cmd(Command::Stop);
338
339 clear_events(Event::AckTxDone | Event::RxAbort | Event::TxSfdDone);
343}
344
345fn stop_tx(state: &mut IeeeState) {
346 set_cmd(Command::Stop);
347
348 let evts = events();
349
350 if state.state == Ieee802154State::TxEnhAck {
351 clear_events(Event::AckTxDone as u16);
353 } else if (evts & Event::TxDone != 0)
354 && (!frame_is_ack_required(unsafe {
355 core::slice::from_raw_parts(TX_FRAME.add(1), *TX_FRAME as usize)
356 }) || !rx_auto_ack())
357 {
358 super::tx_done();
360 } else {
361 super::tx_failed();
362 }
363
364 clear_events(Event::TxDone | Event::TxAbort | Event::TxSfdDone);
365}
366
367fn stop_rx_ack(state: &mut IeeeState) {
368 set_cmd(Command::Stop);
369
370 let evts = events();
371
372 timer0_stop();
373 disable_events(Event::Timer0Overflow as u16);
374
375 if evts & Event::AckRxDone != 0 {
376 state.ack_frame = Some(RawReceived {
378 data: unsafe { RX_BUFFER },
379 channel: freq_to_channel(freq()),
380 });
381 super::tx_done();
382 } else {
383 super::tx_failed();
384 }
385
386 clear_events(Event::AckRxDone | Event::RxSfdDone | Event::TxAbort);
387}
388
389fn receive_done(state: &mut IeeeState) {
390 unsafe {
391 if state.rx_queue.len() < state.rx_queue_size {
392 let item = RawReceived {
393 data: RX_BUFFER,
394 channel: freq_to_channel(freq()),
395 };
396 state.rx_queue.push_back(item);
397 } else {
398 warn!("Receive queue full");
399 }
400 }
401}
402
403fn set_next_rx_buffer() {
404 set_rx_addr(core::ptr::addr_of_mut!(RX_BUFFER).cast());
405}
406
407pub fn set_promiscuous(enable: bool) {
408 ieee802154_pib_set_promiscuous(enable);
409}
410
411pub fn set_auto_ack_tx(enable: bool) {
412 ieee802154_pib_set_auto_ack_tx(enable);
413}
414
415pub fn set_auto_ack_rx(enable: bool) {
416 ieee802154_pib_set_auto_ack_rx(enable);
417}
418
419pub fn set_enhance_ack_tx(enable: bool) {
420 ieee802154_pib_set_enhance_ack_tx(enable);
421}
422
423pub fn set_coordinator(enable: bool) {
424 ieee802154_pib_set_coordinator(enable);
425}
426
427pub fn set_rx_when_idle(enable: bool) {
428 ieee802154_pib_set_rx_when_idle(enable);
429}
430
431pub fn set_tx_power(power: i8) {
432 ieee802154_pib_set_tx_power(power);
433}
434
435pub fn set_channel(channel: u8) {
436 ieee802154_pib_set_channel(channel);
437}
438
439#[allow(unused)]
440pub fn set_pending_mode(mode: PendingMode) {
441 ieee802154_pib_set_pending_mode(mode);
442}
443
444#[allow(unused)]
445pub fn set_multipan_enable(mask: u8) {
446 set_multipan_enable_mask(mask);
447}
448
449pub fn set_short_address(index: u8, address: u16) {
450 ieee802154_pib_set_short_address(index, address);
451}
452
453pub fn set_extended_address(index: u8, address: [u8; IEEE802154_FRAME_EXT_ADDR_SIZE]) {
454 ieee802154_pib_set_extended_address(index, address);
455}
456
457pub fn set_cca_theshold(cca_threshold: i8) {
458 ieee802154_pib_set_cca_theshold(cca_threshold);
459}
460
461pub fn set_cca_mode(mode: CcaMode) {
462 ieee802154_pib_set_cca_mode(mode);
463}
464
465pub fn set_panid(index: u8, id: u16) {
466 ieee802154_pib_set_panid(index, id);
467}
468
469#[inline(always)]
472fn event_end_process() {
473 set_transmit_security(false);
474 timer0_stop();
475 }
477
478fn next_operation_inner(state: &mut IeeeState) {
479 state.state = Ieee802154State::Idle;
484
485 if let Some(pending) = state.pending_tx.take() {
486 disable_rx_abort_events(RxAbortReason::all());
488 enable_rx_abort_events(RxAbortReason::TxAckTimeout | RxAbortReason::TxAckCoexBreak);
489 clear_events(Event::RxAbort as u16);
491 transmit_internal(state, pending.frame, pending.cca);
492 } else if ieee802154_pib_get_rx_when_idle() {
493 enable_rx();
494 state.state = Ieee802154State::Receive;
495 }
496 }
498
499fn next_operation() {
500 STATE.with(next_operation_inner);
501}
502
503pub(crate) fn ensure_receive_enabled() {
505 STATE.with(|state| {
508 if state.state == Ieee802154State::Receive {
509 set_cmd(Command::RxStart);
510 }
511 });
512}
513
514#[handler(priority = Priority::Priority1)]
515fn zb_mac_handler() {
516 trace!("ZB_MAC interrupt");
517
518 let events = events();
519 let rx_abort_reason = get_rx_abort_reason();
520 let tx_abort_reason = get_tx_abort_reason();
521
522 clear_events(events);
523
524 trace!("events = {:032b}", events);
525
526 let mut needs_next_operation = false;
527
528 if events & Event::RxAbort != 0 {
530 trace!("RxAbort phase 1");
531 isr_handle_rx_phase_rx_abort(rx_abort_reason, &mut needs_next_operation);
532 }
533
534 if events & Event::RxSfdDone != 0 {
535 trace!("rx sfd done");
536 }
537
538 if events & Event::TxSfdDone != 0 {
539 trace!("tx sfd done");
540 }
541
542 if events & Event::TxDone != 0 {
543 trace!("tx done");
544 isr_handle_tx_done(&mut needs_next_operation);
545 }
546
547 if events & Event::RxDone != 0 {
548 trace!("rx done");
549 isr_handle_rx_done(&mut needs_next_operation);
550 }
551
552 if events & Event::AckTxDone != 0 {
553 trace!("AckTxDone");
554 isr_handle_ack_tx_done(&mut needs_next_operation);
555 }
556
557 if events & Event::AckRxDone != 0 {
558 trace!("AckRxDone");
559 isr_handle_ack_rx_done(&mut needs_next_operation);
560 }
561
562 if events & Event::RxAbort != 0 {
564 trace!("RxAbort phase 2");
565 isr_handle_tx_ack_phase_rx_abort(rx_abort_reason, &mut needs_next_operation);
566 }
567
568 if events & Event::TxAbort != 0 {
569 trace!("TxAbort");
570 isr_handle_tx_abort(tx_abort_reason, &mut needs_next_operation);
571 }
572
573 if events & Event::Timer0Overflow != 0 {
574 trace!("Timer0Overflow");
575 isr_handle_timer0_done(&mut needs_next_operation);
576 }
577
578 if needs_next_operation {
579 next_operation();
580 }
581}
582
583fn isr_handle_tx_done(needs_next_op: &mut bool) {
585 event_end_process();
586
587 STATE.with(|state| {
588 if state.state == Ieee802154State::Transmit {
589 let tx_frame = unsafe { TX_FRAME };
590 let frame_data =
591 unsafe { core::slice::from_raw_parts(tx_frame.add(1), *tx_frame as usize) };
592
593 if frame_is_ack_required(frame_data) && rx_auto_ack() {
594 state.state = Ieee802154State::RxAck;
596 receive_ack_timeout_timer_start(ACK_TIMEOUT_US);
597 *needs_next_op = false;
598 } else {
599 super::tx_done();
601 *needs_next_op = true;
602 }
603 }
604 });
605}
606
607fn isr_handle_rx_done(needs_next_op: &mut bool) {
609 event_end_process();
610 unsafe {
611 trace!(
612 "Received raw {:?}",
613 crate::fmt::Bytes(&*core::ptr::addr_of!(RX_BUFFER))
614 );
615
616 STATE.with(|state| {
617 let frm = if RX_BUFFER[0] >= FRAME_SIZE as u8 {
618 warn!("RX_BUFFER[0] {} is larger than frame size", RX_BUFFER[0]);
619 &RX_BUFFER[1..][..FRAME_SIZE - 1]
620 } else {
621 &RX_BUFFER[1..][..RX_BUFFER[0] as usize]
622 };
623
624 receive_done(state);
629
630 if will_auto_send_ack(frm) {
631 ack_config_pending_bit(frm);
635 state.state = Ieee802154State::TxAck;
636 *needs_next_op = false;
637 } else if should_send_enhanced_ack(frm) {
638 state.state = Ieee802154State::TxEnhAck;
641 *needs_next_op = false;
642 } else {
643 super::rx_available();
645 *needs_next_op = true;
646 }
647 });
648 }
649}
650
651fn isr_handle_ack_tx_done(needs_next_op: &mut bool) {
653 super::rx_available();
656 *needs_next_op = true;
657}
658
659fn isr_handle_ack_rx_done(needs_next_op: &mut bool) {
661 timer0_stop();
662 disable_events(Event::Timer0Overflow as u16);
663 STATE.with(|state| {
665 state.ack_frame = Some(RawReceived {
666 data: unsafe { RX_BUFFER },
667 channel: freq_to_channel(freq()),
668 });
669 });
670 super::tx_done();
672 *needs_next_op = true;
673}
674
675fn isr_handle_rx_phase_rx_abort(rx_abort_reason: u32, needs_next_op: &mut bool) {
678 event_end_process();
679 match rx_abort_reason {
680 r if r == RxAbortReason::RxStop as u32
682 || r == RxAbortReason::TxAckStop as u32
683 || r == RxAbortReason::EdStop as u32 => {}
684
685 r if r == RxAbortReason::SfdTimeout as u32
687 || r == RxAbortReason::CrcError as u32
688 || r == RxAbortReason::InvalidLen as u32
689 || r == RxAbortReason::FilterFail as u32
690 || r == RxAbortReason::NoRss as u32
691 || r == RxAbortReason::UnexpectedAck as u32
692 || r == RxAbortReason::RxRestart as u32
693 || r == RxAbortReason::CoexBreak as u32 =>
694 {
695 *needs_next_op = true;
696 }
697 r if r == RxAbortReason::TxAckTimeout as u32
699 || r == RxAbortReason::TxAckCoexBreak as u32
700 || r == RxAbortReason::EnhackSecurityError as u32 => {}
701
702 _ => {
703 warn!("Unexpected rx abort reason: {}", rx_abort_reason);
704 *needs_next_op = true;
705 }
706 }
707}
708
709fn isr_handle_tx_ack_phase_rx_abort(rx_abort_reason: u32, needs_next_op: &mut bool) {
712 event_end_process();
713
714 match rx_abort_reason {
715 r if r == RxAbortReason::TxAckStop as u32
717 || r == RxAbortReason::RxStop as u32
718 || r == RxAbortReason::EdStop as u32
719 || r == RxAbortReason::SfdTimeout as u32
720 || r == RxAbortReason::CrcError as u32
721 || r == RxAbortReason::InvalidLen as u32
722 || r == RxAbortReason::FilterFail as u32
723 || r == RxAbortReason::NoRss as u32
724 || r == RxAbortReason::UnexpectedAck as u32
725 || r == RxAbortReason::RxRestart as u32
726 || r == RxAbortReason::CoexBreak as u32
727 || r == RxAbortReason::EdAbort as u32
728 || r == RxAbortReason::EdCoexReject as u32 => {}
729
730 r if r == RxAbortReason::TxAckTimeout as u32
732 || r == RxAbortReason::TxAckCoexBreak as u32 =>
733 {
734 super::rx_available();
736 *needs_next_op = true;
737 }
738 r if r == RxAbortReason::EnhackSecurityError as u32 => {
740 super::rx_available();
742 *needs_next_op = true;
743 }
744 _ => {
745 warn!(
746 "Unexpected rx abort reason in tx_ack phase: {}",
747 rx_abort_reason
748 );
749 }
750 }
751}
752
753fn isr_handle_timer0_done(needs_next_op: &mut bool) {
756 timer0_stop();
758 disable_events(Event::Timer0Overflow as u16);
759 super::tx_failed();
760 *needs_next_op = true;
761}
762
763fn isr_handle_tx_abort(tx_abort_reason: u32, needs_next_op: &mut bool) {
765 event_end_process();
766
767 match tx_abort_reason {
768 r if r == TxAbortReason::RxAckStop as u32 || r == TxAbortReason::TxStop as u32 => {
770 }
772 r if r == TxAbortReason::RxAckSfdTimeout as u32
774 || r == TxAbortReason::RxAckCrcError as u32
775 || r == TxAbortReason::RxAckInvalidLen as u32
776 || r == TxAbortReason::RxAckFilterFail as u32
777 || r == TxAbortReason::RxAckNoRss as u32
778 || r == TxAbortReason::RxAckCoexBreak as u32
779 || r == TxAbortReason::RxAckTypeNotAck as u32
780 || r == TxAbortReason::RxAckRestart as u32 =>
781 {
782 super::tx_failed();
783 *needs_next_op = true;
784 }
785 r if r == TxAbortReason::RxAckTimeout as u32 => {
787 timer0_stop();
788 disable_events(Event::Timer0Overflow as u16);
789 super::tx_failed();
790 *needs_next_op = true;
791 }
792 r if r == TxAbortReason::TxCoexBreak as u32 => {
794 unsafe { esp_coex_ieee802154_coex_break_notify() };
795 super::tx_failed();
796 *needs_next_op = true;
797 }
798 r if r == TxAbortReason::TxSecurityError as u32 => {
800 super::tx_failed();
801 *needs_next_op = true;
802 }
803 r if r == TxAbortReason::CcaFailed as u32 => {
805 super::tx_failed();
806 *needs_next_op = true;
807 }
808 r if r == TxAbortReason::CcaBusy as u32 => {
810 super::tx_failed();
811 *needs_next_op = true;
812 }
813 _ => {
814 warn!("Unexpected tx abort reason: {}", tx_abort_reason);
815 }
816 }
817}
818
819fn freq_to_channel(freq: u8) -> u8 {
820 (freq - 3) / 5 + 11
821}
822
823fn ack_config_pending_bit(frame: &[u8]) {
828 if frame_get_version(frame) <= FRAME_VERSION_1 {
831 set_pending_bit(true);
836 }
837}
838
839fn will_auto_send_ack(frame: &[u8]) -> bool {
840 frame_is_ack_required(frame) && frame_get_version(frame) <= FRAME_VERSION_1 && tx_auto_ack()
841}
842
843fn should_send_enhanced_ack(frame: &[u8]) -> bool {
844 frame_is_ack_required(frame) && frame_get_version(frame) <= FRAME_VERSION_2 && tx_enhance_ack()
845}
846
847fn receive_ack_timeout_timer_start(duration: u32) {
850 enable_events(Event::Timer0Overflow as u16);
851 timer0_set_threshold(duration);
852 timer0_start();
853}