|
|
|
@ -1,11 +1,13 @@
|
|
|
|
use std::pin::Pin;
|
|
|
|
use std::pin::Pin;
|
|
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
|
|
|
|
use std::task::{Context, Poll};
|
|
|
|
use std::time::Duration;
|
|
|
|
use std::time::Duration;
|
|
|
|
|
|
|
|
|
|
|
|
use async_trait::async_trait;
|
|
|
|
use async_trait::async_trait;
|
|
|
|
use btleplug::api::{bleuuid::uuid_from_u16, Central, Peripheral as _, ValueNotification, WriteType};
|
|
|
|
use btleplug::api::{bleuuid::uuid_from_u16, Central, Peripheral as _, ValueNotification, WriteType};
|
|
|
|
use btleplug::platform::{Adapter, Peripheral};
|
|
|
|
use btleplug::platform::{Adapter, Peripheral};
|
|
|
|
use futures::{Stream, StreamExt};
|
|
|
|
use futures::{Stream, StreamExt};
|
|
|
|
|
|
|
|
use tokio::sync::oneshot;
|
|
|
|
use uuid::Uuid;
|
|
|
|
use uuid::Uuid;
|
|
|
|
|
|
|
|
|
|
|
|
use crate::ble::BleError;
|
|
|
|
use crate::ble::BleError;
|
|
|
|
@ -69,6 +71,29 @@ impl BleSource {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Stream wrapper that cancels the background notification router on drop, so a
|
|
|
|
|
|
|
|
/// reconnect does not leak the previous cycle's routing task.
|
|
|
|
|
|
|
|
struct CancellableStream {
|
|
|
|
|
|
|
|
inner: tokio_stream::wrappers::UnboundedReceiverStream<Telemetry>,
|
|
|
|
|
|
|
|
cancel: Option<oneshot::Sender<()>>,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl Stream for CancellableStream {
|
|
|
|
|
|
|
|
type Item = Telemetry;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Telemetry>> {
|
|
|
|
|
|
|
|
Pin::new(&mut self.inner).poll_next(cx)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl Drop for CancellableStream {
|
|
|
|
|
|
|
|
fn drop(&mut self) {
|
|
|
|
|
|
|
|
if let Some(cancel) = self.cancel.take() {
|
|
|
|
|
|
|
|
let _ = cancel.send(());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[async_trait]
|
|
|
|
#[async_trait]
|
|
|
|
impl SensorSource for BleSource {
|
|
|
|
impl SensorSource for BleSource {
|
|
|
|
async fn scan(&self, seconds: u64) -> Result<Vec<Device>, BleError> {
|
|
|
|
async fn scan(&self, seconds: u64) -> Result<Vec<Device>, BleError> {
|
|
|
|
@ -106,19 +131,33 @@ impl SensorSource for BleSource {
|
|
|
|
// `request_control` can await confirmation while telemetry is still being consumed.
|
|
|
|
// `request_control` can await confirmation while telemetry is still being consumed.
|
|
|
|
let (tx, rx) = tokio::sync::mpsc::unbounded_channel::<Telemetry>();
|
|
|
|
let (tx, rx) = tokio::sync::mpsc::unbounded_channel::<Telemetry>();
|
|
|
|
let control = self.control.clone();
|
|
|
|
let control = self.control.clone();
|
|
|
|
|
|
|
|
let (cancel_tx, cancel_rx) = oneshot::channel::<()>();
|
|
|
|
|
|
|
|
|
|
|
|
tokio::spawn(async move {
|
|
|
|
tokio::spawn(async move {
|
|
|
|
let mut notifications = notifications;
|
|
|
|
let mut notifications = notifications;
|
|
|
|
let mut acc = CscAccumulator::new();
|
|
|
|
let mut acc = CscAccumulator::new();
|
|
|
|
while let Some(n) = notifications.next().await {
|
|
|
|
let mut cancel_rx = cancel_rx;
|
|
|
|
for t in parse_notification(n, &mut acc, &control) {
|
|
|
|
loop {
|
|
|
|
let _ = tx.send(t);
|
|
|
|
tokio::select! {
|
|
|
|
|
|
|
|
n = notifications.next() => {
|
|
|
|
|
|
|
|
match n {
|
|
|
|
|
|
|
|
Some(n) => {
|
|
|
|
|
|
|
|
for t in parse_notification(n, &mut acc, &control) {
|
|
|
|
|
|
|
|
let _ = tx.send(t);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
None => break,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
_ = &mut cancel_rx => break,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
let stream: Pin<Box<dyn Stream<Item = Telemetry> + Send>> =
|
|
|
|
let stream: Pin<Box<dyn Stream<Item = Telemetry> + Send>> = Box::pin(CancellableStream {
|
|
|
|
Box::pin(tokio_stream::wrappers::UnboundedReceiverStream::new(rx));
|
|
|
|
inner: tokio_stream::wrappers::UnboundedReceiverStream::new(rx),
|
|
|
|
|
|
|
|
cancel: Some(cancel_tx),
|
|
|
|
|
|
|
|
});
|
|
|
|
Ok(stream)
|
|
|
|
Ok(stream)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|