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#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
32pub enum PendingMode {
33 #[default]
35 Disable = 0,
36 Enable = 1,
39 Enhanced = 2,
41 Zigbee = 3,
44}
45
46#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
48pub enum CcaMode {
49 #[default]
51 Carrier = 0x00,
52 Ed = 0x01,
54 CarrierOrEd = 0x02,
56 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
230fn ieee802154_txpower_convert(txpower: i8) -> u8 {
232 cfg_if::cfg_if! {
233 if #[cfg(feature="esp32h2")] {
234 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 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}