1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
//! Physical layer interactions.
//!
//! Don't expect to see much code here: Most of this layer is hardware.
//!
//! BLE data is transmitted on 40 different RF channels numbered from 0 to 39 with ascending
//! frequencies. Channels 0, 12 and 39 are reserved for advertising, all others are used for data
//! transmission. BLE internally uses so-called "Channel Indices" which reorder the RF channels so
//! that indices 0..=36 refer to data channels and 37..=39 refer to the advertising channels
//! (presumably to simplify channel hopping). The Link-Layer is only interested in these channel
//! indices, so only those are implemented here.
/// Returns the center frequency in MHz corresponding to an RF channel.
fn rf_channel_freq(rf_channel: u8) -> u16 {
2402 + u16::from(rf_channel) * 2
}
/// Returns the data whitening IV for a channel index (not RF channel).
fn whitening_iv(channel_idx: u8) -> u8 {
debug_assert!(channel_idx <= 39);
0b01000000 | channel_idx
}
/// One of the three advertising channels (channel indices 37, 38 or 39).
#[derive(Copy, Clone, Debug, defmt::Format)]
pub struct AdvertisingChannel(u8);
impl AdvertisingChannel {
/// Returns the first (lowest-numbered) advertising channel.
pub fn first() -> Self {
AdvertisingChannel(37)
}
/// Returns an iterator that yields all 3 advertising channels in ascending order.
pub fn iter_all() -> impl Iterator<Item = Self> {
[
AdvertisingChannel(37),
AdvertisingChannel(38),
AdvertisingChannel(39),
]
.iter()
.cloned()
}
/// Returns the next advertising channel, or the first one if `self` is the last channel.
pub fn cycle(&self) -> Self {
if self.0 == 39 {
AdvertisingChannel(37)
} else {
AdvertisingChannel(self.0 + 1)
}
}
/// Returns the channel index.
///
/// Channels 37, 38 and 39 are used for advertising.
pub fn channel(&self) -> u8 {
self.0
}
/// Returns the physical RF channel corresponding to this advertising channel index.
///
/// RF channels 0, 12 and 39 are used for advertising.
pub fn rf_channel(&self) -> u8 {
match self.0 {
37 => 0,
38 => 12,
39 => 39,
_ => unreachable!(),
}
}
/// Returns the center frequency of this channel in MHz.
pub fn freq(&self) -> u16 {
rf_channel_freq(self.rf_channel())
}
/// Calculates the initial value of the LFSR to use for data whitening.
///
/// The value is a 7-bit value. The MSb will always be 0, and the 2nd MSb always 1 (Position 0).
/// The LSb contains Position 6. Refer to the specification for details about the bit positions.
///
/// The polynomial is always `x^7 + x^4 + 1`.
///
/// Whitening is applied to PDU and CRC.
pub fn whitening_iv(&self) -> u8 {
whitening_iv(self.0)
}
}
/// One of 37 data channels on which data channel PDUs are sent between connected devices.
///
/// (channel indices 0..=36)
#[derive(Copy, Clone, Debug, PartialEq, Eq, defmt::Format)]
pub struct DataChannel(u8);
impl DataChannel {
/// Creates a `DataChannel` from a raw index.
///
/// # Panics
///
/// This will panic if `index` is not a valid data channel index. Valid indices are 0..=36.
pub fn new(index: u8) -> Self {
assert!(index <= 36);
DataChannel(index)
}
/// Returns the data channel index.
///
/// The returned value is always in range 0..=36.
pub fn index(&self) -> u8 {
self.0
}
/// Returns the RF channel corresponding to this data channel index.
///
/// RF channels 1-11 and 13-38 are used for data transmission.
pub fn rf_channel(&self) -> u8 {
match self.0 {
ch @ 0..=10 => ch + 1,
ch @ 11..=36 => ch + 2,
_ => unreachable!(),
}
}
/// Returns the center frequency of this channel in MHz.
pub fn freq(&self) -> u16 {
rf_channel_freq(self.rf_channel())
}
/// Calculates the initial value of the LFSR to use for data whitening.
///
/// The value is a 7-bit value. The MSb will always be 0, and the 2nd MSb always 1 (Position 0).
/// The LSb contains Position 6. Refer to the specification for details about the bit positions.
///
/// The polynomial is always `x^7 + x^4 + 1`.
///
/// Whitening is applied to PDU and CRC.
pub fn whitening_iv(&self) -> u8 {
whitening_iv(self.0)
}
}
/// Trait for raw 2.4 GHz non-BLE-specific radios.
///
/// You probably won't need to implement this trait, unless you're working with hardware that has
/// absolutely no special support for BLE. Usually, the Link-Layer `Transmitter` should be
/// implemented.
pub trait Radio {
/// Transmit every Byte in `buf` over the air, LSb first, at `freq` MHz.
///
/// TODO: Document all radio requirements
fn transmit(&mut self, buf: &mut [u8], freq: u16);
}