1use {
2 byteorder::{self, ByteOrder},
3 rubble::link::ad_structure::AdStructure,
4};
5
6pub struct Data([u8; 17]);
7
8impl<'a, 'b> Data
9where
10 'a: 'b,
11{
12 pub fn new(
13 interval: Interval,
14 pair_status: PairingStatus,
15 device_id: u64,
16 accessory_category: AccessoryCategory,
17 global_state_number: u16,
18 configuration_number: u8,
19 ) -> Self {
20 let mut inner = [0u8; 17];
21
22 inner[0] = 0x4C;
24 inner[1] = 0x00;
25
26 inner[2] = 0x06;
28
29 inner[3] = interval.value();
31
32 inner[4] = pair_status.value();
34
35 byteorder::BigEndian::write_u48(&mut inner[5..12], device_id);
37
38 byteorder::BigEndian::write_u16(&mut inner[11..13], accessory_category.value());
40
41 byteorder::BigEndian::write_u16(&mut inner[13..15], global_state_number);
43
44 inner[15] = configuration_number;
46
47 inner[16] = 0x02;
49
50 Self(inner)
51 }
52
53 pub fn as_adstructure(&'a self) -> AdStructure<'b> {
54 AdStructure::Unknown {
55 ty: 0xFF,
56 data: &self.0,
57 }
58 }
59}
60
61pub enum Interval {
62 _10_25MS,
63 _26_100MS,
64 _101_300MS,
65 _301_500MS,
66 _501_1250MS,
67 _1251_2500MS,
68 _2500MS,
69}
70
71impl Interval {
72 fn value(&self) -> u8 {
73 match *self {
74 Interval::_10_25MS => 0x2D,
75 Interval::_26_100MS => 0x4D,
76 Interval::_101_300MS => 0x6D,
77 Interval::_301_500MS => 0x8D,
78 Interval::_501_1250MS => 0xAD,
79 Interval::_1251_2500MS => 0xCD,
80 Interval::_2500MS => 0xED,
81 }
82 }
83}
84
85pub enum PairingStatus {
86 Paired,
87 NotPaired,
88}
89
90impl PairingStatus {
91 fn value(&self) -> u8 {
92 match *self {
93 PairingStatus::Paired => 0b0,
94 PairingStatus::NotPaired => 0b1,
95 }
96 }
97}
98
99pub enum AccessoryCategory {
100 Other,
101 Bridge,
102 Fan,
103 Garage,
104 Lightbulb,
105 DoorLock,
106 Outlet,
107 Switch,
108 Thermostat,
109 Sensor,
110 SecuritySystem,
111 Door,
112 Window,
113 WindowCovering,
114 ProgrammableSwitch,
115 RangeExtender,
116 IPCamera,
117 VideoDoorBell,
118 AirPurifier,
119 Reserved,
120}
121
122impl AccessoryCategory {
123 fn value(&self) -> u16 {
124 match *self {
125 AccessoryCategory::Other => 1,
126 AccessoryCategory::Bridge => 2,
127 AccessoryCategory::Fan => 3,
128 AccessoryCategory::Garage => 4,
129 AccessoryCategory::Lightbulb => 5,
130 AccessoryCategory::DoorLock => 6,
131 AccessoryCategory::Outlet => 7,
132 AccessoryCategory::Switch => 8,
133 AccessoryCategory::Thermostat => 9,
134 AccessoryCategory::Sensor => 10,
135 AccessoryCategory::SecuritySystem => 11,
136 AccessoryCategory::Door => 12,
137 AccessoryCategory::Window => 13,
138 AccessoryCategory::WindowCovering => 14,
139 AccessoryCategory::ProgrammableSwitch => 15,
140 AccessoryCategory::RangeExtender => 16,
141 AccessoryCategory::IPCamera => 17,
142 AccessoryCategory::VideoDoorBell => 18,
143 AccessoryCategory::AirPurifier => 19,
144 AccessoryCategory::Reserved => 65535,
145 }
146 }
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152 use insta::assert_debug_snapshot_matches;
153
154 #[test]
155 fn test_snapshots() {
156 assert_debug_snapshot_matches!(
157 "data_as_adstructure",
158 Data::new(
159 Interval::_501_1250MS,
160 PairingStatus::NotPaired,
161 188899839028173,
162 AccessoryCategory::Lightbulb,
163 1,
164 1,
165 )
166 .as_adstructure()
167 )
168 }
169}