aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuilherme S. Salustiano <[email protected]>2024-02-10 08:09:08 +0100
committerGuilherme S. Salustiano <[email protected]>2024-02-10 08:09:08 +0100
commit802bdd1af86829482d6b847f73f02e6973bb68ea (patch)
tree51ec9d5bec886e2717e8c348d047b1af0b5e9c45
parent9527d1d934a46a50bfc8f26bd942c6f6e5c5b31b (diff)
remove first person comments and assert disable state when it's necessary
-rw-r--r--embassy-nrf/src/radio/ble.rs199
1 files changed, 105 insertions, 94 deletions
diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs
index 369b49c55..b0d374579 100644
--- a/embassy-nrf/src/radio/ble.rs
+++ b/embassy-nrf/src/radio/ble.rs
@@ -64,13 +64,13 @@ impl<'d, T: Instance> Radio<'d, T> {
64 // that if the packet payload length defined by PCNF1.STATLEN and the LENGTH field in the packet specifies a 64 // that if the packet payload length defined by PCNF1.STATLEN and the LENGTH field in the packet specifies a
65 // packet larger than MAXLEN, the payload will be truncated at MAXLEN 65 // packet larger than MAXLEN, the payload will be truncated at MAXLEN
66 // 66 //
67 // To simplify the implementation, I'm setting the max length to the maximum value 67 // To simplify the implementation, It is setted as the maximum value
68 // and I'm using only the length field to truncate the payload 68 // and the length of the packet is controlled only by the LENGTH field in the packet
69 .maxlen() 69 .maxlen()
70 .bits(255) 70 .bits(255)
71 // Configure the length of the address field in the packet 71 // Configure the length of the address field in the packet
72 // The prefix after the address fields is always appended, so is always 1 byte less than the size of the address 72 // The prefix after the address fields is always appended, so is always 1 byte less than the size of the address
73 // The base address is truncated from the least significant byte if the BALEN is less than 4 73 // The base address is truncated from the least significant byte if the BALEN is less than 4
74 // 74 //
75 // BLE address is always 4 bytes long 75 // BLE address is always 4 bytes long
76 .balen() 76 .balen()
@@ -92,14 +92,14 @@ impl<'d, T: Instance> Radio<'d, T> {
92 // Before whitening or de-whitening, the shift register should be 92 // Before whitening or de-whitening, the shift register should be
93 // initialized based on the channel index. 93 // initialized based on the channel index.
94 .whiteen() 94 .whiteen()
95 .set_bit() // Enable whitening 95 .set_bit()
96 }); 96 });
97 97
98 // Configure CRC 98 // Configure CRC
99 r.crccnf.write(|w| { 99 r.crccnf.write(|w| {
100 // In BLE the CRC shall be calculated on the PDU of all Link Layer 100 // In BLE the CRC shall be calculated on the PDU of all Link Layer
101 // packets (even if the packet is encrypted). 101 // packets (even if the packet is encrypted).
102 // So here we skip the address field 102 // It skips the address field
103 w.skipaddr() 103 w.skipaddr()
104 .skip() 104 .skip()
105 // In BLE 24-bit CRC = 3 bytes 105 // In BLE 24-bit CRC = 3 bytes
@@ -125,11 +125,18 @@ impl<'d, T: Instance> Radio<'d, T> {
125 Self { _p: radio } 125 Self { _p: radio }
126 } 126 }
127 127
128 fn state(&self) -> RadioState {
129 match T::regs().state.read().state().variant() {
130 Ok(s) => s,
131 None => unreachable!(),
132 }
133 }
134
128 #[allow(dead_code)] 135 #[allow(dead_code)]
129 fn trace_state(&self) { 136 fn trace_state(&self) {
130 let r = T::regs(); 137 let r = T::regs();
131 138
132 match r.state.read().state().variant().unwrap() { 139 match self.state() {
133 RadioState::DISABLED => trace!("radio:state:DISABLED"), 140 RadioState::DISABLED => trace!("radio:state:DISABLED"),
134 RadioState::RX_RU => trace!("radio:state:RX_RU"), 141 RadioState::RX_RU => trace!("radio:state:RX_RU"),
135 RadioState::RX_IDLE => trace!("radio:state:RX_IDLE"), 142 RadioState::RX_IDLE => trace!("radio:state:RX_IDLE"),
@@ -142,86 +149,12 @@ impl<'d, T: Instance> Radio<'d, T> {
142 } 149 }
143 } 150 }
144 151
145 async fn trigger_and_wait_end(&mut self, trigger: impl FnOnce() -> ()) {
146 //self.trace_state();
147
148 let r = T::regs();
149 let s = T::state();
150
151 // If the Future is dropped before the end of the transmission
152 // we need to disable the interrupt and stop the transmission
153 // to keep the state consistent
154 let drop = OnDrop::new(|| {
155 trace!("radio drop: stopping");
156
157 r.intenclr.write(|w| w.end().clear());
158 r.events_end.reset();
159
160 r.tasks_stop.write(|w| w.tasks_stop().set_bit());
161
162 // The docs don't explicitly mention any event to acknowledge the stop task
163 // So I guess it's the same as end
164 while r.events_end.read().events_end().bit_is_clear() {}
165
166 trace!("radio drop: stopped");
167 });
168
169 // trace!("radio:enable interrupt");
170 // Clear some remnant side-effects (I'm unsure if this is needed)
171 r.events_end.reset();
172
173 // Enable interrupt
174 r.intenset.write(|w| w.end().set());
175
176 compiler_fence(Ordering::SeqCst);
177
178 // Trigger the transmission
179 trigger();
180 // self.trace_state();
181
182 // On poll check if interrupt happen
183 poll_fn(|cx| {
184 s.end_waker.register(cx.waker());
185 if r.events_end.read().events_end().bit_is_set() {
186 // trace!("radio:end");
187 return core::task::Poll::Ready(());
188 }
189 Poll::Pending
190 })
191 .await;
192
193 compiler_fence(Ordering::SeqCst);
194 r.events_disabled.reset(); // ACK
195
196 // Everthing ends fine, so we can disable the drop
197 drop.defuse();
198 }
199
200 /// Disable the radio.
201 fn disable(&mut self) {
202 let r = T::regs();
203
204 compiler_fence(Ordering::SeqCst);
205 // If is already disabled, do nothing
206 if !r.state.read().state().is_disabled() {
207 trace!("radio:disable");
208 // Trigger the disable task
209 r.tasks_disable.write(|w| w.tasks_disable().set_bit());
210
211 // Wait until the radio is disabled
212 while r.events_disabled.read().events_disabled().bit_is_clear() {}
213
214 compiler_fence(Ordering::SeqCst);
215
216 // Acknowledge it
217 r.events_disabled.reset();
218 }
219 }
220
221 /// Set the radio mode 152 /// Set the radio mode
222 /// 153 ///
223 /// The radio must be disabled before calling this function 154 /// The radio must be disabled before calling this function
224 pub fn set_mode(&mut self, mode: Mode) { 155 pub fn set_mode(&mut self, mode: Mode) {
156 assert!(self.state() == RadioState::DISABLED);
157
225 let r = T::regs(); 158 let r = T::regs();
226 r.mode.write(|w| w.mode().variant(mode)); 159 r.mode.write(|w| w.mode().variant(mode));
227 160
@@ -235,10 +168,12 @@ impl<'d, T: Instance> Radio<'d, T> {
235 }); 168 });
236 } 169 }
237 170
238 /// Set the header size changing the S1 field 171 /// Set the header size changing the S1's len field
239 /// 172 ///
240 /// The radio must be disabled before calling this function 173 /// The radio must be disabled before calling this function
241 pub fn set_header_expansion(&mut self, use_s1_field: bool) { 174 pub fn set_header_expansion(&mut self, use_s1_field: bool) {
175 assert!(self.state() == RadioState::DISABLED);
176
242 let r = T::regs(); 177 let r = T::regs();
243 178
244 // s1 len in bits 179 // s1 len in bits
@@ -268,6 +203,8 @@ impl<'d, T: Instance> Radio<'d, T> {
268 /// 203 ///
269 /// The radio must be disabled before calling this function 204 /// The radio must be disabled before calling this function
270 pub fn set_whitening_init(&mut self, whitening_init: u8) { 205 pub fn set_whitening_init(&mut self, whitening_init: u8) {
206 assert!(self.state() == RadioState::DISABLED);
207
271 let r = T::regs(); 208 let r = T::regs();
272 209
273 r.datawhiteiv.write(|w| unsafe { w.datawhiteiv().bits(whitening_init) }); 210 r.datawhiteiv.write(|w| unsafe { w.datawhiteiv().bits(whitening_init) });
@@ -276,9 +213,11 @@ impl<'d, T: Instance> Radio<'d, T> {
276 /// Set the central frequency to be used 213 /// Set the central frequency to be used
277 /// It should be in the range 2400..2500 214 /// It should be in the range 2400..2500
278 /// 215 ///
279 /// The radio must be disabled before calling this function 216 /// [The radio must be disabled before calling this function](https://devzone.nordicsemi.com/f/nordic-q-a/15829/radio-frequency-change)
280 pub fn set_frequency(&mut self, frequency: u32) { 217 pub fn set_frequency(&mut self, frequency: u32) {
218 assert!(self.state() == RadioState::DISABLED);
281 assert!(2400 <= frequency && frequency <= 2500); 219 assert!(2400 <= frequency && frequency <= 2500);
220
282 let r = T::regs(); 221 let r = T::regs();
283 222
284 r.frequency 223 r.frequency
@@ -292,6 +231,8 @@ impl<'d, T: Instance> Radio<'d, T> {
292 /// 231 ///
293 /// The radio must be disabled before calling this function 232 /// The radio must be disabled before calling this function
294 pub fn set_access_address(&mut self, access_address: u32) { 233 pub fn set_access_address(&mut self, access_address: u32) {
234 assert!(self.state() == RadioState::DISABLED);
235
295 let r = T::regs(); 236 let r = T::regs();
296 237
297 // Configure logical address 238 // Configure logical address
@@ -309,9 +250,9 @@ impl<'d, T: Instance> Radio<'d, T> {
309 r.txaddress.write(|w| unsafe { w.txaddress().bits(0) }); 250 r.txaddress.write(|w| unsafe { w.txaddress().bits(0) });
310 251
311 // Match on logical address 252 // Match on logical address
312 // For what I understand, this config only filter the packets 253 // This config only filter the packets by the address,
313 // by the address, so only packages send to the previous address 254 // so only packages send to the previous address
314 // will finish the reception 255 // will finish the reception (TODO: check the explanation)
315 r.rxaddresses.write(|w| { 256 r.rxaddresses.write(|w| {
316 w.addr0() 257 w.addr0()
317 .enabled() 258 .enabled()
@@ -331,6 +272,8 @@ impl<'d, T: Instance> Radio<'d, T> {
331 /// 272 ///
332 /// The radio must be disabled before calling this function 273 /// The radio must be disabled before calling this function
333 pub fn set_crc_poly(&mut self, crc_poly: u32) { 274 pub fn set_crc_poly(&mut self, crc_poly: u32) {
275 assert!(self.state() == RadioState::DISABLED);
276
334 let r = T::regs(); 277 let r = T::regs();
335 278
336 r.crcpoly.write(|w| unsafe { 279 r.crcpoly.write(|w| unsafe {
@@ -351,6 +294,8 @@ impl<'d, T: Instance> Radio<'d, T> {
351 /// 294 ///
352 /// The radio must be disabled before calling this function 295 /// The radio must be disabled before calling this function
353 pub fn set_crc_init(&mut self, crc_init: u32) { 296 pub fn set_crc_init(&mut self, crc_init: u32) {
297 assert!(self.state() == RadioState::DISABLED);
298
354 let r = T::regs(); 299 let r = T::regs();
355 300
356 r.crcinit.write(|w| unsafe { w.crcinit().bits(crc_init & 0xFFFFFF) }); 301 r.crcinit.write(|w| unsafe { w.crcinit().bits(crc_init & 0xFFFFFF) });
@@ -360,6 +305,8 @@ impl<'d, T: Instance> Radio<'d, T> {
360 /// 305 ///
361 /// The radio must be disabled before calling this function 306 /// The radio must be disabled before calling this function
362 pub fn set_tx_power(&mut self, tx_power: TxPower) { 307 pub fn set_tx_power(&mut self, tx_power: TxPower) {
308 assert!(self.state() == RadioState::DISABLED);
309
363 let r = T::regs(); 310 let r = T::regs();
364 311
365 r.txpower.write(|w| w.txpower().variant(tx_power)); 312 r.txpower.write(|w| w.txpower().variant(tx_power));
@@ -408,19 +355,83 @@ impl<'d, T: Instance> Radio<'d, T> {
408 // Initialize the transmission 355 // Initialize the transmission
409 // trace!("rxen"); 356 // trace!("rxen");
410 r.tasks_rxen.write(|w| w.tasks_rxen().set_bit()); 357 r.tasks_rxen.write(|w| w.tasks_rxen().set_bit());
358 })
359 .await;
360 }
411 361
412 // Await until ready 362 async fn trigger_and_wait_end(&mut self, trigger: impl FnOnce()) {
413 while r.events_ready.read().events_ready().bit_is_clear() {} 363 //self.trace_state();
414 364
415 compiler_fence(Ordering::SeqCst); 365 let r = T::regs();
366 let s = T::state();
416 367
417 // Acknowledge it 368 // If the Future is dropped before the end of the transmission
418 r.events_ready.reset(); 369 // we need to disable the interrupt and stop the transmission
370 // to keep the state consistent
371 let drop = OnDrop::new(|| {
372 trace!("radio drop: stopping");
373
374 r.intenclr.write(|w| w.end().clear());
375 r.events_end.reset();
376
377 r.tasks_stop.write(|w| w.tasks_stop().set_bit());
419 378
420 // trace!("radio:start"); 379 // The docs don't explicitly mention any event to acknowledge the stop task
421 r.tasks_start.write(|w| w.tasks_start().set_bit()); 380 while r.events_end.read().events_end().bit_is_clear() {}
381
382 trace!("radio drop: stopped");
383 });
384
385 // trace!("radio:enable interrupt");
386 // Clear some remnant side-effects (TODO: check if this is necessary)
387 r.events_end.reset();
388
389 // Enable interrupt
390 r.intenset.write(|w| w.end().set());
391
392 compiler_fence(Ordering::SeqCst);
393
394 // Trigger the transmission
395 trigger();
396 // self.trace_state();
397
398 // On poll check if interrupt happen
399 poll_fn(|cx| {
400 s.end_waker.register(cx.waker());
401 if r.events_end.read().events_end().bit_is_set() {
402 // trace!("radio:end");
403 return core::task::Poll::Ready(());
404 }
405 Poll::Pending
422 }) 406 })
423 .await; 407 .await;
408
409 compiler_fence(Ordering::SeqCst);
410 r.events_disabled.reset(); // ACK
411
412 // Everthing ends fine, so we can disable the drop
413 drop.defuse();
414 }
415
416 /// Disable the radio
417 fn disable(&mut self) {
418 let r = T::regs();
419
420 compiler_fence(Ordering::SeqCst);
421 // If it is already disabled, do nothing
422 if self.state() != RadioState::DISABLED {
423 trace!("radio:disable");
424 // Trigger the disable task
425 r.tasks_disable.write(|w| w.tasks_disable().set_bit());
426
427 // Wait until the radio is disabled
428 while r.events_disabled.read().events_disabled().bit_is_clear() {}
429
430 compiler_fence(Ordering::SeqCst);
431
432 // Acknowledge it
433 r.events_disabled.reset();
434 }
424 } 435 }
425} 436}
426 437