use super::btleplug_internal::{
BtlePlugInternalEventLoop, DeviceReturnFuture, DeviceReturnStateShared,
};
use crate::{
core::{
errors::{ButtplugDeviceError, ButtplugError},
messages::RawReading,
},
device::{
configuration_manager::{BluetoothLESpecifier, DeviceSpecifier, ProtocolDefinition},
device::{
BoundedDeviceEventBroadcaster, ButtplugDeviceCommand, ButtplugDeviceImplCreator,
ButtplugDeviceReturn, DeviceImpl, DeviceReadCmd, DeviceSubscribeCmd,
DeviceUnsubscribeCmd, DeviceWriteCmd,
},
Endpoint,
},
};
use async_std::{
sync::{channel, Sender},
task,
};
use async_trait::async_trait;
use broadcaster::BroadcastChannel;
use btleplug::api::{Central, Peripheral};
pub struct BtlePlugDeviceImplCreator<T: Peripheral + 'static, C: Central<T> + 'static> {
device: Option<T>,
central: C,
}
impl<T: Peripheral, C: Central<T>> BtlePlugDeviceImplCreator<T, C> {
pub fn new(device: T, central: C) -> Self {
Self {
device: Some(device),
central,
}
}
}
#[async_trait]
impl<T: Peripheral, C: Central<T>> ButtplugDeviceImplCreator for BtlePlugDeviceImplCreator<T, C> {
fn get_specifier(&self) -> DeviceSpecifier {
if self.device.is_none() {
panic!("Cannot call get_specifier after device is taken!");
}
let name = self
.device
.as_ref()
.unwrap()
.properties()
.local_name
.unwrap();
DeviceSpecifier::BluetoothLE(BluetoothLESpecifier::new_from_device(&name))
}
async fn try_create_device_impl(
&mut self,
protocol: ProtocolDefinition,
) -> Result<Box<dyn DeviceImpl>, ButtplugError> {
if self.device.is_none() {
panic!("Cannot call try_create_device_impl twice!");
}
let device = self.device.take().unwrap();
if let Some(ref proto) = protocol.btle {
let (device_sender, device_receiver) = channel(256);
let output_broadcaster = BroadcastChannel::with_cap(256);
let p = proto.clone();
let name = device.properties().local_name.unwrap();
let address = device.properties().address.to_string();
let central = self.central.clone();
let broadcaster_clone = output_broadcaster.clone();
task::spawn(async move {
let mut event_loop = BtlePlugInternalEventLoop::new(
central,
device,
p,
device_receiver,
broadcaster_clone,
);
event_loop.run().await;
});
let fut = DeviceReturnFuture::default();
let waker = fut.get_state_clone();
device_sender
.send((ButtplugDeviceCommand::Connect, waker))
.await;
match fut.await {
ButtplugDeviceReturn::Connected(info) => Ok(Box::new(BtlePlugDeviceImpl::new(
&name,
&address,
info.endpoints,
device_sender,
output_broadcaster.clone()
))),
_ => Err(ButtplugError::ButtplugDeviceError(
ButtplugDeviceError::new("Cannot connect"),
)),
}
} else {
panic!("Got a protocol with no Bluetooth Definition!");
}
}
}
#[derive(Clone)]
pub struct BtlePlugDeviceImpl {
name: String,
address: String,
endpoints: Vec<Endpoint>,
thread_sender: Sender<(ButtplugDeviceCommand, DeviceReturnStateShared)>,
event_receiver: BoundedDeviceEventBroadcaster,
}
unsafe impl Send for BtlePlugDeviceImpl {}
unsafe impl Sync for BtlePlugDeviceImpl {}
impl BtlePlugDeviceImpl {
pub fn new(
name: &String,
address: &String,
endpoints: Vec<Endpoint>,
thread_sender: Sender<(ButtplugDeviceCommand, DeviceReturnStateShared)>,
event_receiver: BoundedDeviceEventBroadcaster,
) -> Self {
Self {
name: name.to_string(),
address: address.to_string(),
endpoints,
thread_sender,
event_receiver,
}
}
async fn send_to_device_task(
&self,
cmd: ButtplugDeviceCommand,
err_msg: &str,
) -> Result<(), ButtplugError> {
let fut = DeviceReturnFuture::default();
let waker = fut.get_state_clone();
self.thread_sender.send((cmd, waker)).await;
match fut.await {
ButtplugDeviceReturn::Ok(_) => Ok(()),
_ => Err(ButtplugError::ButtplugDeviceError(
ButtplugDeviceError::new(err_msg),
)),
}
}
}
#[async_trait]
impl DeviceImpl for BtlePlugDeviceImpl {
fn get_event_receiver(&self) -> BoundedDeviceEventBroadcaster {
self.event_receiver.clone()
}
fn name(&self) -> &str {
&self.name
}
fn address(&self) -> &str {
&self.address
}
fn connected(&self) -> bool {
true
}
fn endpoints(&self) -> Vec<Endpoint> {
self.endpoints.clone()
}
async fn disconnect(&self) {
if let Err(e) = self.send_to_device_task(
ButtplugDeviceCommand::Disconnect,
"Cannot disconnect device",
).await {
error!("Error disconnecting BtlePlug device {}: {:?}", self.name, e);
}
}
fn box_clone(&self) -> Box<dyn DeviceImpl> {
Box::new((*self).clone())
}
async fn write_value(&self, msg: DeviceWriteCmd) -> Result<(), ButtplugError> {
self.send_to_device_task(
ButtplugDeviceCommand::Message(msg.into()),
"Cannot write to endpoint",
)
.await
}
async fn read_value(&self, msg: DeviceReadCmd) -> Result<RawReading, ButtplugError> {
Ok(RawReading::new(0, msg.endpoint, vec![]))
}
async fn subscribe(&self, msg: DeviceSubscribeCmd) -> Result<(), ButtplugError> {
self.send_to_device_task(
ButtplugDeviceCommand::Message(msg.into()),
"Cannot subscribe",
)
.await
}
async fn unsubscribe(&self, msg: DeviceUnsubscribeCmd) -> Result<(), ButtplugError> {
self.send_to_device_task(
ButtplugDeviceCommand::Message(msg.into()),
"Cannot unsubscribe",
)
.await
}
}