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}