#![no_std]
#![feature(const_fn)]
#![feature(try_from)]
#![feature(never_type)]
#![deny(missing_docs)]
#[macro_use]
extern crate bitflags;
extern crate byteorder;
extern crate nb;
#[macro_use]
mod bitflag_array;
pub mod event;
pub mod host;
mod opcode;
pub mod types;
pub use event::Event;
pub use opcode::Opcode;
use core::convert::TryFrom;
use core::fmt::Debug;
pub trait Controller {
type Error;
type Header;
type Vendor: Vendor;
fn write(&mut self, header: &[u8], payload: &[u8]) -> nb::Result<(), Self::Error>;
fn read_into(&mut self, buffer: &mut [u8]) -> nb::Result<(), Self::Error>;
fn peek(&mut self, n: usize) -> nb::Result<u8, Self::Error>;
}
pub trait Vendor {
type Status: TryFrom<u8, Error = BadStatusError> + Into<u8> + Clone + Debug;
type Event: event::VendorEvent;
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Status<V> {
Success,
UnknownCommand,
UnknownConnectionId,
HardwareFailure,
PageTimeout,
AuthFailure,
PinOrKeyMissing,
OutOfMemory,
ConnectionTimeout,
ConnectionLimitExceeeded,
SyncConnectionLimitExceeded,
ConnectionAlreadyExists,
CommandDisallowed,
LimitedResources,
ConnectionRejectedSecurity,
UnacceptableBdAddr,
AcceptTimeoutExceeded,
UnsupportedFeature,
InvalidParameters,
RemoteTerminationByUser,
RemoteTerminationLowResources,
RemoteTerminationPowerOff,
ConnectionTerminatedByHost,
RepeatedAttempts,
PairingNotAllowed,
UnknownLmpPdu,
UnsupportedRemoteFeature,
ScoOffsetRejected,
ScoIntervalRejected,
ScoAirModeRejected,
InvalidLmpParameters,
UnspecifiedError,
UnsupportedLmpParameterValue,
RoleChangeNotAllowed,
LmpResponseTimeout,
LmpTransactionCollision,
LmpPduNotAllowed,
EncryptionModeNotAcceptable,
LinkKeyCannotBeChanged,
RequestedQosNotSupported,
InstantPassed,
PairingWithUnitKeyNotSupported,
DifferentTransactionCollision,
ReservedforFutureUse,
QosUnacceptableParameter,
QosRejected,
ChannelClassificationNotSupported,
InsufficientSecurity,
ParameterOutOfMandatoryRange,
ReservedForFutureUse49,
RoleSwitchPending,
ReservedForFutureUse51,
ReservedSlotViolation,
RoleSwitchFailed,
ExtendedInquiryResponseTooLarge,
SecureSimplePairingNotSupportedByHost,
HostBusyPairing,
ConnectionRejectedNoSuitableChannel,
ControllerBusy,
UnacceptableConnectionParameters,
AdvertisingTimeout,
ConnectionTerminatedMicFailure,
ConnectionFailedToEstablish,
MacConnectionFailed,
CoarseClockAdjustmentRejectedDraggingAttempted,
#[cfg(feature = "version-5-0")]
Type0SubmapNotDefined,
#[cfg(feature = "version-5-0")]
UnknownAdvertisingId,
#[cfg(feature = "version-5-0")]
LimitReached,
#[cfg(feature = "version-5-0")]
OperationCancelledByHost,
Vendor(V),
}
pub enum BadStatusError {
BadValue(u8),
}
impl<V> core::convert::TryFrom<u8> for Status<V>
where
V: core::convert::TryFrom<u8>,
{
type Error = V::Error;
fn try_from(value: u8) -> Result<Status<V>, Self::Error> {
match value {
0x00 => Ok(Status::Success),
0x01 => Ok(Status::UnknownCommand),
0x02 => Ok(Status::UnknownConnectionId),
0x03 => Ok(Status::HardwareFailure),
0x04 => Ok(Status::PageTimeout),
0x05 => Ok(Status::AuthFailure),
0x06 => Ok(Status::PinOrKeyMissing),
0x07 => Ok(Status::OutOfMemory),
0x08 => Ok(Status::ConnectionTimeout),
0x09 => Ok(Status::ConnectionLimitExceeeded),
0x0A => Ok(Status::SyncConnectionLimitExceeded),
0x0B => Ok(Status::ConnectionAlreadyExists),
0x0C => Ok(Status::CommandDisallowed),
0x0D => Ok(Status::LimitedResources),
0x0E => Ok(Status::ConnectionRejectedSecurity),
0x0F => Ok(Status::UnacceptableBdAddr),
0x10 => Ok(Status::AcceptTimeoutExceeded),
0x11 => Ok(Status::UnsupportedFeature),
0x12 => Ok(Status::InvalidParameters),
0x13 => Ok(Status::RemoteTerminationByUser),
0x14 => Ok(Status::RemoteTerminationLowResources),
0x15 => Ok(Status::RemoteTerminationPowerOff),
0x16 => Ok(Status::ConnectionTerminatedByHost),
0x17 => Ok(Status::RepeatedAttempts),
0x18 => Ok(Status::PairingNotAllowed),
0x19 => Ok(Status::UnknownLmpPdu),
0x1A => Ok(Status::UnsupportedRemoteFeature),
0x1B => Ok(Status::ScoOffsetRejected),
0x1C => Ok(Status::ScoIntervalRejected),
0x1D => Ok(Status::ScoAirModeRejected),
0x1E => Ok(Status::InvalidLmpParameters),
0x1F => Ok(Status::UnspecifiedError),
0x20 => Ok(Status::UnsupportedLmpParameterValue),
0x21 => Ok(Status::RoleChangeNotAllowed),
0x22 => Ok(Status::LmpResponseTimeout),
0x23 => Ok(Status::LmpTransactionCollision),
0x24 => Ok(Status::LmpPduNotAllowed),
0x25 => Ok(Status::EncryptionModeNotAcceptable),
0x26 => Ok(Status::LinkKeyCannotBeChanged),
0x27 => Ok(Status::RequestedQosNotSupported),
0x28 => Ok(Status::InstantPassed),
0x29 => Ok(Status::PairingWithUnitKeyNotSupported),
0x2A => Ok(Status::DifferentTransactionCollision),
0x2B => Ok(Status::ReservedforFutureUse),
0x2C => Ok(Status::QosUnacceptableParameter),
0x2D => Ok(Status::QosRejected),
0x2E => Ok(Status::ChannelClassificationNotSupported),
0x2F => Ok(Status::InsufficientSecurity),
0x30 => Ok(Status::ParameterOutOfMandatoryRange),
0x31 => Ok(Status::ReservedForFutureUse49),
0x32 => Ok(Status::RoleSwitchPending),
0x33 => Ok(Status::ReservedForFutureUse51),
0x34 => Ok(Status::ReservedSlotViolation),
0x35 => Ok(Status::RoleSwitchFailed),
0x36 => Ok(Status::ExtendedInquiryResponseTooLarge),
0x37 => Ok(Status::SecureSimplePairingNotSupportedByHost),
0x38 => Ok(Status::HostBusyPairing),
0x39 => Ok(Status::ConnectionRejectedNoSuitableChannel),
0x3A => Ok(Status::ControllerBusy),
0x3B => Ok(Status::UnacceptableConnectionParameters),
0x3C => Ok(Status::AdvertisingTimeout),
0x3D => Ok(Status::ConnectionTerminatedMicFailure),
0x3E => Ok(Status::ConnectionFailedToEstablish),
0x3F => Ok(Status::MacConnectionFailed),
0x40 => Ok(Status::CoarseClockAdjustmentRejectedDraggingAttempted),
0x41 => {
#[cfg(feature = "version-5-0")]
{
Ok(Status::Type0SubmapNotDefined)
}
#[cfg(not(feature = "version-5-0"))]
{
Ok(Status::Vendor(V::try_from(value)?))
}
}
0x42 => {
#[cfg(feature = "version-5-0")]
{
Ok(Status::UnknownAdvertisingId)
}
#[cfg(not(feature = "version-5-0"))]
{
Ok(Status::Vendor(V::try_from(value)?))
}
}
0x43 => {
#[cfg(feature = "version-5-0")]
{
Ok(Status::LimitReached)
}
#[cfg(not(feature = "version-5-0"))]
{
Ok(Status::Vendor(V::try_from(value)?))
}
}
0x44 => {
#[cfg(feature = "version-5-0")]
{
Ok(Status::OperationCancelledByHost)
}
#[cfg(not(feature = "version-5-0"))]
{
Ok(Status::Vendor(V::try_from(value)?))
}
}
_ => Ok(Status::Vendor(V::try_from(value)?)),
}
}
}
impl<V> core::convert::Into<u8> for Status<V>
where
V: core::convert::Into<u8>,
{
fn into(self) -> u8 {
match self {
Status::Success => 0x00,
Status::UnknownCommand => 0x01,
Status::UnknownConnectionId => 0x02,
Status::HardwareFailure => 0x03,
Status::PageTimeout => 0x04,
Status::AuthFailure => 0x05,
Status::PinOrKeyMissing => 0x06,
Status::OutOfMemory => 0x07,
Status::ConnectionTimeout => 0x08,
Status::ConnectionLimitExceeeded => 0x09,
Status::SyncConnectionLimitExceeded => 0x0A,
Status::ConnectionAlreadyExists => 0x0B,
Status::CommandDisallowed => 0x0C,
Status::LimitedResources => 0x0D,
Status::ConnectionRejectedSecurity => 0x0E,
Status::UnacceptableBdAddr => 0x0F,
Status::AcceptTimeoutExceeded => 0x10,
Status::UnsupportedFeature => 0x11,
Status::InvalidParameters => 0x12,
Status::RemoteTerminationByUser => 0x13,
Status::RemoteTerminationLowResources => 0x14,
Status::RemoteTerminationPowerOff => 0x15,
Status::ConnectionTerminatedByHost => 0x16,
Status::RepeatedAttempts => 0x17,
Status::PairingNotAllowed => 0x18,
Status::UnknownLmpPdu => 0x19,
Status::UnsupportedRemoteFeature => 0x1A,
Status::ScoOffsetRejected => 0x1B,
Status::ScoIntervalRejected => 0x1C,
Status::ScoAirModeRejected => 0x1D,
Status::InvalidLmpParameters => 0x1E,
Status::UnspecifiedError => 0x1F,
Status::UnsupportedLmpParameterValue => 0x20,
Status::RoleChangeNotAllowed => 0x21,
Status::LmpResponseTimeout => 0x22,
Status::LmpTransactionCollision => 0x23,
Status::LmpPduNotAllowed => 0x24,
Status::EncryptionModeNotAcceptable => 0x25,
Status::LinkKeyCannotBeChanged => 0x26,
Status::RequestedQosNotSupported => 0x27,
Status::InstantPassed => 0x28,
Status::PairingWithUnitKeyNotSupported => 0x29,
Status::DifferentTransactionCollision => 0x2A,
Status::ReservedforFutureUse => 0x2B,
Status::QosUnacceptableParameter => 0x2C,
Status::QosRejected => 0x2D,
Status::ChannelClassificationNotSupported => 0x2E,
Status::InsufficientSecurity => 0x2F,
Status::ParameterOutOfMandatoryRange => 0x30,
Status::ReservedForFutureUse49 => 0x31,
Status::RoleSwitchPending => 0x32,
Status::ReservedForFutureUse51 => 0x33,
Status::ReservedSlotViolation => 0x34,
Status::RoleSwitchFailed => 0x35,
Status::ExtendedInquiryResponseTooLarge => 0x36,
Status::SecureSimplePairingNotSupportedByHost => 0x37,
Status::HostBusyPairing => 0x38,
Status::ConnectionRejectedNoSuitableChannel => 0x39,
Status::ControllerBusy => 0x3A,
Status::UnacceptableConnectionParameters => 0x3B,
Status::AdvertisingTimeout => 0x3C,
Status::ConnectionTerminatedMicFailure => 0x3D,
Status::ConnectionFailedToEstablish => 0x3E,
Status::MacConnectionFailed => 0x3F,
Status::CoarseClockAdjustmentRejectedDraggingAttempted => 0x40,
_ => {
#[cfg(feature = "version-5-0")]
{
match self {
Status::Type0SubmapNotDefined => 0x41,
Status::UnknownAdvertisingId => 0x42,
Status::LimitReached => 0x43,
Status::OperationCancelledByHost => 0x44,
Status::Vendor(v) => v.into(),
_ => 0xFF,
}
}
#[cfg(not(feature = "version-5-0"))]
{
if let Status::Vendor(v) = self {
v.into()
} else {
0xFF
}
}
}
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ConnectionHandle(pub u16);
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct BdAddr(pub [u8; 6]);
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BdAddrType {
Public(BdAddr),
Random(BdAddr),
}
impl BdAddrType {
pub fn into_bytes(&self, bytes: &mut [u8]) {
assert_eq!(bytes.len(), 7);
match *self {
BdAddrType::Public(addr) => {
bytes[0] = 0;
bytes[1..7].copy_from_slice(&addr.0);
}
BdAddrType::Random(addr) => {
bytes[0] = 1;
bytes[1..7].copy_from_slice(&addr.0);
}
}
}
}
pub struct BdAddrTypeError(pub u8);
pub fn to_bd_addr_type(bd_addr_type: u8, addr: BdAddr) -> Result<BdAddrType, BdAddrTypeError> {
match bd_addr_type {
0 => Ok(BdAddrType::Public(addr)),
1 => Ok(BdAddrType::Random(addr)),
_ => Err(BdAddrTypeError(bd_addr_type)),
}
}
bitflags! {
#[derive(Default)]
pub struct LinkLayerFeature : u64 {
const LE_ENCRYPTION = 1 << 0;
const CONNECTION_PARAMETERS_REQUEST_PROCEDURE = 1 << 1;
const EXTENDED_REJECT_INDICATION = 1 << 2;
const PERIPHERAL_INITIATED_FEATURES_EXCHANGE = 1 << 3;
const LE_PING = 1 << 4;
#[cfg(any(feature = "version-4-2", feature = "version-5-0"))]
const LE_DATA_PACKET_LENGTH_EXTENSION = 1 << 5;
#[cfg(any(feature = "version-4-2", feature = "version-5-0"))]
const LL_PRIVACY = 1 << 6;
#[cfg(any(feature = "version-4-2", feature = "version-5-0"))]
const EXTENDED_SCANNER_FILTER_POLICIES = 1 << 7;
#[cfg(feature = "version-5-0")]
const LE_2M_PHY = 1 << 8;
#[cfg(feature = "version-5-0")]
const STABLE_MODULATION_INDEX_TX = 1 << 9;
#[cfg(feature = "version-5-0")]
const STABLE_MODULATION_INDEX_RX = 1 << 10;
#[cfg(feature = "version-5-0")]
const LE_CODED_PHY = 1 << 11;
#[cfg(feature = "version-5-0")]
const LE_EXTENDED_ADVERTISING = 1 << 12;
#[cfg(feature = "version-5-0")]
const LE_PERIODIC_ADVERTISING = 1 << 13;
#[cfg(feature = "version-5-0")]
const CHANNEL_SELECTION_ALGORITHM_2 = 1 << 14;
#[cfg(feature = "version-5-0")]
const LE_POWER_CLASS_1 = 1 << 15;
#[cfg(feature = "version-5-0")]
const MINIMUM_NUMBER_OF_USED_CHANNELS_PROCEDURE = 1 << 16;
}
}
bitflag_array! {
#[derive(Copy, Clone, Debug)]
pub struct ChannelClassification : 5;
pub struct ChannelFlag;
const CH_0 = 0, 1 << 0;
const CH_1 = 0, 1 << 1;
const CH_2 = 0, 1 << 2;
const CH_3 = 0, 1 << 3;
const CH_4 = 0, 1 << 4;
const CH_5 = 0, 1 << 5;
const CH_6 = 0, 1 << 6;
const CH_7 = 0, 1 << 7;
const CH_8 = 1, 1 << 0;
const CH_9 = 1, 1 << 1;
const CH_10 = 1, 1 << 2;
const CH_11 = 1, 1 << 3;
const CH_12 = 1, 1 << 4;
const CH_13 = 1, 1 << 5;
const CH_14 = 1, 1 << 6;
const CH_15 = 1, 1 << 7;
const CH_16 = 2, 1 << 0;
const CH_17 = 2, 1 << 1;
const CH_18 = 2, 1 << 2;
const CH_19 = 2, 1 << 3;
const CH_20 = 2, 1 << 4;
const CH_21 = 2, 1 << 5;
const CH_22 = 2, 1 << 6;
const CH_23 = 2, 1 << 7;
const CH_24 = 3, 1 << 0;
const CH_25 = 3, 1 << 1;
const CH_26 = 3, 1 << 2;
const CH_27 = 3, 1 << 3;
const CH_28 = 3, 1 << 4;
const CH_29 = 3, 1 << 5;
const CH_30 = 3, 1 << 6;
const CH_31 = 3, 1 << 7;
const CH_32 = 4, 1 << 0;
const CH_33 = 4, 1 << 1;
const CH_34 = 4, 1 << 2;
const CH_35 = 4, 1 << 3;
const CH_36 = 4, 1 << 4;
}