1use crate::error::BluetoothError;
2
3use btleplug::api::Characteristic;
4use btleplug::api::{Peripheral as _, WriteType};
5use btleplug::platform::Peripheral;
6
7use uuid::Uuid;
8
9use async_trait::async_trait;
10use enumflags2::{bitflags, BitFlags};
11use std::fmt;
12
13pub use self::led_device::LedDevice;
18pub mod led_device;
21
22const BT_BASE_UUID: u128 = 0x00000000_0000_1000_8000_00805f9b34fb;
23
24#[bitflags]
36#[repr(u8)]
37#[derive(Copy, Clone, Debug, PartialEq)]
38pub enum OpKind {
39 Broadcast = 0x01,
40 Read = 0x02,
41 WriteWithoutResponse = 0x04,
42 Write = 0x08,
43 Notify = 0x10,
44 Indicate = 0x20,
45 AuthenticatedSignedWrites = 0x40,
46 ExtendedProperties = 0x80,
47}
48
49pub enum UuidKind {
52 Uuid(Uuid),
53 Uuid16(u16),
54 Uuid32(u32),
55 Uuid128(u128),
56}
57
58pub enum CharKind {
60 Read,
61 Write,
62}
63
64pub trait Device: fmt::Display {
65 fn new(
66 name: &str,
67 alias: &str,
68 peripheral: Option<Peripheral>,
69 write_char: Option<Characteristic>,
70 read_char: Option<Characteristic>,
71 ) -> Self;
72 fn alias(&self) -> &str;
76 fn name(&self) -> &str;
77 fn address(&self) -> Option<String>;
78 fn peripheral(&self) -> Option<&Peripheral>;
79 fn write_char(&self) -> Option<&Characteristic>;
80 fn read_char(&self) -> Option<&Characteristic>;
81 fn default_write_characteristic_uuid(&self) -> Uuid;
82
83 fn characteristics(&self) -> Option<Vec<Characteristic>> {
95 if let Some(peripheral) = self.peripheral().as_ref() {
96 return Some(
97 peripheral
98 .characteristics()
99 .into_iter()
100 .collect::<Vec<Characteristic>>(),
101 );
102 }
103 None
104 }
105
106 fn characteristics_by_type(&self, kinds: BitFlags<OpKind>) -> Option<Vec<Characteristic>> {
125 if let Some(chars) = self.characteristics() {
126 return Some(
127 chars
128 .into_iter()
129 .filter(|c| c.properties.bits() == kinds.bits())
130 .collect(),
131 );
132 }
133 None
134 }
135
136 fn set_alias(&mut self, alias: &str);
140 fn set_name(&mut self, name: &str);
141 fn set_peripheral(&mut self, peripheral: Peripheral);
142
143 fn set_write_char(&mut self, characteristic: &Characteristic);
152
153 fn set_char(
162 &mut self,
163 char_kind: &CharKind,
164 uuid_kind: &UuidKind,
165 ) -> Result<(), BluetoothError> {
166 match char_kind {
167 CharKind::Write => match uuid_kind {
168 UuidKind::Uuid(uuid) => self.set_char_with_uuid(char_kind, &uuid),
169 UuidKind::Uuid128(uuid) => {
170 self.set_char_with_uuid(char_kind, &Uuid::from_u128(*uuid))
171 }
172 UuidKind::Uuid32(uuid) => self.set_char_with_u32(char_kind, *uuid),
173 UuidKind::Uuid16(uuid) => self.set_char_with_u16(char_kind, *uuid),
174 },
175 CharKind::Read => unimplemented!(),
176 }
177 }
178 fn set_char_with_uuid(
179 &mut self,
180 char_kind: &CharKind,
181 uuid: &Uuid,
182 ) -> Result<(), BluetoothError> {
183 let char = self
184 .peripheral()
185 .as_ref()
186 .ok_or(BluetoothError::InvalidPeripheralReference)?
187 .characteristics()
188 .into_iter()
189 .find(|c| c.uuid.as_u128() == uuid.as_u128())
190 .ok_or(BluetoothError::NotFoundTargetCharacteristic)?;
191 match char_kind {
192 CharKind::Write => self.set_write_char(&char),
193 CharKind::Read => unimplemented!(),
194 }
195 Ok(())
196 }
197 fn set_char_with_u16(&mut self, char_kind: &CharKind, u16: u16) -> Result<(), BluetoothError> {
198 self.set_char_with_u32(char_kind, u16 as u32) }
200 fn set_char_with_u32(&mut self, char_kind: &CharKind, u32: u32) -> Result<(), BluetoothError> {
201 let uuid = Uuid::from_u128(BT_BASE_UUID | ((u32 as u128) << 96));
202 self.set_char_with_uuid(char_kind, &uuid)
203 }
204}
205
206#[async_trait]
207pub trait Disconnect {
208 async fn leave(&self) -> Result<(), BluetoothError>;
209}
210pub trait Connect {}
211#[async_trait]
212pub trait Write {
213 async fn push(&self, raw_bytes: &[u8]) -> Result<(), BluetoothError>;
214}
215
216#[async_trait]
220impl<D: Device + std::marker::Sync> Disconnect for D {
221 async fn leave(&self) -> Result<(), BluetoothError> {
222 self.peripheral()
223 .as_ref()
224 .ok_or(BluetoothError::InvalidPeripheralReference)?
225 .disconnect()
226 .await?;
227 Ok(())
228 }
229}
230
231#[async_trait]
232impl<D: Device + std::marker::Sync> Write for D {
233 async fn push(&self, raw_bytes: &[u8]) -> Result<(), BluetoothError> {
234 self.peripheral()
236 .as_ref()
237 .ok_or(BluetoothError::InvalidPeripheralReference)?
238 .write(
239 self.write_char()
240 .ok_or(BluetoothError::InvalidCharacteristic)?,
241 raw_bytes,
242 WriteType::WithoutResponse,
243 )
244 .await?;
245
246 Ok(())
247 }
248}