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