stm32wb_hci/types/extended_advertisement.rs
1use core::time::Duration;
2
3use byteorder::{ByteOrder, LittleEndian};
4
5use crate::AdvertisingHandle;
6
7#[cfg(not(feature = "defmt"))]
8bitflags::bitflags! {
9 /// Extended advertising modes
10 pub struct AdvertisingMode: u8 {
11 /// Use specific random address
12 const SPECIFIC = 0x01;
13 }
14}
15
16#[cfg(feature = "defmt")]
17defmt::bitflags! {
18 /// Extended advertising modes
19 pub struct AdvertisingMode: u8 {
20 /// Use specific random address
21 const SPECIFIC = 0x01;
22 }
23}
24
25#[cfg(not(feature = "defmt"))]
26bitflags::bitflags! {
27 /// Advertising event types
28 pub struct AdvertisingEvent: u16 {
29 /// Connectable advertising
30 const CONNECTABLE = 0x0001;
31 /// Scannable advertising
32 const SCANNABLE = 0x0002;
33 /// Directed advertising
34 const DIRECTED = 0x0004;
35 /// High duty cycle directed connectable advertising
36 const HIGH_DUTY_DIRECTED = 0x0008;
37 /// Use legacy advertising PDUs
38 const LEGACY = 0x0010;
39 /// Anonymous advertising
40 const ANONYMOUS = 0x0020;
41 /// Include Tx power in at least one advertising PDU
42 const INCLUDE_TX_POWER = 0x0040;
43 }
44}
45
46#[cfg(feature = "defmt")]
47defmt::bitflags! {
48 /// Advertising event types
49 pub struct AdvertisingEvent: u16 {
50 /// Connectable advertising
51 const CONNECTABLE = 0x0001;
52 /// Scannable advertising
53 const SCANNABLE = 0x0002;
54 /// Directed advertising
55 const DIRECTED = 0x0004;
56 /// High duty cycle directed connectable advertising
57 const HIGH_DUTY_DIRECTED = 0x0008;
58 /// Use legacy advertising PDUs
59 const LEGACY = 0x0010;
60 /// Anonymous advertising
61 const ANONYMOUS = 0x0020;
62 /// Include Tx power in at least one advertising PDU
63 const INCLUDE_TX_POWER = 0x0040;
64 }
65}
66
67/// Define an extended advertising interval range.
68///
69/// The advertising interval min shall be less than or equal to the advertising interval
70/// max. The advertising interval min and advertising interval max should not be the same
71/// values to enable the Controller to determine the best advertising interval given other
72/// adctivities, through this implementation allows them to be equal.
73pub struct ExtendedAdvertisingInterval {
74 /// The first field is the min, the second is the max
75 interval: (Duration, Duration),
76}
77
78impl ExtendedAdvertisingInterval {
79 /// Creates an advertising interval with the provided minimum and maximum values.
80 ///
81 /// # Errors
82 ///
83 /// - [TooShort](ExtendedAdvertisingIntervalError::TooShort) if the minimum value is too small. For
84 /// Bluetooth specifications v4.x, if the advertising type is
85 /// [ScannableUndirected](AdvertisingType::ScannableUndirected), then the minimum value is 100
86 /// ms. In all other cases, the minimum value is 20 ms.
87 /// - [TooLong](ExtendedAdvertisingIntervalError::TooLong) if the maximum value is too large. The
88 /// maximum value is 10.24 seconds.
89 /// - [Inverted](ExtendedAdvertisingIntervalError::Inverted) if the minimum is greater than the
90 /// maximum.
91 pub fn with_range(
92 min: Duration,
93 max: Duration,
94 ) -> Result<Self, ExtendedAdvertisingIntervalError> {
95 const MIN: Duration = Duration::from_millis(20);
96 const MAX: Duration = Duration::from_micros(10485759375);
97
98 if min < MIN {
99 return Err(ExtendedAdvertisingIntervalError::TooShort(min));
100 }
101 if max > MAX {
102 return Err(ExtendedAdvertisingIntervalError::TooLong(max));
103 }
104 if min > max {
105 return Err(ExtendedAdvertisingIntervalError::Inverted(min, max));
106 }
107
108 Ok(Self {
109 interval: (min, max),
110 })
111 }
112
113 fn duration_as_u32(d: Duration) -> u32 {
114 // T = 0.625 ms * N
115 // so N = T / 0.625 ms
116 // = T / 625 us
117 //
118 // Note: 1600 = 1_000_000 / 625
119 1600 * d.as_secs() as u32 + (d.subsec_micros() / 625)
120 }
121
122 /// Serialize the interval into the given buffer.
123 ///
124 /// Serializes the minimum range of the interval (4 bytes), the maximum range of the
125 /// interval (4 bytees)
126 ///
127 /// # Panics
128 ///
129 /// - If the provided buffer is not at least 8 bytes long.
130 pub fn copy_into_slice(&self, bytes: &mut [u8]) {
131 LittleEndian::write_u32(&mut bytes[0..], Self::duration_as_u32(self.interval.0));
132 LittleEndian::write_u32(&mut bytes[4..], Self::duration_as_u32(self.interval.1));
133 }
134}
135
136/// Potential errors that can occur when specifying an [`ExtendedAdvertisingInterval`].
137#[derive(Copy, Clone, Debug, PartialEq)]
138#[cfg_attr(feature = "defmt", derive(defmt::Format))]
139pub enum ExtendedAdvertisingIntervalError {
140 /// The minimum value was too short. Includes the invalid value.
141 TooShort(Duration),
142 /// The maximum value was too long. Includes the invalid value.
143 TooLong(Duration),
144 /// The minimum value was greater than the maximum value. Includes the provided minimum and
145 /// value, respectively.
146 Inverted(Duration, Duration),
147}
148
149/// Advertising PHY
150#[derive(Clone, Copy, Debug)]
151#[cfg_attr(feature = "defmt", derive(defmt::Format))]
152pub enum AdvertisingPhy {
153 /// Advertisement PHY is LE 1M
154 Le1M = 0x01,
155 /// Advertisement PHY is LE 2M
156 Le2M = 0x02,
157}
158
159/// Advertising set
160pub struct AdvSet {
161 /// Used to identify an advertising set
162 pub handle: AdvertisingHandle,
163 /// Duration of advertising set.
164 ///
165 /// Values:
166 /// - 0x0000 (0 ms) : No advertising duration.
167 /// - 0x0001 (10 ms) ... 0xFFFF (655350 ms) : Advertising duration
168 pub duration: u16,
169 /// Maximum number of advertising events.
170 ///
171 /// Values:
172 /// - 0x00: No maximum number of advertising events
173 /// - 0x01 .. 0xFF: Maximum number of extended advertising events the
174 /// Controller shall attempt to send prior to terminating the extended
175 /// advertising
176 pub max_extended_adv_events: u8,
177}
178
179impl AdvSet {
180 pub(crate) fn copy_into_slice(&self, bytes: &mut [u8]) {
181 bytes[0] = self.handle.0;
182 LittleEndian::write_u16(&mut bytes[1..], self.duration);
183 bytes[3] = self.max_extended_adv_events;
184 }
185}
186
187/// Advertising Operation
188#[derive(Clone, Copy, Debug)]
189#[cfg_attr(feature = "defmt", derive(defmt::Format))]
190pub enum AdvertisingOperation {
191 /// Intermediate fragment of fragmented extended advertising data
192 IntermediateFragment = 0x00,
193 /// First fragment of fragmented extended advertising data
194 FirstFragment = 0x01,
195 /// Last fragment of fragmented extended advertising data
196 LastFragment = 0x02,
197 /// Complete extended advertising data
198 CompleteData = 0x03,
199 /// Unchanged data (just update the advertising DID)
200 UnchangedData = 0x04,
201}