blackmagic_camera_control/
blecamera.rs1use crate::command::Command;
2use crate::error::BluetoothCameraError;
3use crate::rawcommand::{Operation, RawCommand};
4use btleplug::api::{
5 Central, Characteristic, Manager as _, Peripheral as _, ScanFilter, ValueNotification,
6};
7use btleplug::platform::{Adapter, Manager, Peripheral};
8use futures::stream::StreamExt;
9use std::collections::HashMap;
10use std::pin::Pin;
11use std::sync::Arc;
12use std::time::Duration;
13use tokio::sync::broadcast::{self, Receiver, Sender};
14use tokio::sync::RwLock;
15use tokio::time;
16use uuid::Uuid;
17
18pub const CAMERA_SERVICE: Uuid = Uuid::from_u128(54650678423016196498641639054569411539);
19pub const CAMERA_MANUFACTURER: Uuid = Uuid::from_u128(855109558092022082745622393992443);
20pub const CAMERA_MODEL: Uuid = Uuid::from_u128(854713417279450761057654674240763);
21pub const OUTGOING_CAMERA_CONTROL: Uuid = Uuid::from_u128(124715205548830368390231916378743955899);
22pub const INCOMING_CAMERA_CONTROL: Uuid = Uuid::from_u128(245101749559754194128926468485788547033);
23pub const TIMECODE: Uuid = Uuid::from_u128(145629020620256484157652687441451644616);
24pub const CAMERA_STATUS: Uuid = Uuid::from_u128(170018700332869099062316608707586904505);
25pub const DEVICE_NAME: Uuid = Uuid::from_u128(339846463932956345205123112215954503836);
26pub const PROTOCOL_VERSION: Uuid = Uuid::from_u128(190244785298557795456958317949635929862);
27
28#[allow(dead_code)]
29pub struct BluetoothCamera {
30 name: String,
31
32 bluetooth_manager: Manager,
33 adapter: Adapter,
34
35 device: Option<Peripheral>,
36
37 write_char: Option<Characteristic>,
38 read_char: Option<Characteristic>,
39
40 updates: Sender<Command>,
41 cache: Arc<RwLock<HashMap<String, Command>>>,
42}
43
44impl BluetoothCamera {
45 pub async fn new(name: &str) -> Result<BluetoothCamera, BluetoothCameraError> {
51 let bluetooth_manager = Manager::new().await?;
52
53 let adapter = bluetooth_manager.adapters().await?;
54
55 let adapter = adapter
56 .into_iter()
57 .nth(0)
58 .ok_or(BluetoothCameraError::NoBluetooth)?;
59
60 Ok(BluetoothCamera {
61 name: name.to_string(),
62 bluetooth_manager,
63 adapter,
64 device: None,
65
66 write_char: None,
67 read_char: None,
68
69 updates: broadcast::channel(16).0,
70 cache: Arc::new(RwLock::new(HashMap::new())),
71 })
72 }
73
74 pub async fn connect(&mut self, timeout: Duration) -> Result<(), BluetoothCameraError> {
80 let now = time::Instant::now();
81 self.adapter
82 .start_scan(ScanFilter {
83 services: vec![CAMERA_SERVICE],
84 })
85 .await?;
86
87 loop {
88 if now.elapsed().as_millis() > timeout.as_millis() {
90 break;
91 }
92
93 match self.find_camera().await {
94 Ok(v) => {
95 v.connect().await?;
96 self.device = Some(v);
97
98 time::sleep(Duration::from_millis(500)).await;
105
106 let device = self
107 .device
108 .as_ref()
109 .ok_or(BluetoothCameraError::DevRefError)?;
110
111 device.discover_services().await?;
113
114 let char = device.characteristics();
115
116 let inc = char
117 .iter()
118 .find(|c| c.uuid == INCOMING_CAMERA_CONTROL)
119 .ok_or(BluetoothCameraError::NoCharacteristic)?;
120
121 self.read_char = Some(inc.to_owned());
122
123 let ouc = char
124 .iter()
125 .find(|c| c.uuid == OUTGOING_CAMERA_CONTROL)
126 .ok_or(BluetoothCameraError::NoCharacteristic)?;
127
128 self.write_char = Some(ouc.to_owned());
129
130 device
132 .subscribe(
133 self.read_char
134 .as_ref()
135 .ok_or(BluetoothCameraError::DevRefError)?,
136 )
137 .await?;
138 let stream = device.notifications().await?;
139
140 let ble_cache = self.cache.clone();
141 let ble_updates = self.updates.clone();
142 tokio::spawn(async move {
143 BluetoothCamera::handle_incoming(ble_cache, ble_updates, stream).await;
144 });
145
146 return Ok(());
147 }
148 Err(_) => {}
149 }
150
151 time::sleep(Duration::from_millis(50)).await;
152 }
153
154 Err(BluetoothCameraError::ConnectError)
155 }
156
157 pub async fn disconnect(&mut self) -> Result<(), BluetoothCameraError> {
161 Ok(self
162 .device
163 .as_ref()
164 .ok_or(BluetoothCameraError::DevRefError)?
165 .disconnect()
166 .await?)
167 }
168
169 pub async fn write(
170 &mut self,
171 destination: u8,
172 operation: Operation,
173 command: Command,
174 ) -> Result<(), BluetoothCameraError> {
175 let device = self
176 .device
177 .as_ref()
178 .ok_or(BluetoothCameraError::SendError)?;
179
180 device
181 .write(
182 self.write_char
183 .as_ref()
184 .ok_or(BluetoothCameraError::NoCharacteristic)?,
185 &RawCommand::to_raw(destination, operation, &command),
186 btleplug::api::WriteType::WithoutResponse,
187 )
188 .await?;
189
190 Ok(())
191 }
192
193 async fn handle_incoming(
194 cache: Arc<RwLock<HashMap<String, Command>>>,
195 updates: Sender<Command>,
196 mut stream: Pin<Box<dyn futures::Stream<Item = ValueNotification> + Send>>,
197 ) {
198 while let Some(data) = stream.next().await {
199 let cmd = Command::from_raw(&data.value);
200 match cmd {
201 Ok(v) => {
202 let (cg, pr) = v.normalized_name();
203 cache
204 .write()
205 .await
206 .insert(format!("{}_{}", cg, pr), v.clone());
207 let _ = updates.send(v.clone());
208 }
209 Err(_) => {}
210 }
211 }
212 }
213
214 pub async fn get(&self, cmd: Command) -> Command {
221 let (cg, pr) = cmd.normalized_name();
222 match self
223 .cache
224 .clone()
225 .read()
226 .await
227 .get(&format! {"{}_{}", &cg, &pr})
228 {
229 Some(c) => c.clone(),
230 None => cmd,
231 }
232 }
233
234 pub async fn get_normalized(&self, normalized_name: &str) -> Option<Command> {
240 match self.cache.clone().read().await.get(normalized_name) {
241 Some(c) => Some(c.clone()),
242 None => None,
243 }
244 }
245
246 pub async fn updates(&mut self) -> Receiver<Command> {
248 self.updates.subscribe()
249 }
250
251 async fn find_camera(&self) -> Result<Peripheral, BluetoothCameraError> {
252 for p in self.adapter.peripherals().await? {
253 if p.properties()
254 .await?
255 .ok_or(BluetoothCameraError::DiscoveryError)?
256 .local_name
257 .iter()
258 .any(|name| name.contains(&self.name))
259 {
260 return Ok(p);
261 }
262 }
263 Err(BluetoothCameraError::CameraNotFound(self.name.to_string()))
264 }
265}