, DeskSubscription>,
+ cancel_subscription_tx: oneshot::Sender<()>,
+ disconnect_on_drop: bool,
+ },
+ Disconnected {
+ peripheral: P,
+ },
+}
+
+impl UpliftDesk {
+ pub fn new(peripheral: P) -> Self {
+ Self::Disconnected { peripheral }
+ }
+
+ pub async fn connect(&mut self) -> Result<()> {
+ if !matches!(self, UpliftDesk::Connected { peripheral, .. } if peripheral.is_connected().await?)
+ {
+ let peripheral = self.peripheral().clone();
+
+ log::debug!("{{{}}} - Connecting to desk", peripheral.id());
+
+ peripheral.connect().await?;
+ peripheral.discover_services().await?;
+
+ let (service, desk_uuids) = peripheral.services().iter().find_map(|service| {
+ for desk in DESK_UUIDS {
+ if desk.service_uuid == service.uuid {
+ return Some((service.clone(), desk));
+ }
+ }
+ None
+ }).ok_or_else(|| {
+ log::warn!("{{{}}} - Attempted to connect to desk that isn't advertising the necessary Service or Characteristics", peripheral.id());
+ Error::DeviceNotFound
+ })?;
+
+ let (data_in_characteristic, data_out_characteristic, name_characteristic) =
+ get_characteristics(desk_uuids, service.characteristics)?;
+
+ let (cancel_subscription_tx, cancel_subscription_rx) = oneshot::channel();
+
+ // we're about to drop our non-connected self, we don't want to drop our connection as we're establishing it
+ if let UpliftDesk::Connected {
+ disconnect_on_drop, ..
+ } = self
+ {
+ *disconnect_on_drop = true;
+ }
+
+ *self = Self::Connected {
+ peripheral,
+ disconnect_on_drop: false,
+ data_in_characteristic,
+ data_out_characteristic,
+ name_characteristic,
+ subscription: Either::Left(cancel_subscription_rx),
+ cancel_subscription_tx,
+ };
+ }
+
+ Ok(())
+ }
+
+ pub fn id(&self) -> UpliftDeskId {
+ UpliftDeskId(self.peripheral().id())
+ }
+
+ pub async fn rssi(&self) -> Result