extern crate bluetooth_hci as hci;
extern crate byteorder;
extern crate embedded_hal as hal;
extern crate nb;
use byteorder::{ByteOrder, LittleEndian};
pub trait Commands {
type Error;
fn get_firmware_revision(&mut self) -> nb::Result<(), Self::Error>;
fn write_config_data(&mut self, config: &ConfigData) -> nb::Result<(), Self::Error>;
fn read_config_data(&mut self, param: ConfigParameter) -> nb::Result<(), Self::Error>;
fn set_tx_power_level(&mut self, level: PowerLevel) -> nb::Result<(), Self::Error>;
fn device_standby(&mut self) -> nb::Result<(), Self::Error>;
fn get_tx_test_packet_count(&mut self) -> nb::Result<(), Self::Error>;
fn start_tone(&mut self, channel: u8) -> nb::Result<(), Error<Self::Error>>;
fn stop_tone(&mut self) -> nb::Result<(), Self::Error>;
fn get_link_status(&mut self) -> nb::Result<(), Self::Error>;
fn get_anchor_period(&mut self) -> nb::Result<(), Self::Error>;
}
impl<'bnrg, 'spi, 'dbuf, SPI, OutputPin1, OutputPin2, InputPin, SpiError, GpioError> Commands
for crate::ActiveBlueNRG<'bnrg, 'spi, 'dbuf, SPI, OutputPin1, OutputPin2, InputPin, GpioError>
where
SPI: hal::blocking::spi::Transfer<u8, Error = SpiError>
+ hal::blocking::spi::Write<u8, Error = SpiError>,
OutputPin1: hal::digital::v2::OutputPin<Error = GpioError>,
OutputPin2: hal::digital::v2::OutputPin<Error = GpioError>,
InputPin: hal::digital::v2::InputPin<Error = GpioError>,
{
type Error = crate::Error<SpiError, GpioError>;
fn get_firmware_revision(&mut self) -> nb::Result<(), Self::Error> {
self.write_command(crate::opcode::HAL_GET_FIRMWARE_REVISION, &[])
}
impl_variable_length_params!(
write_config_data,
ConfigData,
crate::opcode::HAL_WRITE_CONFIG_DATA
);
fn read_config_data(&mut self, param: ConfigParameter) -> nb::Result<(), Self::Error> {
self.write_command(crate::opcode::HAL_READ_CONFIG_DATA, &[param as u8])
}
fn set_tx_power_level(&mut self, level: PowerLevel) -> nb::Result<(), Self::Error> {
let mut bytes = [0; 2];
LittleEndian::write_u16(&mut bytes, level as u16);
self.write_command(crate::opcode::HAL_SET_TX_POWER_LEVEL, &bytes)
}
fn device_standby(&mut self) -> nb::Result<(), Self::Error> {
self.write_command(crate::opcode::HAL_DEVICE_STANDBY, &[])
}
fn get_tx_test_packet_count(&mut self) -> nb::Result<(), Self::Error> {
self.write_command(crate::opcode::HAL_TX_TEST_PACKET_COUNT, &[])
}
fn start_tone(&mut self, channel: u8) -> nb::Result<(), Error<Self::Error>> {
const MAX_CHANNEL: u8 = 39;
if channel > MAX_CHANNEL {
return Err(nb::Error::Other(Error::InvalidChannel(channel)));
}
self.write_command(crate::opcode::HAL_START_TONE, &[channel as u8])
.map_err(rewrap_error)
}
fn stop_tone(&mut self) -> nb::Result<(), Self::Error> {
self.write_command(crate::opcode::HAL_STOP_TONE, &[])
}
fn get_link_status(&mut self) -> nb::Result<(), Self::Error> {
self.write_command(crate::opcode::HAL_GET_LINK_STATUS, &[])
}
fn get_anchor_period(&mut self) -> nb::Result<(), Self::Error> {
self.write_command(crate::opcode::HAL_GET_ANCHOR_PERIOD, &[])
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Error<E> {
InvalidChannel(u8),
Comm(E),
}
fn rewrap_error<E>(e: nb::Error<E>) -> nb::Error<Error<E>> {
match e {
nb::Error::WouldBlock => nb::Error::WouldBlock,
nb::Error::Other(c) => nb::Error::Other(Error::Comm(c)),
}
}
pub struct ConfigData {
offset: u8,
length: u8,
value_buf: [u8; ConfigData::MAX_LENGTH],
}
impl ConfigData {
pub const MAX_LENGTH: usize = 0x2E;
pub fn copy_into_slice(&self, bytes: &mut [u8]) -> usize {
bytes[0] = self.offset;
bytes[1] = self.length;
let len = self.length as usize;
bytes[2..2 + len].copy_from_slice(&self.value_buf[..len]);
2 + len
}
pub fn public_address(addr: hci::BdAddr) -> ConfigDataDiversifierBuilder {
let mut data = Self {
offset: 0,
length: 6,
value_buf: [0; Self::MAX_LENGTH],
};
data.value_buf[0..6].copy_from_slice(&addr.0);
ConfigDataDiversifierBuilder { data }
}
pub fn diversifier(d: u16) -> ConfigDataEncryptionRootBuilder {
let mut data = Self {
offset: 6,
length: 2,
value_buf: [0; Self::MAX_LENGTH],
};
LittleEndian::write_u16(&mut data.value_buf[0..2], d);
ConfigDataEncryptionRootBuilder { data }
}
pub fn encryption_root(key: &hci::host::EncryptionKey) -> ConfigDataIdentityRootBuilder {
let mut data = Self {
offset: 8,
length: 16,
value_buf: [0; Self::MAX_LENGTH],
};
data.value_buf[0..16].copy_from_slice(&key.0);
ConfigDataIdentityRootBuilder { data }
}
pub fn identity_root(key: &hci::host::EncryptionKey) -> ConfigDataLinkLayerOnlyBuilder {
let mut data = Self {
offset: 24,
length: 16,
value_buf: [0; Self::MAX_LENGTH],
};
data.value_buf[0..16].copy_from_slice(&key.0);
ConfigDataLinkLayerOnlyBuilder { data }
}
pub fn link_layer_only(ll_only: bool) -> ConfigDataRoleBuilder {
let mut data = Self {
offset: 40,
length: 1,
value_buf: [0; Self::MAX_LENGTH],
};
data.value_buf[0] = ll_only as u8;
ConfigDataRoleBuilder { data }
}
pub fn role(role: Role) -> ConfigDataCompleteBuilder {
let mut data = Self {
offset: 41,
length: 1,
value_buf: [0; Self::MAX_LENGTH],
};
data.value_buf[0] = role as u8;
ConfigDataCompleteBuilder { data }
}
}
pub struct ConfigDataDiversifierBuilder {
data: ConfigData,
}
impl ConfigDataDiversifierBuilder {
pub fn diversifier(mut self, d: u16) -> ConfigDataEncryptionRootBuilder {
let len = self.data.length as usize;
LittleEndian::write_u16(&mut self.data.value_buf[len..2 + len], d);
self.data.length += 2;
ConfigDataEncryptionRootBuilder { data: self.data }
}
pub fn build(self) -> ConfigData {
self.data
}
}
pub struct ConfigDataEncryptionRootBuilder {
data: ConfigData,
}
impl ConfigDataEncryptionRootBuilder {
pub fn encryption_root(
mut self,
key: &hci::host::EncryptionKey,
) -> ConfigDataIdentityRootBuilder {
let len = self.data.length as usize;
self.data.value_buf[len..16 + len].copy_from_slice(&key.0);
self.data.length += 16;
ConfigDataIdentityRootBuilder { data: self.data }
}
pub fn build(self) -> ConfigData {
self.data
}
}
pub struct ConfigDataIdentityRootBuilder {
data: ConfigData,
}
impl ConfigDataIdentityRootBuilder {
pub fn identity_root(
mut self,
key: &hci::host::EncryptionKey,
) -> ConfigDataLinkLayerOnlyBuilder {
let len = self.data.length as usize;
self.data.value_buf[len..16 + len].copy_from_slice(&key.0);
self.data.length += 16;
ConfigDataLinkLayerOnlyBuilder { data: self.data }
}
pub fn build(self) -> ConfigData {
self.data
}
}
pub struct ConfigDataLinkLayerOnlyBuilder {
data: ConfigData,
}
impl ConfigDataLinkLayerOnlyBuilder {
pub fn link_layer_only(mut self, ll_only: bool) -> ConfigDataRoleBuilder {
self.data.value_buf[self.data.length as usize] = ll_only as u8;
self.data.length += 1;
ConfigDataRoleBuilder { data: self.data }
}
pub fn build(self) -> ConfigData {
self.data
}
}
pub struct ConfigDataRoleBuilder {
data: ConfigData,
}
impl ConfigDataRoleBuilder {
pub fn role(mut self, role: Role) -> ConfigDataCompleteBuilder {
self.data.value_buf[self.data.length as usize] = role as u8;
self.data.length += 1;
ConfigDataCompleteBuilder { data: self.data }
}
pub fn build(self) -> ConfigData {
self.data
}
}
pub struct ConfigDataCompleteBuilder {
data: ConfigData,
}
impl ConfigDataCompleteBuilder {
pub fn build(self) -> ConfigData {
self.data
}
}
#[repr(u8)]
pub enum Role {
Peripheral6Kb = 1,
Peripheral12Kb = 2,
Primary12Kb = 3,
SimultaneousAdvertisingScanning = 4,
}
#[repr(u8)]
pub enum ConfigParameter {
PublicAddress = 0,
Diversifier = 6,
EncryptionRoot = 8,
IdentityRoot = 24,
LinkLayerOnly = 40,
Role = 41,
}
#[repr(u16)]
pub enum PowerLevel {
DbmNeg18 = 0x000,
DbmNeg15 = 0x001,
DbmNeg14_7 = 0x100,
DbmNeg11_7 = 0x101,
DbmNeg11_4 = 0x200,
DbmNeg8_4 = 0x201,
DbmNeg8_1 = 0x300,
DbmNeg5_1 = 0x301,
DbmNeg4_9 = 0x400,
DbmNeg2_1 = 0x401,
DbmNeg1_6 = 0x500,
Dbm1_4 = 0x501,
Dbm1_7 = 0x600,
Dbm4_7 = 0x601,
Dbm5_0 = 0x700,
Dbm8_0 = 0x701,
}