esp_ieee802154/
pib.rs

1use core::cell::RefCell;
2
3use critical_section::Mutex;
4
5use crate::hal::{
6    set_cca_mode,
7    set_cca_threshold,
8    set_coordinator,
9    set_freq,
10    set_multipan_enable_mask,
11    set_multipan_ext_addr,
12    set_multipan_panid,
13    set_multipan_short_addr,
14    set_pending_mode,
15    set_power,
16    set_promiscuous,
17    set_rx_auto_ack,
18    set_tx_auto_ack,
19    set_tx_enhance_ack,
20};
21
22pub(crate) const CONFIG_IEEE802154_CCA_THRESHOLD: i8 = -60;
23pub(crate) const IEEE802154_FRAME_EXT_ADDR_SIZE: usize = 8;
24
25const IEEE802154_MULTIPAN_0: u8 = 0;
26const IEEE802154_MULTIPAN_MAX: usize = 4;
27
28static PIB: Mutex<RefCell<Option<Pib>>> = Mutex::new(RefCell::new(None));
29
30/// Frame pending mode
31#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
32pub enum PendingMode {
33    /// Frame pending bit always set to 1 in the ack to Data Request
34    #[default]
35    Disable  = 0,
36    /// Frame pending bit set to 1 if src address matches, in the ack to Data
37    /// Request
38    Enable   = 1,
39    /// Frame pending bit set to 1 if src address matches, in all ack frames
40    Enhanced = 2,
41    /// Frame pending bit set to 0 only if src address is short address and
42    /// matches in table, in the ack to Data Request
43    Zigbee   = 3,
44}
45
46/// CCA mode
47#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
48pub enum CcaMode {
49    /// Carrier only
50    #[default]
51    Carrier      = 0x00,
52    /// Energy Detect only
53    Ed           = 0x01,
54    /// Carrier or Energy Detect
55    CarrierOrEd  = 0x02,
56    /// Carrier and Energy Detect
57    CarrierAndEd = 0x03,
58}
59
60#[derive(Debug, Default, Clone, Copy)]
61struct Pib {
62    auto_ack_tx: bool,
63    auto_ack_rx: bool,
64    enhance_ack_tx: bool,
65    promiscuous: bool,
66    coordinator: bool,
67    rx_when_idle: bool,
68    txpower: i8,
69    channel: u8,
70    pending_mode: PendingMode,
71    multipan_mask: u8,
72    panid: [u16; IEEE802154_MULTIPAN_MAX],
73    short_addr: [u16; IEEE802154_MULTIPAN_MAX],
74    ext_addr: [[u8; IEEE802154_FRAME_EXT_ADDR_SIZE]; IEEE802154_MULTIPAN_MAX],
75    cca_threshold: i8,
76    cca_mode: CcaMode,
77}
78
79pub(crate) fn ieee802154_pib_init() {
80    critical_section::with(|cs| {
81        PIB.borrow_ref_mut(cs).replace(Pib {
82            auto_ack_tx: true,
83            auto_ack_rx: true,
84            enhance_ack_tx: true,
85            coordinator: false,
86            promiscuous: true,
87            rx_when_idle: false,
88            txpower: 10,
89            channel: 11,
90            pending_mode: PendingMode::Disable,
91            multipan_mask: 1 << IEEE802154_MULTIPAN_0,
92            panid: [0u16; 4],
93            short_addr: [0u16; IEEE802154_MULTIPAN_MAX],
94            ext_addr: [[0xffu8; IEEE802154_FRAME_EXT_ADDR_SIZE]; IEEE802154_MULTIPAN_MAX],
95            cca_threshold: CONFIG_IEEE802154_CCA_THRESHOLD,
96            cca_mode: CcaMode::Ed,
97        });
98    });
99}
100
101pub(crate) fn ieee802154_pib_set_panid(index: u8, panid: u16) {
102    critical_section::with(|cs| {
103        PIB.borrow_ref_mut(cs).as_mut().unwrap().panid[index as usize] = panid;
104    });
105}
106
107pub(crate) fn ieee802154_pib_set_promiscuous(enable: bool) {
108    critical_section::with(|cs| {
109        PIB.borrow_ref_mut(cs).as_mut().unwrap().promiscuous = enable;
110    });
111}
112
113pub(crate) fn ieee802154_pib_set_auto_ack_tx(enable: bool) {
114    critical_section::with(|cs| {
115        PIB.borrow_ref_mut(cs).as_mut().unwrap().auto_ack_tx = enable;
116    });
117}
118
119pub(crate) fn ieee802154_pib_set_auto_ack_rx(enable: bool) {
120    critical_section::with(|cs| {
121        PIB.borrow_ref_mut(cs).as_mut().unwrap().auto_ack_rx = enable;
122    });
123}
124
125pub(crate) fn ieee802154_pib_set_enhance_ack_tx(enable: bool) {
126    critical_section::with(|cs| {
127        PIB.borrow_ref_mut(cs).as_mut().unwrap().enhance_ack_tx = enable;
128    });
129}
130
131pub(crate) fn ieee802154_pib_set_coordinator(enable: bool) {
132    critical_section::with(|cs| {
133        PIB.borrow_ref_mut(cs).as_mut().unwrap().coordinator = enable;
134    });
135}
136
137pub(crate) fn ieee802154_pib_set_rx_when_idle(enable: bool) {
138    critical_section::with(|cs| {
139        PIB.borrow_ref_mut(cs).as_mut().unwrap().rx_when_idle = enable;
140    });
141}
142
143pub(crate) fn ieee802154_pib_get_rx_when_idle() -> bool {
144    critical_section::with(|cs| PIB.borrow_ref_mut(cs).as_mut().unwrap().rx_when_idle)
145}
146
147pub(crate) fn ieee802154_pib_set_tx_power(power: i8) {
148    critical_section::with(|cs| {
149        PIB.borrow_ref_mut(cs).as_mut().unwrap().txpower = power;
150    });
151}
152
153pub(crate) fn ieee802154_pib_set_channel(channel: u8) {
154    critical_section::with(|cs| {
155        PIB.borrow_ref_mut(cs).as_mut().unwrap().channel = channel;
156    });
157}
158
159pub(crate) fn ieee802154_pib_set_pending_mode(mode: PendingMode) {
160    critical_section::with(|cs| {
161        PIB.borrow_ref_mut(cs).as_mut().unwrap().pending_mode = mode;
162    });
163}
164
165pub(crate) fn ieee802154_pib_set_short_address(index: u8, address: u16) {
166    critical_section::with(|cs| {
167        PIB.borrow_ref_mut(cs).as_mut().unwrap().short_addr[index as usize] = address;
168    });
169}
170
171pub(crate) fn ieee802154_pib_set_extended_address(
172    index: u8,
173    address: [u8; IEEE802154_FRAME_EXT_ADDR_SIZE],
174) {
175    critical_section::with(|cs| {
176        PIB.borrow_ref_mut(cs).as_mut().unwrap().ext_addr[index as usize] = address;
177    });
178}
179
180pub(crate) fn ieee802154_pib_set_cca_theshold(cca_threshold: i8) {
181    critical_section::with(|cs| {
182        PIB.borrow_ref_mut(cs).as_mut().unwrap().cca_threshold = cca_threshold;
183    });
184}
185
186pub(crate) fn ieee802154_pib_set_cca_mode(mode: CcaMode) {
187    critical_section::with(|cs| {
188        PIB.borrow_ref_mut(cs).as_mut().unwrap().cca_mode = mode;
189    });
190}
191
192pub(crate) fn ieee802154_pib_update() {
193    critical_section::with(|cs| {
194        let mut pib = PIB.borrow_ref_mut(cs);
195        let pib = pib.as_mut().unwrap();
196
197        set_freq(channel_to_freq(pib.channel));
198        set_power(ieee802154_txpower_convert(pib.txpower));
199
200        set_multipan_enable_mask(pib.multipan_mask);
201        ieee802154_set_multipan_hal(pib);
202
203        set_cca_mode(pib.cca_mode);
204        set_cca_threshold(pib.cca_threshold);
205
206        set_tx_auto_ack(pib.auto_ack_tx);
207        set_rx_auto_ack(pib.auto_ack_rx);
208        set_tx_enhance_ack(pib.enhance_ack_tx);
209
210        set_coordinator(pib.coordinator);
211        set_promiscuous(pib.promiscuous);
212        set_pending_mode(pib.pending_mode == PendingMode::Enhanced);
213    });
214}
215
216fn channel_to_freq(channel: u8) -> u8 {
217    (channel - 11) * 5 + 3
218}
219
220fn ieee802154_set_multipan_hal(pib: &Pib) {
221    for index in 0..IEEE802154_MULTIPAN_MAX {
222        if (pib.multipan_mask & (1 << index)) != 0 {
223            set_multipan_panid(index.into(), pib.panid[index]);
224            set_multipan_short_addr(index.into(), pib.short_addr[index]);
225            set_multipan_ext_addr(index.into(), pib.ext_addr[index].as_ptr());
226        }
227    }
228}
229
230// https://github.com/espressif/esp-idf/blob/release/v5.3/components/ieee802154/driver/esp_ieee802154_pib.c#L48
231fn ieee802154_txpower_convert(txpower: i8) -> u8 {
232    cfg_if::cfg_if! {
233        if #[cfg(feature="esp32h2")] {
234            // https://github.com/espressif/esp-idf/blob/release/v5.3/components/hal/esp32h2/include/hal/ieee802154_ll.h
235            const IEEE802154_TXPOWER_VALUE_MAX: i8 = 20;
236            const IEEE802154_TXPOWER_VALUE_MIN: i8 = -24;
237            const IEEE802154_TXPOWER_INDEX_MIN: i8 = 0;
238        } else if #[cfg(feature="esp32c6")]{
239            // https://github.com/espressif/esp-idf/blob/release/v5.3/components/hal/esp32c6/include/hal/ieee802154_ll.h
240            const IEEE802154_TXPOWER_VALUE_MAX: i8 = 20;
241            const IEEE802154_TXPOWER_VALUE_MIN: i8 = -15;
242            const IEEE802154_TXPOWER_INDEX_MIN: i8 = 3;
243        }
244    }
245    if txpower > IEEE802154_TXPOWER_VALUE_MAX {
246        15
247    } else if txpower <= IEEE802154_TXPOWER_VALUE_MIN {
248        IEEE802154_TXPOWER_INDEX_MIN as u8
249    } else {
250        (((txpower - IEEE802154_TXPOWER_VALUE_MIN) / 3) + IEEE802154_TXPOWER_INDEX_MIN) as u8
251    }
252}