hive_btle/platform/linux/
connection.rs1use bluer::Device;
4use std::sync::Arc;
5use std::time::{Duration, Instant};
6use tokio::sync::RwLock;
7
8use crate::config::BlePhy;
9use crate::error::{BleError, Result};
10use crate::transport::BleConnection;
11use crate::NodeId;
12
13struct ConnectionState {
15 alive: bool,
17 mtu: u16,
19 phy: BlePhy,
21 rssi: Option<i8>,
23}
24
25#[derive(Clone)]
29pub struct BluerConnection {
30 peer_id: NodeId,
32 device: Device,
34 state: Arc<RwLock<ConnectionState>>,
36 connected_at: Instant,
38}
39
40impl BluerConnection {
41 pub(crate) async fn new(peer_id: NodeId, device: Device) -> Result<Self> {
43 let mtu = 23; let state = ConnectionState {
48 alive: true,
49 mtu,
50 phy: BlePhy::Le1M, rssi: None,
52 };
53
54 let conn = Self {
55 peer_id,
56 device,
57 state: Arc::new(RwLock::new(state)),
58 connected_at: Instant::now(),
59 };
60
61 conn.update_rssi().await;
63
64 Ok(conn)
65 }
66
67 pub fn device(&self) -> &Device {
69 &self.device
70 }
71
72 pub async fn update_rssi(&self) {
74 if let Ok(Some(rssi)) = self.device.rssi().await {
75 let mut state = self.state.write().await;
76 state.rssi = Some(rssi as i8);
77 }
78 }
79
80 pub async fn set_mtu(&self, mtu: u16) {
82 let mut state = self.state.write().await;
83 state.mtu = mtu;
84 }
85
86 pub async fn set_phy(&self, phy: BlePhy) {
88 let mut state = self.state.write().await;
89 state.phy = phy;
90 }
91
92 pub async fn mark_dead(&self) {
94 let mut state = self.state.write().await;
95 state.alive = false;
96 }
97
98 pub async fn disconnect(&self) -> Result<()> {
100 self.device
101 .disconnect()
102 .await
103 .map_err(|e| BleError::ConnectionFailed(format!("Failed to disconnect: {}", e)))?;
104 self.mark_dead().await;
105 Ok(())
106 }
107
108 pub async fn discover_services(&self) -> Result<()> {
110 let _ = self.device.services().await;
114 Ok(())
115 }
116
117 pub async fn services(&self) -> Result<Vec<bluer::gatt::remote::Service>> {
119 self.device
120 .services()
121 .await
122 .map_err(|e| BleError::GattError(format!("Failed to get services: {}", e)))
123 }
124
125 pub async fn find_service(
127 &self,
128 uuid: uuid::Uuid,
129 ) -> Result<Option<bluer::gatt::remote::Service>> {
130 let services = self.services().await?;
131 for service in services {
132 if service.uuid().await.ok() == Some(uuid) {
133 return Ok(Some(service));
134 }
135 }
136 Ok(None)
137 }
138
139 pub async fn read_characteristic(
141 &self,
142 service_uuid: uuid::Uuid,
143 char_uuid: uuid::Uuid,
144 ) -> Result<Vec<u8>> {
145 let service = self
146 .find_service(service_uuid)
147 .await?
148 .ok_or_else(|| BleError::ServiceNotFound(service_uuid.to_string()))?;
149
150 let characteristics = service
151 .characteristics()
152 .await
153 .map_err(|e| BleError::GattError(format!("Failed to get characteristics: {}", e)))?;
154
155 for char in characteristics {
156 if char.uuid().await.ok() == Some(char_uuid) {
157 return char.read().await.map_err(|e| {
158 BleError::GattError(format!("Failed to read characteristic: {}", e))
159 });
160 }
161 }
162
163 Err(BleError::CharacteristicNotFound(char_uuid.to_string()))
164 }
165
166 pub async fn write_characteristic(
168 &self,
169 service_uuid: uuid::Uuid,
170 char_uuid: uuid::Uuid,
171 value: &[u8],
172 ) -> Result<()> {
173 let service = self
174 .find_service(service_uuid)
175 .await?
176 .ok_or_else(|| BleError::ServiceNotFound(service_uuid.to_string()))?;
177
178 let characteristics = service
179 .characteristics()
180 .await
181 .map_err(|e| BleError::GattError(format!("Failed to get characteristics: {}", e)))?;
182
183 for char in characteristics {
184 if char.uuid().await.ok() == Some(char_uuid) {
185 return char.write(value).await.map_err(|e| {
186 BleError::GattError(format!("Failed to write characteristic: {}", e))
187 });
188 }
189 }
190
191 Err(BleError::CharacteristicNotFound(char_uuid.to_string()))
192 }
193
194 pub async fn subscribe_characteristic(
196 &self,
197 service_uuid: uuid::Uuid,
198 char_uuid: uuid::Uuid,
199 ) -> Result<impl tokio_stream::Stream<Item = Vec<u8>>> {
200 let service = self
201 .find_service(service_uuid)
202 .await?
203 .ok_or_else(|| BleError::ServiceNotFound(service_uuid.to_string()))?;
204
205 let characteristics = service
206 .characteristics()
207 .await
208 .map_err(|e| BleError::GattError(format!("Failed to get characteristics: {}", e)))?;
209
210 for char in characteristics {
211 if char.uuid().await.ok() == Some(char_uuid) {
212 return char.notify().await.map_err(|e| {
213 BleError::GattError(format!("Failed to subscribe to notifications: {}", e))
214 });
215 }
216 }
217
218 Err(BleError::CharacteristicNotFound(char_uuid.to_string()))
219 }
220}
221
222impl BleConnection for BluerConnection {
223 fn peer_id(&self) -> &NodeId {
224 &self.peer_id
225 }
226
227 fn is_alive(&self) -> bool {
228 if let Ok(state) = self.state.try_read() {
230 state.alive
231 } else {
232 true
234 }
235 }
236
237 fn mtu(&self) -> u16 {
238 if let Ok(state) = self.state.try_read() {
239 state.mtu
240 } else {
241 23 }
243 }
244
245 fn phy(&self) -> BlePhy {
246 if let Ok(state) = self.state.try_read() {
247 state.phy
248 } else {
249 BlePhy::Le1M
250 }
251 }
252
253 fn rssi(&self) -> Option<i8> {
254 if let Ok(state) = self.state.try_read() {
255 state.rssi
256 } else {
257 None
258 }
259 }
260
261 fn connected_duration(&self) -> Duration {
262 self.connected_at.elapsed()
263 }
264}
265
266#[cfg(test)]
267mod tests {
268 }