esp_ieee802154/
raw.rs

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); // from libbtbb.a
37
38    fn bt_bb_set_zb_tx_on_delay(time: u16); // from libbtbb.a
39
40    fn esp_coex_ieee802154_ack_pti_set(event: ieee802154_coex_event_t); // from ???
41
42    fn esp_coex_ieee802154_txrx_pti_set(event: ieee802154_coex_event_t); // from ???
43
44    fn phy_version_print(); // from libphy.a
45}
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/// A raw payload received on some channel
66#[derive(Debug, Clone, Copy, PartialEq, Eq)]
67pub struct RawReceived {
68    /// Payload
69    pub data: [u8; FRAME_SIZE],
70    /// Receiver channel
71    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() }; // libphy.a
85    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        // Manually set `coex_pti_tab_ptr` pointing to `coex_pti_tab`
117        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); // set tx on delay for libbtbb.a
144    }
145    set_rx_on_delay(50);
146
147    // memset(s_rx_frame, 0, sizeof(s_rx_frame));
148    // s_ieee802154_state = IEEE802154_STATE_IDLE;
149
150    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    // ieee802154_frame_is_ack_required(frame)
183    {
184        // set rx pointer for ack frame
185        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            // disable_events(IEEE802154_EVENT_ED_DONE);
197            // set_cmd(IEEE802154_CMD_CCA_TX_START);
198            // ieee802154_state = IEEE802154_STATE_TX_CCA;
199        } else {
200            set_cmd(Command::TxStart);
201            // if (ieee802154_frame_get_type(frame) == IEEE802154_FRAME_TYPE_ACK
202            //     && ieee802154_frame_get_version(frame) == IEEE802154_FRAME_VERSION_2)
203            // {
204            //     ieee802154_state = IEEE802154_STATE_TX_ENH_ACK;
205            // } else {
206            *STATE.borrow_ref_mut(cs) = Ieee802154State::Transmit;
207            // }
208        }
209    });
210
211    0 // ESP_OK
212}
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 // ESP-OK
227}
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    // ieee802154_state = IEEE802154_STATE_RX;
248}
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)] // stable compiler needs unsafe, nightly complains about it
258    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    // ieee802154_sec_clr_transmit_security();
330}
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        // IEEE802154_STATE_TX && IEEE802154_STATE_TX_CCA && IEEE802154_STATE_TX_ENH_ACK
365        // for isr processing delay
366        trace!("rx sfd done");
367    }
368
369    if events & Event::TxSfdDone != 0 {
370        // IEEE802154_STATE_RX for isr processing delay, only 821
371        // IEEE802154_STATE_TX_ACK for workaround jira ZB-81.
372        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                    // TODO
409                } else {
410                    // esp_ieee802154_coex_pti_set(IEEE802154_IDLE_RX);
411                    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}