1212// See the License for the specific language governing permissions and
1313// limitations under the License.
1414
15+ use itertools:: Itertools ;
1516pub use pdl_runtime:: { Error , Packet } ;
17+ use std:: fmt;
1618
17- use crate :: internal:: hci:: packets:: { Acl , Command , Event , Sco } ;
19+ use crate :: internal:: hci:: packets:: { Acl , AddressType , Command , Event , Sco } ;
1820use pdl_derive:: pdl;
1921
2022#[ allow( missing_docs, warnings, clippy:: all) ]
@@ -23,6 +25,110 @@ pub mod packets {}
2325#[ cfg( test) ]
2426mod tests;
2527
28+ /// A Bluetooth address
29+ #[ derive( Clone , Copy , PartialEq , Eq , Hash ) ]
30+ pub struct Address {
31+ /// Little-endian bytes
32+ le_bytes : [ u8 ; 6 ] ,
33+ address_type : AddressType ,
34+ }
35+
36+ impl Address {
37+ /// Creates a new address with the provided little-endian bytes.
38+ pub fn from_le_bytes ( le_bytes : [ u8 ; 6 ] , address_type : AddressType ) -> Self {
39+ Self {
40+ le_bytes,
41+ address_type,
42+ }
43+ }
44+
45+ /// Creates a new address with the provided big endian hex (with or without `:` separators).
46+ ///
47+ /// # Examples
48+ ///
49+ /// ```
50+ /// use bumble::{wrapper::{hci::{Address, packets::AddressType}}};
51+ /// let hex = "F0:F1:F2:F3:F4:F5";
52+ /// assert_eq!(
53+ /// hex,
54+ /// Address::from_be_hex(hex, AddressType::PublicDeviceAddress).unwrap().as_be_hex()
55+ /// );
56+ /// ```
57+ pub fn from_be_hex (
58+ address : & str ,
59+ address_type : AddressType ,
60+ ) -> Result < Self , InvalidAddressHex > {
61+ let filtered: String = address. chars ( ) . filter ( |c| * c != ':' ) . collect ( ) ;
62+ let mut bytes: [ u8 ; 6 ] = hex:: decode ( filtered)
63+ . map_err ( |_| InvalidAddressHex { address } ) ?
64+ . try_into ( )
65+ . map_err ( |_| InvalidAddressHex { address } ) ?;
66+ bytes. reverse ( ) ;
67+
68+ Ok ( Self {
69+ le_bytes : bytes,
70+ address_type,
71+ } )
72+ }
73+
74+ /// The type of address
75+ pub fn address_type ( & self ) -> AddressType {
76+ self . address_type
77+ }
78+
79+ /// True if the address is static
80+ pub fn is_static ( & self ) -> bool {
81+ !self . is_public ( ) && self . le_bytes [ 5 ] >> 6 == 3
82+ }
83+
84+ /// True if the address type is [AddressType::PublicIdentityAddress] or
85+ /// [AddressType::PublicDeviceAddress]
86+ pub fn is_public ( & self ) -> bool {
87+ matches ! (
88+ self . address_type,
89+ AddressType :: PublicDeviceAddress | AddressType :: PublicIdentityAddress
90+ )
91+ }
92+
93+ /// True if the address is resolvable
94+ pub fn is_resolvable ( & self ) -> bool {
95+ self . address_type == AddressType :: RandomDeviceAddress && self . le_bytes [ 5 ] >> 6 == 1
96+ }
97+
98+ /// Address bytes in _little-endian_ format
99+ pub fn as_le_bytes ( & self ) -> [ u8 ; 6 ] {
100+ self . le_bytes
101+ }
102+
103+ /// Address bytes as big-endian colon-separated hex
104+ pub fn as_be_hex ( & self ) -> String {
105+ self . le_bytes
106+ . into_iter ( )
107+ . rev ( )
108+ . map ( |byte| hex:: encode_upper ( [ byte] ) )
109+ . join ( ":" )
110+ }
111+ }
112+
113+ // show a more readable form than default Debug for a byte array
114+ impl fmt:: Debug for Address {
115+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
116+ write ! (
117+ f,
118+ "Address {{ address: {}, type: {:?} }}" ,
119+ self . as_be_hex( ) ,
120+ self . address_type
121+ )
122+ }
123+ }
124+
125+ /// Error type for [Address::from_be_hex].
126+ #[ derive( Debug , thiserror:: Error ) ]
127+ #[ error( "Invalid address hex: {address}" ) ]
128+ pub struct InvalidAddressHex < ' a > {
129+ address : & ' a str ,
130+ }
131+
26132/// HCI Packet type, prepended to the packet.
27133/// Rootcanal's PDL declaration excludes this from ser/deser and instead is implemented in code.
28134/// To maintain the ability to easily use future versions of their packet PDL, packet type is
0 commit comments