diff options
| -rw-r--r-- | embassy-nrf/src/radio/ble.rs | 394 | ||||
| -rw-r--r-- | embassy-nrf/src/radio/ieee802154.rs | 7 | ||||
| -rw-r--r-- | embassy-nrf/src/radio/mod.rs | 8 |
3 files changed, 5 insertions, 404 deletions
diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs deleted file mode 100644 index d42bbe5f6..000000000 --- a/embassy-nrf/src/radio/ble.rs +++ /dev/null | |||
| @@ -1,394 +0,0 @@ | |||
| 1 | //! Radio driver implementation focused on Bluetooth Low-Energy transmission. | ||
| 2 | |||
| 3 | use core::future::poll_fn; | ||
| 4 | use core::sync::atomic::{compiler_fence, Ordering}; | ||
| 5 | use core::task::Poll; | ||
| 6 | |||
| 7 | use embassy_hal_internal::drop::OnDrop; | ||
| 8 | pub use pac::radio::vals::Mode; | ||
| 9 | #[cfg(not(feature = "_nrf51"))] | ||
| 10 | use pac::radio::vals::Plen as PreambleLength; | ||
| 11 | |||
| 12 | use crate::interrupt::typelevel::Interrupt; | ||
| 13 | use crate::pac::radio::vals; | ||
| 14 | use crate::radio::*; | ||
| 15 | pub use crate::radio::{Error, TxPower}; | ||
| 16 | use crate::util::slice_in_ram_or; | ||
| 17 | use crate::Peri; | ||
| 18 | |||
| 19 | /// Radio driver. | ||
| 20 | pub struct Radio<'d, T: Instance> { | ||
| 21 | _p: Peri<'d, T>, | ||
| 22 | } | ||
| 23 | |||
| 24 | impl<'d, T: Instance> Radio<'d, T> { | ||
| 25 | /// Create a new radio driver. | ||
| 26 | pub fn new( | ||
| 27 | radio: Peri<'d, T>, | ||
| 28 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||
| 29 | ) -> Self { | ||
| 30 | let r = T::regs(); | ||
| 31 | |||
| 32 | r.pcnf1().write(|w| { | ||
| 33 | // It is 0 bytes long in a standard BLE packet | ||
| 34 | w.set_statlen(0); | ||
| 35 | // MaxLen configures the maximum packet payload plus add-on size in | ||
| 36 | // number of bytes that can be transmitted or received by the RADIO. This feature can be used to ensure | ||
| 37 | // that the RADIO does not overwrite, or read beyond, the RAM assigned to the packet payload. This means | ||
| 38 | // that if the packet payload length defined by PCNF1.STATLEN and the LENGTH field in the packet specifies a | ||
| 39 | // packet larger than MAXLEN, the payload will be truncated at MAXLEN | ||
| 40 | // | ||
| 41 | // To simplify the implementation, It is setted as the maximum value | ||
| 42 | // and the length of the packet is controlled only by the LENGTH field in the packet | ||
| 43 | w.set_maxlen(255); | ||
| 44 | // Configure the length of the address field in the packet | ||
| 45 | // The prefix after the address fields is always appended, so is always 1 byte less than the size of the address | ||
| 46 | // The base address is truncated from the least significant byte if the BALEN is less than 4 | ||
| 47 | // | ||
| 48 | // BLE address is always 4 bytes long | ||
| 49 | w.set_balen(3); // 3 bytes base address (+ 1 prefix); | ||
| 50 | // Configure the endianess | ||
| 51 | // For BLE is always little endian (LSB first) | ||
| 52 | w.set_endian(vals::Endian::LITTLE); | ||
| 53 | // Data whitening is used to avoid long sequences of zeros or | ||
| 54 | // ones, e.g., 0b0000000 or 0b1111111, in the data bit stream. | ||
| 55 | // The whitener and de-whitener are defined the same way, | ||
| 56 | // using a 7-bit linear feedback shift register with the | ||
| 57 | // polynomial x7 + x4 + 1. | ||
| 58 | // | ||
| 59 | // In BLE Whitening shall be applied on the PDU and CRC of all | ||
| 60 | // Link Layer packets and is performed after the CRC generation | ||
| 61 | // in the transmitter. No other parts of the packets are whitened. | ||
| 62 | // De-whitening is performed before the CRC checking in the receiver | ||
| 63 | // Before whitening or de-whitening, the shift register should be | ||
| 64 | // initialized based on the channel index. | ||
| 65 | w.set_whiteen(true); | ||
| 66 | }); | ||
| 67 | |||
| 68 | // Configure CRC | ||
| 69 | r.crccnf().write(|w| { | ||
| 70 | // In BLE the CRC shall be calculated on the PDU of all Link Layer | ||
| 71 | // packets (even if the packet is encrypted). | ||
| 72 | // It skips the address field | ||
| 73 | w.set_skipaddr(vals::Skipaddr::SKIP); | ||
| 74 | // In BLE 24-bit CRC = 3 bytes | ||
| 75 | w.set_len(vals::Len::THREE); | ||
| 76 | }); | ||
| 77 | |||
| 78 | // Ch map between 2400 MHZ .. 2500 MHz | ||
| 79 | // All modes use this range | ||
| 80 | #[cfg(not(feature = "_nrf51"))] | ||
| 81 | r.frequency().write(|w| w.set_map(vals::Map::DEFAULT)); | ||
| 82 | |||
| 83 | // Configure shortcuts to simplify and speed up sending and receiving packets. | ||
| 84 | r.shorts().write(|w| { | ||
| 85 | // start transmission/recv immediately after ramp-up | ||
| 86 | // disable radio when transmission/recv is done | ||
| 87 | w.set_ready_start(true); | ||
| 88 | w.set_end_disable(true); | ||
| 89 | }); | ||
| 90 | |||
| 91 | // Enable NVIC interrupt | ||
| 92 | T::Interrupt::unpend(); | ||
| 93 | unsafe { T::Interrupt::enable() }; | ||
| 94 | |||
| 95 | Self { _p: radio } | ||
| 96 | } | ||
| 97 | |||
| 98 | fn state(&self) -> RadioState { | ||
| 99 | super::state(T::regs()) | ||
| 100 | } | ||
| 101 | |||
| 102 | /// Set the radio mode | ||
| 103 | /// | ||
| 104 | /// The radio must be disabled before calling this function | ||
| 105 | pub fn set_mode(&mut self, mode: Mode) { | ||
| 106 | assert!(self.state() == RadioState::DISABLED); | ||
| 107 | |||
| 108 | let r = T::regs(); | ||
| 109 | r.mode().write(|w| w.set_mode(mode)); | ||
| 110 | |||
| 111 | #[cfg(not(feature = "_nrf51"))] | ||
| 112 | r.pcnf0().write(|w| { | ||
| 113 | w.set_plen(match mode { | ||
| 114 | Mode::BLE_1MBIT => PreambleLength::_8BIT, | ||
| 115 | Mode::BLE_2MBIT => PreambleLength::_16BIT, | ||
| 116 | #[cfg(any( | ||
| 117 | feature = "nrf52811", | ||
| 118 | feature = "nrf52820", | ||
| 119 | feature = "nrf52833", | ||
| 120 | feature = "nrf52840", | ||
| 121 | feature = "_nrf5340-net" | ||
| 122 | ))] | ||
| 123 | Mode::BLE_LR125KBIT | Mode::BLE_LR500KBIT => PreambleLength::LONG_RANGE, | ||
| 124 | _ => unimplemented!(), | ||
| 125 | }) | ||
| 126 | }); | ||
| 127 | } | ||
| 128 | |||
| 129 | /// Set the header size changing the S1's len field | ||
| 130 | /// | ||
| 131 | /// The radio must be disabled before calling this function | ||
| 132 | pub fn set_header_expansion(&mut self, use_s1_field: bool) { | ||
| 133 | assert!(self.state() == RadioState::DISABLED); | ||
| 134 | |||
| 135 | let r = T::regs(); | ||
| 136 | |||
| 137 | // s1 len in bits | ||
| 138 | let s1len: u8 = match use_s1_field { | ||
| 139 | false => 0, | ||
| 140 | true => 8, | ||
| 141 | }; | ||
| 142 | |||
| 143 | r.pcnf0().write(|w| { | ||
| 144 | // Configure S0 to 1 byte length, this will represent the Data/Adv header flags | ||
| 145 | w.set_s0len(true); | ||
| 146 | // Configure the length (in bits) field to 1 byte length, this will represent the length of the payload | ||
| 147 | // and also be used to know how many bytes to read/write from/to the buffer | ||
| 148 | w.set_lflen(0); | ||
| 149 | // Configure the lengh (in bits) of bits in the S1 field. It could be used to represent the CTEInfo for data packages in BLE. | ||
| 150 | w.set_s1len(s1len); | ||
| 151 | }); | ||
| 152 | } | ||
| 153 | |||
| 154 | /// Set initial data whitening value | ||
| 155 | /// Data whitening is used to avoid long sequences of zeros or ones, e.g., 0b0000000 or 0b1111111, in the data bit stream | ||
| 156 | /// On BLE the initial value is the channel index | 0x40 | ||
| 157 | /// | ||
| 158 | /// The radio must be disabled before calling this function | ||
| 159 | pub fn set_whitening_init(&mut self, whitening_init: u8) { | ||
| 160 | assert!(self.state() == RadioState::DISABLED); | ||
| 161 | |||
| 162 | let r = T::regs(); | ||
| 163 | |||
| 164 | r.datawhiteiv().write(|w| w.set_datawhiteiv(whitening_init)); | ||
| 165 | } | ||
| 166 | |||
| 167 | /// Set the central frequency to be used | ||
| 168 | /// It should be in the range 2400..2500 | ||
| 169 | /// | ||
| 170 | /// [The radio must be disabled before calling this function](https://devzone.nordicsemi.com/f/nordic-q-a/15829/radio-frequency-change) | ||
| 171 | pub fn set_frequency(&mut self, frequency: u32) { | ||
| 172 | assert!(self.state() == RadioState::DISABLED); | ||
| 173 | assert!((2400..=2500).contains(&frequency)); | ||
| 174 | |||
| 175 | let r = T::regs(); | ||
| 176 | |||
| 177 | r.frequency().write(|w| w.set_frequency((frequency - 2400) as u8)); | ||
| 178 | } | ||
| 179 | |||
| 180 | /// Set the acess address | ||
| 181 | /// This address is always constants for advertising | ||
| 182 | /// And a random value generate on each connection | ||
| 183 | /// It is used to filter the packages | ||
| 184 | /// | ||
| 185 | /// The radio must be disabled before calling this function | ||
| 186 | pub fn set_access_address(&mut self, access_address: u32) { | ||
| 187 | assert!(self.state() == RadioState::DISABLED); | ||
| 188 | |||
| 189 | let r = T::regs(); | ||
| 190 | |||
| 191 | // Configure logical address | ||
| 192 | // The byte ordering on air is always least significant byte first for the address | ||
| 193 | // So for the address 0xAA_BB_CC_DD, the address on air will be DD CC BB AA | ||
| 194 | // The package order is BASE, PREFIX so BASE=0xBB_CC_DD and PREFIX=0xAA | ||
| 195 | r.prefix0().write(|w| w.set_ap0((access_address >> 24) as u8)); | ||
| 196 | |||
| 197 | // The base address is truncated from the least significant byte (because the BALEN is less than 4) | ||
| 198 | // So it shifts the address to the right | ||
| 199 | r.base0().write_value(access_address << 8); | ||
| 200 | |||
| 201 | // Don't match tx address | ||
| 202 | r.txaddress().write(|w| w.set_txaddress(0)); | ||
| 203 | |||
| 204 | // Match on logical address | ||
| 205 | // This config only filter the packets by the address, | ||
| 206 | // so only packages send to the previous address | ||
| 207 | // will finish the reception (TODO: check the explanation) | ||
| 208 | r.rxaddresses().write(|w| { | ||
| 209 | w.set_addr0(true); | ||
| 210 | w.set_addr1(true); | ||
| 211 | w.set_addr2(true); | ||
| 212 | w.set_addr3(true); | ||
| 213 | w.set_addr4(true); | ||
| 214 | }); | ||
| 215 | } | ||
| 216 | |||
| 217 | /// Set the CRC polynomial | ||
| 218 | /// It only uses the 24 least significant bits | ||
| 219 | /// | ||
| 220 | /// The radio must be disabled before calling this function | ||
| 221 | pub fn set_crc_poly(&mut self, crc_poly: u32) { | ||
| 222 | assert!(self.state() == RadioState::DISABLED); | ||
| 223 | |||
| 224 | let r = T::regs(); | ||
| 225 | |||
| 226 | r.crcpoly().write(|w| { | ||
| 227 | // Configure the CRC polynomial | ||
| 228 | // Each term in the CRC polynomial is mapped to a bit in this | ||
| 229 | // register which index corresponds to the term's exponent. | ||
| 230 | // The least significant term/bit is hard-wired internally to | ||
| 231 | // 1, and bit number 0 of the register content is ignored by | ||
| 232 | // the hardware. The following example is for an 8 bit CRC | ||
| 233 | // polynomial: x8 + x7 + x3 + x2 + 1 = 1 1000 1101 . | ||
| 234 | w.set_crcpoly(crc_poly & 0xFFFFFF) | ||
| 235 | }); | ||
| 236 | } | ||
| 237 | |||
| 238 | /// Set the CRC init value | ||
| 239 | /// It only uses the 24 least significant bits | ||
| 240 | /// The CRC initial value varies depending of the PDU type | ||
| 241 | /// | ||
| 242 | /// The radio must be disabled before calling this function | ||
| 243 | pub fn set_crc_init(&mut self, crc_init: u32) { | ||
| 244 | assert!(self.state() == RadioState::DISABLED); | ||
| 245 | |||
| 246 | let r = T::regs(); | ||
| 247 | |||
| 248 | r.crcinit().write(|w| w.set_crcinit(crc_init & 0xFFFFFF)); | ||
| 249 | } | ||
| 250 | |||
| 251 | /// Set the radio tx power | ||
| 252 | /// | ||
| 253 | /// The radio must be disabled before calling this function | ||
| 254 | pub fn set_tx_power(&mut self, tx_power: TxPower) { | ||
| 255 | assert!(self.state() == RadioState::DISABLED); | ||
| 256 | |||
| 257 | let r = T::regs(); | ||
| 258 | |||
| 259 | r.txpower().write(|w| w.set_txpower(tx_power)); | ||
| 260 | } | ||
| 261 | |||
| 262 | /// Set buffer to read/write | ||
| 263 | /// | ||
| 264 | /// This method is unsound. You should guarantee that the buffer will live | ||
| 265 | /// for the life time of the transmission or if the buffer will be modified. | ||
| 266 | /// Also if the buffer is smaller than the packet length, the radio will | ||
| 267 | /// read/write memory out of the buffer bounds. | ||
| 268 | fn set_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { | ||
| 269 | slice_in_ram_or(buffer, Error::BufferNotInRAM)?; | ||
| 270 | |||
| 271 | let r = T::regs(); | ||
| 272 | |||
| 273 | // Here it consider that the length of the packet is | ||
| 274 | // correctly set in the buffer, otherwise it will send | ||
| 275 | // unowned regions of memory | ||
| 276 | let ptr = buffer.as_ptr(); | ||
| 277 | |||
| 278 | // Configure the payload | ||
| 279 | r.packetptr().write_value(ptr as u32); | ||
| 280 | |||
| 281 | Ok(()) | ||
| 282 | } | ||
| 283 | |||
| 284 | /// Send packet | ||
| 285 | /// If the length byte in the package is greater than the buffer length | ||
| 286 | /// the radio will read memory out of the buffer bounds | ||
| 287 | pub async fn transmit(&mut self, buffer: &[u8]) -> Result<(), Error> { | ||
| 288 | self.set_buffer(buffer)?; | ||
| 289 | |||
| 290 | let r = T::regs(); | ||
| 291 | self.trigger_and_wait_end(move || { | ||
| 292 | // Initialize the transmission | ||
| 293 | // trace!("txen"); | ||
| 294 | |||
| 295 | r.tasks_txen().write_value(1); | ||
| 296 | }) | ||
| 297 | .await; | ||
| 298 | |||
| 299 | Ok(()) | ||
| 300 | } | ||
| 301 | |||
| 302 | /// Receive packet | ||
| 303 | /// If the length byte in the received package is greater than the buffer length | ||
| 304 | /// the radio will write memory out of the buffer bounds | ||
| 305 | pub async fn receive(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 306 | self.set_buffer(buffer)?; | ||
| 307 | |||
| 308 | let r = T::regs(); | ||
| 309 | self.trigger_and_wait_end(move || { | ||
| 310 | // Initialize the transmission | ||
| 311 | // trace!("rxen"); | ||
| 312 | r.tasks_rxen().write_value(1); | ||
| 313 | }) | ||
| 314 | .await; | ||
| 315 | |||
| 316 | Ok(()) | ||
| 317 | } | ||
| 318 | |||
| 319 | async fn trigger_and_wait_end(&mut self, trigger: impl FnOnce()) { | ||
| 320 | let r = T::regs(); | ||
| 321 | let s = T::state(); | ||
| 322 | |||
| 323 | // If the Future is dropped before the end of the transmission | ||
| 324 | // it disable the interrupt and stop the transmission | ||
| 325 | // to keep the state consistent | ||
| 326 | let drop = OnDrop::new(|| { | ||
| 327 | trace!("radio drop: stopping"); | ||
| 328 | |||
| 329 | r.intenclr().write(|w| w.set_end(true)); | ||
| 330 | |||
| 331 | r.tasks_stop().write_value(1); | ||
| 332 | |||
| 333 | r.events_end().write_value(0); | ||
| 334 | |||
| 335 | trace!("radio drop: stopped"); | ||
| 336 | }); | ||
| 337 | |||
| 338 | // trace!("radio:enable interrupt"); | ||
| 339 | // Clear some remnant side-effects (TODO: check if this is necessary) | ||
| 340 | r.events_end().write_value(0); | ||
| 341 | |||
| 342 | // Enable interrupt | ||
| 343 | r.intenset().write(|w| w.set_end(true)); | ||
| 344 | |||
| 345 | compiler_fence(Ordering::SeqCst); | ||
| 346 | |||
| 347 | // Trigger the transmission | ||
| 348 | trigger(); | ||
| 349 | |||
| 350 | // On poll check if interrupt happen | ||
| 351 | poll_fn(|cx| { | ||
| 352 | s.event_waker.register(cx.waker()); | ||
| 353 | if r.events_end().read() == 1 { | ||
| 354 | // trace!("radio:end"); | ||
| 355 | return core::task::Poll::Ready(()); | ||
| 356 | } | ||
| 357 | Poll::Pending | ||
| 358 | }) | ||
| 359 | .await; | ||
| 360 | |||
| 361 | compiler_fence(Ordering::SeqCst); | ||
| 362 | r.events_end().write_value(0); // ACK | ||
| 363 | |||
| 364 | // Everthing ends fine, so it disable the drop | ||
| 365 | drop.defuse(); | ||
| 366 | } | ||
| 367 | |||
| 368 | /// Disable the radio | ||
| 369 | fn disable(&mut self) { | ||
| 370 | let r = T::regs(); | ||
| 371 | |||
| 372 | compiler_fence(Ordering::SeqCst); | ||
| 373 | // If it is already disabled, do nothing | ||
| 374 | if self.state() != RadioState::DISABLED { | ||
| 375 | trace!("radio:disable"); | ||
| 376 | // Trigger the disable task | ||
| 377 | r.tasks_disable().write_value(1); | ||
| 378 | |||
| 379 | // Wait until the radio is disabled | ||
| 380 | while r.events_disabled().read() == 0 {} | ||
| 381 | |||
| 382 | compiler_fence(Ordering::SeqCst); | ||
| 383 | |||
| 384 | // Acknowledge it | ||
| 385 | r.events_disabled().write_value(0); | ||
| 386 | } | ||
| 387 | } | ||
| 388 | } | ||
| 389 | |||
| 390 | impl<'d, T: Instance> Drop for Radio<'d, T> { | ||
| 391 | fn drop(&mut self) { | ||
| 392 | self.disable(); | ||
| 393 | } | ||
| 394 | } | ||
diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs index 2f0bcbe04..7f4f8f462 100644 --- a/embassy-nrf/src/radio/ieee802154.rs +++ b/embassy-nrf/src/radio/ieee802154.rs | |||
| @@ -5,10 +5,11 @@ use core::task::Poll; | |||
| 5 | 5 | ||
| 6 | use embassy_hal_internal::drop::OnDrop; | 6 | use embassy_hal_internal::drop::OnDrop; |
| 7 | 7 | ||
| 8 | use super::{state, Error, Instance, InterruptHandler, RadioState, TxPower}; | 8 | use super::{Error, Instance, InterruptHandler, TxPower}; |
| 9 | use crate::interrupt::typelevel::Interrupt; | 9 | use crate::interrupt::typelevel::Interrupt; |
| 10 | use crate::interrupt::{self}; | 10 | use crate::interrupt::{self}; |
| 11 | use crate::pac::radio::vals; | 11 | use crate::pac::radio::vals; |
| 12 | pub use crate::pac::radio::vals::State as RadioState; | ||
| 12 | use crate::Peri; | 13 | use crate::Peri; |
| 13 | 14 | ||
| 14 | /// Default (IEEE compliant) Start of Frame Delimiter | 15 | /// Default (IEEE compliant) Start of Frame Delimiter |
| @@ -200,7 +201,7 @@ impl<'d, T: Instance> Radio<'d, T> { | |||
| 200 | 201 | ||
| 201 | /// Get the current radio state | 202 | /// Get the current radio state |
| 202 | fn state(&self) -> RadioState { | 203 | fn state(&self) -> RadioState { |
| 203 | state(T::regs()) | 204 | T::regs().state().read().state() |
| 204 | } | 205 | } |
| 205 | 206 | ||
| 206 | /// Moves the radio from any state to the DISABLED state | 207 | /// Moves the radio from any state to the DISABLED state |
| @@ -293,7 +294,7 @@ impl<'d, T: Instance> Radio<'d, T> { | |||
| 293 | r.shorts().write(|_| {}); | 294 | r.shorts().write(|_| {}); |
| 294 | r.tasks_stop().write_value(1); | 295 | r.tasks_stop().write_value(1); |
| 295 | loop { | 296 | loop { |
| 296 | match state(r) { | 297 | match r.state().read().state() { |
| 297 | RadioState::DISABLED | RadioState::RX_IDLE => break, | 298 | RadioState::DISABLED | RadioState::RX_IDLE => break, |
| 298 | _ => (), | 299 | _ => (), |
| 299 | } | 300 | } |
diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs index 982436266..608ef9024 100644 --- a/embassy-nrf/src/radio/mod.rs +++ b/embassy-nrf/src/radio/mod.rs | |||
| @@ -6,7 +6,6 @@ | |||
| 6 | #![macro_use] | 6 | #![macro_use] |
| 7 | 7 | ||
| 8 | /// Bluetooth Low Energy Radio driver. | 8 | /// Bluetooth Low Energy Radio driver. |
| 9 | pub mod ble; | ||
| 10 | #[cfg(any( | 9 | #[cfg(any( |
| 11 | feature = "nrf52811", | 10 | feature = "nrf52811", |
| 12 | feature = "nrf52820", | 11 | feature = "nrf52820", |
| @@ -21,7 +20,6 @@ use core::marker::PhantomData; | |||
| 21 | 20 | ||
| 22 | use embassy_hal_internal::PeripheralType; | 21 | use embassy_hal_internal::PeripheralType; |
| 23 | use embassy_sync::waitqueue::AtomicWaker; | 22 | use embassy_sync::waitqueue::AtomicWaker; |
| 24 | use pac::radio::vals::State as RadioState; | ||
| 25 | pub use pac::radio::vals::Txpower as TxPower; | 23 | pub use pac::radio::vals::Txpower as TxPower; |
| 26 | 24 | ||
| 27 | use crate::{interrupt, pac}; | 25 | use crate::{interrupt, pac}; |
| @@ -82,6 +80,7 @@ macro_rules! impl_radio { | |||
| 82 | pac::$pac_type | 80 | pac::$pac_type |
| 83 | } | 81 | } |
| 84 | 82 | ||
| 83 | #[allow(unused)] | ||
| 85 | fn state() -> &'static crate::radio::State { | 84 | fn state() -> &'static crate::radio::State { |
| 86 | static STATE: crate::radio::State = crate::radio::State::new(); | 85 | static STATE: crate::radio::State = crate::radio::State::new(); |
| 87 | &STATE | 86 | &STATE |
| @@ -99,8 +98,3 @@ pub trait Instance: SealedInstance + PeripheralType + 'static + Send { | |||
| 99 | /// Interrupt for this peripheral. | 98 | /// Interrupt for this peripheral. |
| 100 | type Interrupt: interrupt::typelevel::Interrupt; | 99 | type Interrupt: interrupt::typelevel::Interrupt; |
| 101 | } | 100 | } |
| 102 | |||
| 103 | /// Get the state of the radio | ||
| 104 | pub(crate) fn state(radio: pac::radio::Radio) -> RadioState { | ||
| 105 | radio.state().read().state() | ||
| 106 | } | ||
