br_ble/
device.rs

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/// 蓝牙设备
19#[derive(Clone)]
20pub struct Device {
21    /// 设备名称
22    pub name: String,
23    /// 设备id
24    pub uuid: String,
25    /// 设备信号
26    pub rssi: i32,
27    /// 服务列表
28    pub characteristic: HashMap<String, Characteristic>,
29    /// 发现
30    pub discover: bool,
31    /// 连接
32    pub connect: bool,
33    /// 禁用
34    pub disable: bool,
35    /// 环境类型
36    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    /// 关闭连接
66    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    /// 开启连接
82    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    /// 订阅
98    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/// 特征
141#[derive(Clone)]
142pub struct Characteristic {
143    /// 特征UUID
144    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    /// 是否订阅
153    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/// 属性标志
178#[derive(Debug, Clone)]
179pub struct Properties {
180    /// 可读
181    pub read: bool,
182    /// 可写
183    pub write: bool,
184    /// 通知
185    pub notify: bool,
186    /// 发送指示
187    pub indicate: bool,
188    /// 无响应写入
189    pub write_without_response: bool,
190    /// 认证签名写入
191    pub authenticated_signed_writes: bool,
192    /// 指示特征具有扩展的属性
193    pub extended_properties: bool,
194    /// 支持可靠写入
195    pub reliable_write: bool,
196    /// 支持可写辅助属性
197    pub writable_auxiliaries: bool,
198    /// 允许特征值进行广播
199    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}