bluetooth_hci/types/connection_interval.rs
1//! Types related to the connection interval.
2
3use byteorder::{ByteOrder, LittleEndian};
4use core::cmp;
5use core::time::Duration;
6
7/// Define a connection interval range with its latency and supervision timeout. This value is
8/// passed to the controller, which determines the [actual connection
9/// interval](crate::types::FixedConnectionInterval).
10#[derive(Copy, Clone, Debug)]
11pub struct ConnectionInterval {
12 interval_: (Duration, Duration),
13 conn_latency_: u16,
14 supervision_timeout_: Duration,
15}
16
17impl ConnectionInterval {
18 /// Returns the connection interval.
19 pub fn interval(&self) -> (Duration, Duration) {
20 self.interval_
21 }
22
23 /// Returns the connection latency, in number of events.
24 pub fn conn_latency(&self) -> u16 {
25 self.conn_latency_
26 }
27
28 /// Returns the supervision timeout.
29 pub fn supervision_timeout(&self) -> Duration {
30 self.supervision_timeout_
31 }
32
33 /// Serializes the connection interval into the given byte buffer.
34 ///
35 /// The interval is serialized as:
36 /// - The minimum interval value, appropriately converted (2 bytes)
37 /// - The maximum interval value, appropriately converted (2 bytes)
38 /// - The connection latency (2 bytes)
39 /// - The supervision timeout, appropriately converted (2 bytes)
40 ///
41 /// # Panics
42 ///
43 /// The provided buffer must be at least 8 bytes long.
44 pub fn copy_into_slice(&self, bytes: &mut [u8]) {
45 assert!(bytes.len() >= 8);
46
47 LittleEndian::write_u16(&mut bytes[0..2], Self::interval_as_u16(self.interval_.0));
48 LittleEndian::write_u16(&mut bytes[2..4], Self::interval_as_u16(self.interval_.1));
49 LittleEndian::write_u16(&mut bytes[4..6], self.conn_latency_);
50 LittleEndian::write_u16(
51 &mut bytes[6..8],
52 Self::timeout_as_u16(self.supervision_timeout_),
53 );
54 }
55
56 /// Deserializes the connection interval from the given byte buffer.
57 ///
58 /// - The minimum interval value, appropriately converted (2 bytes)
59 /// - The maximum interval value, appropriately converted (2 bytes)
60 /// - The connection latency (2 bytes)
61 /// - The supervision timeout, appropriately converted (2 bytes)
62 ///
63 /// # Panics
64 ///
65 /// The provided buffer must be at least 8 bytes long.
66 ///
67 /// # Errors
68 ///
69 /// Any of the errors from the [builder](ConnectionIntervalBuilder::build) except for
70 /// Incomplete.
71 pub fn from_bytes(bytes: &[u8]) -> Result<Self, ConnectionIntervalError> {
72 assert!(bytes.len() >= 8);
73
74 // Do the error checking with the standard connection interval builder. The min and max of
75 // the interval range are allowed to be equal.
76 let interval_min =
77 Duration::from_micros(1_250) * u32::from(LittleEndian::read_u16(&bytes[0..2]));
78 let interval_max =
79 Duration::from_micros(1_250) * u32::from(LittleEndian::read_u16(&bytes[2..4]));
80 let latency = LittleEndian::read_u16(&bytes[4..6]);
81 let timeout = Duration::from_millis(10) * u32::from(LittleEndian::read_u16(&bytes[6..8]));
82 ConnectionIntervalBuilder::new()
83 .with_range(interval_min, interval_max)
84 .with_latency(latency)
85 .with_supervision_timeout(timeout)
86 .build()
87 }
88
89 fn interval_as_u16(d: Duration) -> u16 {
90 // T ms = N * 1.25 ms
91 // N = T / 1.25 ms
92 // = T / (5/4) ms
93 // = 4 * T ms / 5 ms
94 //
95 // Note: 1000 * 4 / 5 = 800
96 ((800 * d.as_secs()) as u32 + 4 * d.subsec_millis() / 5) as u16
97 }
98
99 fn timeout_as_u16(d: Duration) -> u16 {
100 // T ms = N * 10 ms
101 // N = T ms / 10 ms
102 ((100 * d.as_secs()) as u32 + d.subsec_millis() / 10) as u16
103 }
104}
105
106/// Intermediate builder for the [`ConnectionInterval`].
107#[derive(Default)]
108pub struct ConnectionIntervalBuilder {
109 interval: Option<(Duration, Duration)>,
110 conn_latency: Option<u16>,
111 supervision_timeout: Option<Duration>,
112}
113
114impl ConnectionIntervalBuilder {
115 /// Initializes a new builder.
116 pub fn new() -> ConnectionIntervalBuilder {
117 ConnectionIntervalBuilder {
118 interval: None,
119 conn_latency: None,
120 supervision_timeout: None,
121 }
122 }
123
124 /// Sets the connection interval range.
125 ///
126 /// # Errors
127 ///
128 /// There are no errors from this function, but it may cause errors in
129 /// [build](ConnectionIntervalBuilder::build) if:
130 /// - `min` is greater than `max`
131 /// - Either `min` or `max` is less than 7.5 ms or more than 4 seconds.
132 /// - `max` leads to an invalid relative supervision timeout.
133 pub fn with_range(&mut self, min: Duration, max: Duration) -> &mut ConnectionIntervalBuilder {
134 self.interval = Some((min, max));
135 self
136 }
137
138 /// Sets the connection latency.
139 ///
140 /// # Errors
141 ///
142 /// There are no errors from this function, but it may cause errors in
143 /// [build](ConnectionIntervalBuilder::build) if:
144 /// - `latency` is 500 or greater.
145 /// - `latency` leads to an invalid relative supervision timeout.
146 pub fn with_latency(&mut self, latency: u16) -> &mut ConnectionIntervalBuilder {
147 self.conn_latency = Some(latency);
148 self
149 }
150
151 /// Sets the supervision timeout.
152 ///
153 /// # Errors
154 ///
155 /// There are no errors from this function, but it may cause errors in
156 /// [build](ConnectionIntervalBuilder::build) if:
157 /// - `timeout` less than 100 ms or greater than 32 seconds
158 /// - `timeout` results in an invalid relative supervision timeout.
159 pub fn with_supervision_timeout(
160 &mut self,
161 timeout: Duration,
162 ) -> &mut ConnectionIntervalBuilder {
163 self.supervision_timeout = Some(timeout);
164 self
165 }
166
167 /// Builds the connection interval if all parameters are valid.
168 ///
169 /// # Errors
170 ///
171 /// - [Incomplete](ConnectionIntervalError::Incomplete) if any of
172 /// [`with_range`](ConnectionIntervalBuilder::with_range),
173 /// [`with_latency`](ConnectionIntervalBuilder::with_latency), or
174 /// [`with_supervision_timeout`](ConnectionIntervalBuilder::with_supervision_timeout) have not
175 /// been called.
176 /// - [IntervalTooShort](ConnectionIntervalError::IntervalTooShort) if the minimum range value
177 /// is less than 7.5 ms.
178 /// - [IntervalTooLong](ConnectionIntervalError::IntervalTooLong) if the maximum range value
179 /// is greater than 4 seconds.
180 /// - [IntervalInverted](ConnectionIntervalError::IntervalInverted) if the minimum range value
181 /// is greater than the maximum.
182 /// - [BadConnectionLatency](ConnectionIntervalError::BadConnectionLatency) if the connection
183 /// latency is 500 or more.
184 /// - [SupervisionTimeoutTooShort](ConnectionIntervalError::SupervisionTimeoutTooShort) if the
185 /// supervision timeout is less than 100 ms, or if it is less than the computed minimum: (1 +
186 /// latency) * interval max * 2.
187 /// - [SupervisionTimeoutTooLong](ConnectionIntervalError::SupervisionTimeoutTooLong) if the
188 /// supervision timeout is more than 32 seconds.
189 /// - [ImpossibleSupervisionTimeout](ConnectionIntervalError::ImpossibleSupervisionTimeout) if
190 /// the computed minimum supervision timeout ((1 + latency) * interval max * 2) is 32 seconds
191 /// or more.
192 pub fn build(&self) -> Result<ConnectionInterval, ConnectionIntervalError> {
193 if self.interval.is_none()
194 || self.conn_latency.is_none()
195 || self.supervision_timeout.is_none()
196 {
197 return Err(ConnectionIntervalError::Incomplete);
198 }
199
200 let interval = self.interval.unwrap();
201 const INTERVAL_MIN: Duration = Duration::from_micros(7500);
202 if interval.0 < INTERVAL_MIN {
203 return Err(ConnectionIntervalError::IntervalTooShort(interval.0));
204 }
205
206 const INTERVAL_MAX: Duration = Duration::from_secs(4);
207 if interval.1 > INTERVAL_MAX {
208 return Err(ConnectionIntervalError::IntervalTooLong(interval.1));
209 }
210
211 if interval.0 > interval.1 {
212 return Err(ConnectionIntervalError::IntervalInverted(
213 interval.0, interval.1,
214 ));
215 }
216
217 let conn_latency = self.conn_latency.unwrap();
218 const LATENCY_MAX: u16 = 0x1F3;
219 if conn_latency > LATENCY_MAX {
220 return Err(ConnectionIntervalError::BadConnectionLatency(conn_latency));
221 }
222
223 let supervision_timeout = self.supervision_timeout.unwrap();
224 let computed_timeout_min = interval.1 * (1 + u32::from(conn_latency)) * 2;
225 const TIMEOUT_MAX: Duration = Duration::from_secs(32);
226 if computed_timeout_min >= TIMEOUT_MAX {
227 return Err(ConnectionIntervalError::ImpossibleSupervisionTimeout(
228 computed_timeout_min,
229 ));
230 }
231
232 const TIMEOUT_ABS_MIN: Duration = Duration::from_millis(100);
233 let timeout_min = cmp::max(computed_timeout_min, TIMEOUT_ABS_MIN);
234 if supervision_timeout <= timeout_min {
235 return Err(ConnectionIntervalError::SupervisionTimeoutTooShort(
236 supervision_timeout,
237 timeout_min,
238 ));
239 }
240
241 if supervision_timeout > TIMEOUT_MAX {
242 return Err(ConnectionIntervalError::SupervisionTimeoutTooLong(
243 supervision_timeout,
244 ));
245 }
246
247 Ok(ConnectionInterval {
248 interval_: interval,
249 conn_latency_: conn_latency,
250 supervision_timeout_: supervision_timeout,
251 })
252 }
253}
254
255/// Types of errors that can occure when creating a [`ConnectionInterval`].
256#[derive(Copy, Clone, Debug, PartialEq)]
257pub enum ConnectionIntervalError {
258 /// At least one of any of [`with_range`](ConnectionIntervalBuilder::with_range),
259 /// [`with_latency`](ConnectionIntervalBuilder::with_latency), or
260 /// [`with_supervision_timeout`](ConnectionIntervalBuilder::with_supervision_timeout) has not
261 /// been called.
262 Incomplete,
263 /// The minimum range value is less than 7.5 ms. Includes the invalid value.
264 IntervalTooShort(Duration),
265 /// The maximum range value is greater than 4 seconds. Includes the invalid value.
266 IntervalTooLong(Duration),
267 /// The minimum range value is greater than the maximum. Includes the provided minimum and
268 /// maximum, respectively.
269 IntervalInverted(Duration, Duration),
270 /// The connection latency is 500 or more. Includes the provided value.
271 BadConnectionLatency(u16),
272 /// The supervision timeout is less than 100 ms, or it is less than the computed minimum: (1 +
273 /// latency) * interval max * 2. The first value is the provided timeout; the second is the
274 /// required minimum.
275 SupervisionTimeoutTooShort(Duration, Duration),
276 /// The supervision timeout is more than 32 seconds. Includes the provided timeout.
277 SupervisionTimeoutTooLong(Duration),
278 /// The computed minimum supervision timeout ((1 + latency) * interval max * 2) is 32 seconds
279 /// or more. Includes the computed minimum.
280 ImpossibleSupervisionTimeout(Duration),
281}
282
283/// Define a connection interval with its latency and supervision timeout. This value is
284/// returned from the controller.
285#[derive(Copy, Clone, Debug)]
286pub struct FixedConnectionInterval {
287 interval_: Duration,
288 conn_latency_: u16,
289 supervision_timeout_: Duration,
290}
291
292impl FixedConnectionInterval {
293 /// Deserializes the connection interval from the given byte buffer.
294 ///
295 /// - The interval value, appropriately converted (2 bytes)
296 /// - The connection latency (2 bytes)
297 /// - The supervision timeout, appropriately converted (2 bytes)
298 ///
299 /// # Panics
300 ///
301 /// The provided buffer must be at least 6 bytes long.
302 ///
303 /// # Errors
304 ///
305 /// Any of the errors from the [builder](ConnectionIntervalBuilder::build) except for
306 /// Incomplete.
307 pub fn from_bytes(bytes: &[u8]) -> Result<Self, ConnectionIntervalError> {
308 assert!(bytes.len() >= 6);
309
310 // Do the error checking with the standard connection interval builder. The min and max of
311 // the interval range are allowed to be equal.
312 let interval =
313 Duration::from_micros(1_250) * u32::from(LittleEndian::read_u16(&bytes[0..2]));
314 let latency = LittleEndian::read_u16(&bytes[2..4]);
315 let timeout = Duration::from_millis(10) * u32::from(LittleEndian::read_u16(&bytes[4..6]));
316 ConnectionIntervalBuilder::new()
317 .with_range(interval, interval)
318 .with_latency(latency)
319 .with_supervision_timeout(timeout)
320 .build()?;
321
322 Ok(FixedConnectionInterval {
323 interval_: interval,
324 conn_latency_: latency,
325 supervision_timeout_: timeout,
326 })
327 }
328
329 /// Returns the connection interval.
330 pub fn interval(&self) -> Duration {
331 self.interval_
332 }
333
334 /// Returns the connection latency, in number of events.
335 pub fn conn_latency(&self) -> u16 {
336 self.conn_latency_
337 }
338
339 /// Returns the supervision timeout.
340 pub fn supervision_timeout(&self) -> Duration {
341 self.supervision_timeout_
342 }
343}