From 0590f57e5af393bebe22a698624cb9a8f264692f Mon Sep 17 00:00:00 2001 From: Andrzej Klajnert Date: Sun, 27 Sep 2020 17:37:09 +0200 Subject: [PATCH] Finished move_to() method, add some docstrings --- Cargo.toml | 3 +- src/lib.rs | 114 ++++++++++++++++++++++++++++++++++------------------- 2 files changed, 75 insertions(+), 42 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b2b807d..821bfce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,5 +7,4 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -#btleplug = "0.5.1" -btleplug = { path = "../btleplug" } \ No newline at end of file +btleplug = "0.5.1" \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 9859702..d358543 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ use btleplug::corebluetooth::{ use btleplug::winrtble::{ adapter::Adapter, manager::Manager, peripheral::Peripheral as PeripheralStruct, }; +use std::cmp::{max, min, Ordering}; use std::thread; use std::time::Duration; @@ -22,59 +23,53 @@ use std::time::Duration; #[cfg(any(target_os = "windows", target_os = "macos"))] fn get_central(manager: &Manager) -> Adapter { let adapters = manager.adapters().unwrap(); - adapters.into_iter().nth(0).unwrap() + adapters.into_iter().next().unwrap() } #[cfg(target_os = "linux")] fn get_central(manager: &Manager) -> ConnectedAdapter { let adapters = manager.adapters().unwrap(); - let adapter = adapters.into_iter().nth(0).unwrap(); + let adapter = adapters.into_iter().next().unwrap(); adapter.connect().unwrap() } -#[cfg(any(target_os = "windows", target_os = "macos"))] -type BtCentral = Adapter; - -#[cfg(target_os = "linux")] -type BtCentral = ConnectedAdapter; - const CONTROL_UUID: UUID = UUID::B128([ 0x8a, 0xf7, 0x15, 0x02, 0x9c, 0x00, 0x49, 0x8a, 0x24, 0x10, 0x8a, 0x33, 0x02, 0x00, 0xfa, 0x99, ]); -const STATUS_UUID: UUID = UUID::B128([ - 0x8a, 0xf7, 0x15, 0x02, 0x9c, 0x00, 0x49, 0x8a, 0x24, 0x10, 0x8a, 0x33, 0x21, 0x00, 0xfa, 0x99, -]); const POSITION_UUID: UUID = UUID::B128([ - 0x8a, 0xf7, 0x15, 0x02, 0x9c, 0x00, 0x49, 0x8a, 0x24, 0x10, 0x8a, 0x33, 0x20, 0x00, 0xfa, 0x99, + 0x8a, 0xf7, 0x15, 0x02, 0x9c, 0x00, 0x49, 0x8a, 0x24, 0x10, 0x8a, 0x33, 0x21, 0x00, 0xfa, 0x99, ]); const UP: [u8; 2] = [0x47, 0x00]; const DOWN: [u8; 2] = [0x46, 0x00]; const STOP: [u8; 2] = [0xFF, 0x00]; -pub const MIN_HEIGHT: f32 = 0.62; -pub const MAX_HEIGHT: f32 = 1.27; +pub const MIN_HEIGHT: i16 = 6200; +pub const MAX_HEIGHT: i16 = 12700; /// convert desk response from bytes to meters /// /// ``` -/// assert_eq!(idasen::bytes_to_meters(&[0x64, 0x19, 0x00, 0x00]), idasen::MAX_HEIGHT); -/// assert_eq!(idasen::bytes_to_meters(&[0x00, 0x00, 0x00, 0x00]), idasen::MIN_HEIGHT); -/// assert_eq!(idasen::bytes_to_meters(&[0x51, 0x04, 0x00, 0x00]), 0.7305); -/// assert_eq!(idasen::bytes_to_meters(&[0x08, 0x08, 0x00, 0x00]), 0.8256); +/// assert_eq!(idasen::bytes_to_tenth_milimeters(&[0x64, 0x19, 0x00, 0x00]), idasen::MAX_HEIGHT); +/// assert_eq!(idasen::bytes_to_tenth_milimeters(&[0x00, 0x00, 0x00, 0x00]), idasen::MIN_HEIGHT); +/// assert_eq!(idasen::bytes_to_tenth_milimeters(&[0x51, 0x04, 0x00, 0x00]), 7305); +/// assert_eq!(idasen::bytes_to_tenth_milimeters(&[0x08, 0x08, 0x00, 0x00]), 8256); +/// assert_eq!(idasen::bytes_to_tenth_milimeters(&[0x64, 0x18, 0x00, 0x00]), 12444); /// ``` -pub fn bytes_to_meters(bytes: &[u8]) -> f32 { - let as_int = ((bytes[1] as u32) << 8) + bytes[0] as u32; - (as_int as f32 / 10000.0) + MIN_HEIGHT +pub fn bytes_to_tenth_milimeters(bytes: &[u8]) -> i16 { + let as_int = ((bytes[1] as i16) << 8) + bytes[0] as i16; + as_int + MIN_HEIGHT } pub struct Idasen { - manager: Manager, - central: BtCentral, desk: PeripheralStruct, control_characteristic: Characteristic, - status_characteristic: Characteristic, + position_characteristic: Characteristic, +} + +pub enum Error { + PositionNotInRange, } impl Idasen { @@ -103,37 +98,76 @@ impl Idasen { .find(|characteristic| characteristic.uuid == CONTROL_UUID) .unwrap() .clone(); - let status_characteristic = characteristics + let position_characteristic = characteristics .iter() - .find(|characteristics| characteristics.uuid == STATUS_UUID) + .find(|characteristics| characteristics.uuid == POSITION_UUID) .unwrap() .clone(); Self { - manager, - central, desk, control_characteristic, - status_characteristic, + position_characteristic, } } - pub fn up(&self) { - self.desk.command(&self.control_characteristic, &UP); + /// Move desk up. + pub fn up(&self) -> btleplug::Result<()> { + self.desk.command(&self.control_characteristic, &UP) + } + + /// Lower the desk's position. + pub fn down(&self) -> btleplug::Result<()> { + self.desk.command(&self.control_characteristic, &DOWN) } - pub fn down(&self) { - self.desk.command(&self.control_characteristic, &DOWN); + /// Stop desk from moving. + pub fn stop(&self) -> btleplug::Result<()> { + self.desk.command(&self.control_characteristic, &STOP) } - pub fn stop(&self) { - self.desk.command(&self.control_characteristic, &STOP); + /// Move desk to a desired position. The precision is decent, usually less than 1mm off. + pub fn move_to(&self, target_position: i16) -> Result<(), Error> { + if target_position < MIN_HEIGHT || target_position > MAX_HEIGHT { + return Err(Error::PositionNotInRange); + } + + let going_up = match target_position.cmp(&self.position()) { + Ordering::Greater => true, + Ordering::Less => false, + Ordering::Equal => return Ok(()), + }; + + let mut position_reached = false; + let mut last_position = self.position(); + let mut speed; + while !position_reached { + let current_position = self.position(); + let remaining_distance = (target_position - current_position).abs(); + speed = (last_position - current_position).abs(); + if remaining_distance <= min(speed, 5) { + position_reached = true; + let _ = self.stop(); + } else if going_up { + let _ = self.up(); + } else if !going_up { + let _ = self.down(); + } + if remaining_distance < max(speed * 10, 10) { + let _ = self.stop(); + } + last_position = current_position; + } + + Ok(()) } - pub fn height(&self) -> f32 { - let response = self - .desk - .read_by_type(&self.status_characteristic, self.status_characteristic.uuid); - bytes_to_meters(&response.unwrap()) + /// Return the desk height in tenth milimeters (1m = 10000) + pub fn position(&self) -> i16 { + let response = self.desk.read_by_type( + &self.position_characteristic, + self.position_characteristic.uuid, + ); + bytes_to_tenth_milimeters(&response.unwrap()) } }