use byteorder::{ByteOrder, LittleEndian};
use core::time::Duration;
#[derive(Clone, Debug)]
pub struct AdvertisingInterval {
interval: (Duration, Duration),
_advertising_type: AdvertisingType,
}
impl AdvertisingInterval {
pub fn for_type(adv_type: AdvertisingType) -> AdvertisingIntervalBuilder {
AdvertisingIntervalBuilder {
advertising_type: adv_type,
}
}
pub fn into_bytes(&self, bytes: &mut [u8]) {
if self._advertising_type == AdvertisingType::ConnectableDirectedHighDutyCycle {
bytes[0..4].copy_from_slice(&[0; 4]);
} else {
LittleEndian::write_u16(&mut bytes[0..2], Self::as_u16(self.interval.0));
LittleEndian::write_u16(&mut bytes[2..4], Self::as_u16(self.interval.1));
}
bytes[4] = self._advertising_type as u8;
}
fn as_u16(d: Duration) -> u16 {
(1600 * d.as_secs() as u32 + (d.subsec_micros() / 625)) as u16
}
pub fn advertising_type(&self) -> AdvertisingType {
self._advertising_type
}
}
pub struct AdvertisingIntervalBuilder {
advertising_type: AdvertisingType,
}
impl AdvertisingIntervalBuilder {
pub fn with_range(
&self,
min: Duration,
max: Duration,
) -> Result<AdvertisingInterval, AdvertisingIntervalError> {
const MIN: Duration = Duration::from_millis(20);
if min < MIN {
return Err(AdvertisingIntervalError::TooShort(min));
}
#[cfg(not(feature = "version-5-0"))]
{
if self.advertising_type == AdvertisingType::ScannableUndirected {
const SCANNABLE_MIN: Duration = Duration::from_millis(100);
if min < SCANNABLE_MIN {
return Err(AdvertisingIntervalError::TooShort(min));
}
}
}
const MAX: Duration = Duration::from_millis(10240);
if max > MAX {
return Err(AdvertisingIntervalError::TooLong(max));
}
if min > max {
return Err(AdvertisingIntervalError::Inverted(min, max));
}
Ok(AdvertisingInterval {
interval: (min, max),
_advertising_type: self.advertising_type,
})
}
pub fn build(&self) -> Result<AdvertisingInterval, AdvertisingIntervalError> {
if self.advertising_type == AdvertisingType::ConnectableDirectedHighDutyCycle {
Ok(AdvertisingInterval {
interval: (Duration::from_secs(0), Duration::from_secs(0)),
_advertising_type: self.advertising_type,
})
} else {
Err(AdvertisingIntervalError::NoRange)
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AdvertisingIntervalError {
TooShort(Duration),
TooLong(Duration),
Inverted(Duration, Duration),
NoRange,
}
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AdvertisingType {
ConnectableUndirected = 0x00,
ConnectableDirectedHighDutyCycle = 0x01,
ScannableUndirected = 0x02,
NonConnectableUndirected = 0x03,
ConnectableDirectedLowDutyCycle = 0x04,
}