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