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