diff options
| -rw-r--r-- | embassy-nrf/src/radio/ble.rs | 199 |
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 | ||
