"libbytes",
"libnum_traits",
"libthiserror",
+ "libbt_hci_custom_types",
],
}
return type_name_;
}
+std::string CustomFieldFixedSize::GetRustDataType() const {
+ return type_name_;
+}
+
int CustomFieldFixedSize::GenBounds(std::ostream& s, Size start_offset, Size end_offset, Size size) const {
if (!start_offset.empty()) {
// Default to start if available.
// We assume that custom fields will have a ToString() method
s << accessor << ".ToString()";
}
+
+std::string CustomFieldFixedSize::GetRustParseDataType() const {
+ return "[u8; " + std::to_string(GetSize().bytes()) + "]";
+}
+
+void CustomFieldFixedSize::GenRustGetter(std::ostream& s, Size start_offset, Size end_offset) const {
+ Size size = GetSize();
+ int num_leading_bits = GetRustBitOffset(s, start_offset, end_offset, GetSize());
+ if (num_leading_bits != 0) {
+ ERROR(this) << "must be byte aligned";
+ }
+ if (size.bits() % 8 != 0) {
+ ERROR(this) << "size must be in full bytes";
+ }
+
+ s << "let " << GetName() << " = bytes[" << start_offset.bytes() << "..";
+ s << start_offset.bytes() + size.bytes() << "].try_into().unwrap();";
+}
+
+void CustomFieldFixedSize::GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const {
+ Size size = GetSize();
+ int num_leading_bits = GetRustBitOffset(s, start_offset, end_offset, GetSize());
+ if (num_leading_bits != 0) {
+ ERROR(this) << "must be byte aligned";
+ }
+ if (size.bits() % 8 != 0) {
+ ERROR(this) << "size must be in full bytes";
+ }
+
+ s << "let " << GetName() << ": " << GetRustParseDataType() << " = self." << GetName() << ".into();";
+ s << "buffer[" << start_offset.bytes() << ".." << start_offset.bytes() + GetSize().bytes() << "].copy_from_slice(&"
+ << GetName() << ");";
+}
virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+ void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual std::string GetRustDataType() const override;
+
+ virtual std::string GetRustParseDataType() const override;
+
std::string type_name_;
};
InvalidPacketError
}
-pub struct Address {
- pub addr: [u8; 6],
-}
-
-pub struct ClassOfDevice {
- pub cod: [u8; 3],
-}
)";
}
"libgddi",
"liblog_rust",
"libbt_common",
+ "libbt_hci_custom_types",
],
proc_macros: [
"libnum_derive",
],
}
+
+rust_library {
+ name: "libbt_hci_custom_types",
+ defaults: ["gd_rust_defaults"],
+ crate_name: "bt_hci_custom_types",
+ srcs: ["custom_types/lib.rs"],
+ edition: "2018",
+}
--- /dev/null
+//! custom types to be imported by hci packet pdl
+//! (since hci depends on the packet library, we need to split these out)
+
+use std::convert::TryFrom;
+use std::fmt;
+
+/// Signal for "empty" address
+pub const EMPTY_ADDRESS: Address = Address { bytes: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00] };
+/// Signal for "any" address
+pub const ANY_ADDRESS: Address = Address { bytes: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF] };
+
+/// A Bluetooth address
+#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
+pub struct Address {
+ /// the actual bytes representing this address
+ pub bytes: [u8; 6],
+}
+
+impl Address {
+ /// whether this address is empty
+ pub fn is_empty(&self) -> bool {
+ *self == EMPTY_ADDRESS
+ }
+}
+
+impl fmt::Display for Address {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
+ self.bytes[5],
+ self.bytes[4],
+ self.bytes[3],
+ self.bytes[2],
+ self.bytes[1],
+ self.bytes[0]
+ )
+ }
+}
+
+/// When you parse an address and it's not valid
+#[derive(Debug, Clone)]
+pub struct InvalidAddressError;
+
+impl TryFrom<&[u8]> for Address {
+ type Error = InvalidAddressError;
+
+ fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
+ if slice.len() == 6 {
+ match <[u8; 6]>::try_from(slice) {
+ Ok(bytes) => Ok(Self { bytes }),
+ Err(_) => Err(InvalidAddressError),
+ }
+ } else {
+ Err(InvalidAddressError)
+ }
+ }
+}
+
+impl From<Address> for [u8; 6] {
+ fn from(addr: Address) -> [u8; 6] {
+ addr.bytes
+ }
+}
+
+/// A Bluetooth class of device
+#[derive(Clone, Eq, Copy, PartialEq, Hash, Ord, PartialOrd, Debug)]
+pub struct ClassOfDevice {
+ /// the actual bytes representing this class of device
+ pub bytes: [u8; 3],
+}
+
+impl fmt::Display for ClassOfDevice {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "{:03X}-{:01X}-{:02X}",
+ ((self.bytes[2] as u16) << 4) | ((self.bytes[1] as u16) >> 4),
+ self.bytes[1] & 0x0F,
+ self.bytes[0]
+ )
+ }
+}
+
+/// When you parse a class of device and it's not valid
+#[derive(Debug, Clone)]
+pub struct InvalidClassOfDeviceError;
+
+impl TryFrom<&[u8]> for ClassOfDevice {
+ type Error = InvalidClassOfDeviceError;
+
+ fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
+ if slice.len() == 3 {
+ match <[u8; 3]>::try_from(slice) {
+ Ok(bytes) => Ok(Self { bytes }),
+ Err(_) => Err(InvalidClassOfDeviceError),
+ }
+ } else {
+ Err(InvalidClassOfDeviceError)
+ }
+ }
+}
+
+impl From<ClassOfDevice> for [u8; 3] {
+ fn from(cod: ClassOfDevice) -> [u8; 3] {
+ cod.bytes
+ }
+}
//! Loads info from the controller at startup
-use crate::HciExports;
+use crate::{Address, HciExports};
use bt_packets::hci::{
Enable, ErrorCode, LeMaximumDataLength, LeReadBufferSizeV1Builder, LeReadBufferSizeV2Builder,
LeReadConnectListSizeBuilder, LeReadLocalSupportedFeaturesBuilder,
LeReadNumberOfSupportedAdvertisingSetsBuilder, LeReadPeriodicAdvertiserListSizeBuilder,
LeReadResolvingListSizeBuilder, LeReadSuggestedDefaultDataLengthBuilder,
LeReadSupportedStatesBuilder, LeSetEventMaskBuilder, LocalVersionInformation, OpCode,
- OpCodeIndex, ReadBufferSizeBuilder, ReadLocalExtendedFeaturesBuilder, ReadLocalNameBuilder,
- ReadLocalSupportedCommandsBuilder, ReadLocalVersionInformationBuilder, SetEventMaskBuilder,
- WriteLeHostSupportBuilder, WriteSimplePairingModeBuilder,
+ OpCodeIndex, ReadBdAddrBuilder, ReadBufferSizeBuilder, ReadLocalExtendedFeaturesBuilder,
+ ReadLocalNameBuilder, ReadLocalSupportedCommandsBuilder, ReadLocalVersionInformationBuilder,
+ SetEventMaskBuilder, WriteLeHostSupportBuilder, WriteSimplePairingModeBuilder,
};
use gddi::{module, provides, Stoppable};
use num_traits::ToPrimitive;
#[provides]
async fn provide_controller(mut hci: HciExports) -> ControllerExports {
- assert_success!(hci.send(LeSetEventMaskBuilder {
- le_event_mask: 0x0000000000021e7f
- }));
- assert_success!(hci.send(SetEventMaskBuilder {
- event_mask: 0x3dbfffffffffffff
- }));
- assert_success!(hci.send(WriteSimplePairingModeBuilder {
- simple_pairing_mode: Enable::Enabled
- }));
- assert_success!(hci.send(WriteLeHostSupportBuilder {
- le_supported_host: Enable::Enabled
- }));
+ assert_success!(hci.send(LeSetEventMaskBuilder { le_event_mask: 0x0000000000021e7f }));
+ assert_success!(hci.send(SetEventMaskBuilder { event_mask: 0x3dbfffffffffffff }));
+ assert_success!(
+ hci.send(WriteSimplePairingModeBuilder { simple_pairing_mode: Enable::Enabled })
+ );
+ assert_success!(hci.send(WriteLeHostSupportBuilder { le_supported_host: Enable::Enabled }));
let name = null_terminated_to_string(
assert_success!(hci.send(ReadLocalNameBuilder {})).get_local_name(),
0
};
+ let address = assert_success!(hci.send(ReadBdAddrBuilder {})).get_bd_addr();
+
ControllerExports {
name,
+ address,
version_info,
commands,
lmp_features,
#[derive(Clone, Stoppable)]
pub struct ControllerExports {
name: String,
+ address: Address,
version_info: LocalVersionInformation,
commands: SupportedCommands,
lmp_features: Vec<u64>,
/// HCI layer facade service
pub mod facade;
+pub use bt_hci_custom_types::*;
+
use bt_common::time::Alarm;
use bt_hal::HalExports;
use bt_packets::hci::EventChild::{
#![allow(missing_docs)]
pub mod hci {
+ use bt_hci_custom_types::*;
+
include!(concat!(env!("OUT_DIR"), "/hci_packets.rs"));
}