1use std::collections::HashMap;
2use json::{JsonValue, object};
3#[cfg(target_os = "windows")]
4use windows::core::GUID;
5#[cfg(target_os = "windows")]
6use windows::Devices::Bluetooth::Advertisement::BluetoothLEAdvertisementReceivedEventArgs;
7#[cfg(target_os = "windows")]
8use windows::Devices::Bluetooth::BluetoothLEDevice;
9#[cfg(target_os = "windows")]
10use windows::Devices::Bluetooth::GenericAttributeProfile::GattCharacteristic;
11#[cfg(target_os = "windows")]
12use windows::Devices::Bluetooth::GenericAttributeProfile::GattCharacteristicProperties;
13#[cfg(target_os = "macos")]
14use crate::mac::central::{AdvertisementData, CentralManager};
15#[cfg(target_os = "macos")]
16use crate::mac::central::peripheral::Peripheral;
17
18#[derive(Clone)]
20pub struct Device {
21 pub name: String,
23 pub uuid: String,
25 pub rssi: i32,
27 pub characteristic: HashMap<String, Characteristic>,
29 pub discover: bool,
31 pub connect: bool,
33 pub disable: bool,
35 pub types: Types,
37}
38impl Device {
39 #[cfg(target_os = "macos")]
40 pub fn new(uuid: String, name: String, rssi: i32, manager: CentralManager, peripheral: Peripheral, advertisement_data: AdvertisementData) -> Self {
41 Self {
42 name,
43 uuid,
44 rssi,
45 characteristic: Default::default(),
46 discover: false,
47 connect: false,
48 disable: false,
49 types: Types::Mac(manager, peripheral, Box::new(advertisement_data)),
50 }
51 }
52 #[cfg(target_os = "windows")]
53 pub fn new(uuid: String, name: String, rssi: i32, manager: CentralManager, peripheral: BluetoothLEDevice, advertisement_data: AdvertisementData) -> Self {
54 Self {
55 name,
56 uuid,
57 rssi,
58 characteristic: Default::default(),
59 discover: false,
60 connect: false,
61 disable: false,
62 types: Types::Win(manager, peripheral, advertisement_data),
63 }
64 }
65 pub fn disconnect(&mut self) -> bool {
67 match self.clone().types {
68 #[cfg(target_os = "macos")]
69 Types::Mac(manager, peripheral, _advertisement_data) => {
70 manager.cancel_connect(&peripheral);
71 true
72 }
73 #[cfg(target_os = "windows")]
74 Types::Win(manager, peripheral, _2) => {
75 manager.cancel_connect(peripheral);
76 true
77 }
78 Types::None => { false }
79 }
80 }
81 pub fn connect(&mut self) -> bool {
83 match self.clone().types {
84 #[cfg(target_os = "macos")]
85 Types::Mac(manager, peripheral, _advertisement_data) => {
86 manager.connect(&peripheral);
87 true
88 }
89 #[cfg(target_os = "windows")]
90 Types::Win(manager, BluetoothLEDevice, _2) => {
91 manager.connect(BluetoothLEDevice);
92 true
93 }
94 Types::None => false
95 }
96 }
97 pub fn subscribe(&mut self, characteristic: Characteristic) -> bool {
99 match self.clone().types {
100 #[cfg(target_os = "macos")]
101 Types::Mac(_, peripheral, _) => {
102 peripheral.subscribe(&characteristic.characteristic);
103 true
104 }
105 #[cfg(target_os = "windows")]
106 Types::Win(manager, BluetoothLEDevice, _2) => {
107 manager.subscribe(BluetoothLEDevice, characteristic);
108 true
109 }
110 _ => false
111 }
112 }
113 pub fn json(&mut self) -> JsonValue {
114 object! {
115 name:self.name.clone(),
116 uuid:self.uuid.clone(),
117 rssi:self.rssi,
118 discover: self.discover,
119 connect: self.connect,
120 disable:self.disable,
121 }
122 }
123}
124#[derive(Clone)]
125pub enum Types {
126 #[cfg(target_os = "macos")]
127 Mac(CentralManager, Peripheral, Box<AdvertisementData>),
128 #[cfg(target_os = "windows")]
129 Win(CentralManager, BluetoothLEDevice, AdvertisementData),
130 None,
131}
132
133#[cfg(target_os = "macos")]
134use crate::mac::central::characteristic::Characteristic as Char;
135#[cfg(target_os = "windows")]
136use crate::win::central::{AdvertisementData, CentralManager};
137#[cfg(target_os = "windows")]
138use crate::win::Win;
139
140#[derive(Clone)]
142pub struct Characteristic {
143 pub uuid: String,
145 pub properties: Properties,
146 #[cfg(target_os = "macos")]
147 characteristic: Char,
148 #[cfg(target_os = "windows")]
149 pub characteristic: GattCharacteristicProperties,
150 #[cfg(target_os = "windows")]
151 pub gatt_characteristic: GattCharacteristic,
152 pub is_subscribe: Option<bool>,
154}
155
156impl Characteristic {
157 #[cfg(target_os = "macos")]
158 pub fn default(characteristic: Char) -> Characteristic {
159 Self {
160 uuid: characteristic.id().to_string(),
161 properties: Properties::form(format!("{:?}", characteristic.properties())),
162 characteristic,
163 is_subscribe: None,
164 }
165 }
166 #[cfg(target_os = "windows")]
167 pub fn default(uuid: String, characteristic: GattCharacteristicProperties, gatt_characteristic: GattCharacteristic) -> Characteristic {
168 Self {
169 uuid,
170 properties: Properties::form(characteristic.0),
171 characteristic,
172 gatt_characteristic,
173 is_subscribe: None,
174 }
175 }
176}
177#[derive(Debug, Clone)]
179pub struct Properties {
180 pub read: bool,
182 pub write: bool,
184 pub notify: bool,
186 pub indicate: bool,
188 pub write_without_response: bool,
190 pub authenticated_signed_writes: bool,
192 pub extended_properties: bool,
194 pub reliable_write: bool,
196 pub writable_auxiliaries: bool,
198 pub broadcast: bool,
200}
201
202impl Properties {
203 const BROADCAST: u16 = 0b00000001;
204 const READ: u16 = 0b00000010;
205 const WRITE_WITHOUT_RESPONSE: u16 = 0b00000100;
206 const WRITE: u16 = 0b00001000;
207 const NOTIFY: u16 = 0b00010000;
208 const INDICATE: u16 = 0b00100000;
209 const AUTHENTICATED_SIGNED_WRITES: u16 = 0b01000000;
210 const EXTENDED_PROPERTIES: u16 = 0b10000000;
211 const RELIABLE_WRITE: u16 = 0b000100000000;
212 const WRITABLE_AUXILIARIES: u16 = 0b001000000000;
213
214 #[cfg(target_os = "macos")]
215 pub fn form(text: String) -> Properties {
216 let text = text.trim_start_matches("Properties(BitFlagsDebug(BitFlags<Property>(");
217 let text = text.split(",").collect::<Vec<&str>>()[0];
218 let text = text.trim_start_matches("0b");
219 let raw_value = u16::from_str_radix(text, 2).map_err(|e| e.to_string()).unwrap();
220 let is_read = (Properties::READ & raw_value) == Properties::READ;
221 let is_write = (Properties::WRITE & raw_value) == Properties::WRITE;
222 let is_notify = (Properties::NOTIFY & raw_value) == Properties::NOTIFY;
223 let is_indicate = (Properties::INDICATE & raw_value) == Properties::INDICATE;
224 let is_write_without_response = (Properties::WRITE_WITHOUT_RESPONSE & raw_value) == Properties::WRITE_WITHOUT_RESPONSE;
225 let is_authenticated_signed_writes = (Properties::AUTHENTICATED_SIGNED_WRITES & raw_value) == Properties::AUTHENTICATED_SIGNED_WRITES;
226 let is_extended_properties = (Properties::EXTENDED_PROPERTIES & raw_value) == Properties::EXTENDED_PROPERTIES;
227 let is_reliable_write = (Properties::RELIABLE_WRITE & raw_value) == Properties::RELIABLE_WRITE;
228 let is_writable_auxiliaries = (Properties::WRITABLE_AUXILIARIES & raw_value) == Properties::WRITABLE_AUXILIARIES;
229 let is_broadcast = (Properties::BROADCAST & raw_value) == Properties::BROADCAST;
230 Self {
231 read: is_read,
232 write: is_write,
233 notify: is_notify,
234 indicate: is_indicate,
235 write_without_response: is_write_without_response,
236 authenticated_signed_writes: is_authenticated_signed_writes,
237 extended_properties: is_extended_properties,
238 reliable_write: is_reliable_write,
239 writable_auxiliaries: is_writable_auxiliaries,
240 broadcast: is_broadcast,
241 }
242 }
243 #[cfg(target_os = "windows")]
244 pub fn form(properties: u32) -> Properties {
245 let is_read = if (properties & GattCharacteristicProperties::Read.0) != 0 { true } else { false };
246 let is_write = if (properties & GattCharacteristicProperties::Write.0) != 0 { true } else { false };
247 let is_notify = if (properties & GattCharacteristicProperties::Notify.0) != 0 { true } else { false };
248 let is_indicate = if (properties & GattCharacteristicProperties::Indicate.0) != 0 { true } else { false };
249 let is_write_without_response = if (properties & GattCharacteristicProperties::WriteWithoutResponse.0) != 0 { true } else { false };
250 let is_authenticated_signed_writes = if (properties & GattCharacteristicProperties::AuthenticatedSignedWrites.0) != 0 { true } else { false };
251 let is_extended_properties = if (properties & GattCharacteristicProperties::ExtendedProperties.0) != 0 { true } else { false };
252 let is_reliable_write = if (properties & GattCharacteristicProperties::ReliableWrites.0) != 0 { true } else { false };
253 let is_writable_auxiliaries = if (properties & GattCharacteristicProperties::WritableAuxiliaries.0) != 0 { true } else { false };
254 let is_broadcast = if (properties & GattCharacteristicProperties::Broadcast.0) != 0 { true } else { false };
255 Self {
256 read: is_read,
257 write: is_write,
258 notify: is_notify,
259 indicate: is_indicate,
260 write_without_response: is_write_without_response,
261 authenticated_signed_writes: is_authenticated_signed_writes,
262 extended_properties: is_extended_properties,
263 reliable_write: is_reliable_write,
264 writable_auxiliaries: is_writable_auxiliaries,
265 broadcast: is_broadcast,
266 }
267 }
268}