From 0c8834ccb3ee8fef391666451545b1eb37c2c2c1 Mon Sep 17 00:00:00 2001 From: Daniel Mayfield Date: Wed, 3 Sep 2025 18:44:01 -0400 Subject: [PATCH] Updating to do checking of seen UUIDs vs those expected in the Spec. --- Cargo.lock | 5 +- Cargo.toml | 1 + src/main.rs | 131 +++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 129 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8ae6fcf..eba00c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -78,6 +78,7 @@ dependencies = [ "btleplug", "pretty_env_logger", "tokio", + "uuid", ] [[package]] @@ -889,9 +890,9 @@ checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "uuid" -version = "1.18.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 28d2db4..a7694ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,4 @@ anyhow = "1.0.99" btleplug = "0.11.8" pretty_env_logger = "0.5.0" tokio = { version = "1.47.1", features = ["full"] } +uuid = "1.18.1" diff --git a/src/main.rs b/src/main.rs index c9e8ec8..27adb59 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,107 @@ // See the "macOS permissions note" in README.md before running this on macOS // Big Sur or later. +use std::str::FromStr; use std::time::Duration; use tokio::time; use btleplug::api::{BDAddr, Central, CharPropFlags, Manager as _, Peripheral, ScanFilter}; use btleplug::platform::Manager; +use uuid::{Uuid,uuid}; + +use std::collections::HashMap; + +struct CharacteristicData { + expected_size: u16, + name: String +} +struct ServiceData { + characteristics: HashMap, + name: String +} +fn build_map() -> HashMap { + let mut retval = HashMap::new(); + + retval.insert( + Uuid::from_bytes([0xB4, 0x09, 0x8D, 0xE0, 0x61, 0x08, 0x66, 0xBA, 0x61, 0x4B, 0x3C, 0xF1, 0x5A, 0xAD, 0x66, 0x99]), + ServiceData { characteristics: HashMap::new(), name: String::from_str("Pairing Service").unwrap() }); + + let mut lift_service_characteristics_map = HashMap::new(); + lift_service_characteristics_map.insert( + uuid!("c1401121-8dda-45a3-959b-d23a0f8f53d7"), + CharacteristicData{ expected_size: 0, + name: String::from_str("Up Button").unwrap() }); + lift_service_characteristics_map.insert( + uuid!("c1401122-8dda-45a3-959b-d23a0f8f53d7"), + CharacteristicData{ expected_size: 0, + name: String::from_str("Down Button").unwrap() }); + lift_service_characteristics_map.insert( + uuid!("c1401123-8dda-45a3-959b-d23a0f8f53d7"), + CharacteristicData{ expected_size: 0, + name: String::from_str("Stop Button").unwrap() }); + lift_service_characteristics_map.insert( + uuid!("c1401223-8dda-45a3-959b-d23a0f8f53d7"), + CharacteristicData{ expected_size: 0, + name: String::from_str("Learning Mode Button").unwrap() }); + lift_service_characteristics_map.insert( + uuid!("c1401124-8dda-45a3-959b-d23a0f8f53d7"), + CharacteristicData{ expected_size: 0, + name: String::from_str("Auxiliary Circuit Button").unwrap() }); + lift_service_characteristics_map.insert( + uuid!("c1401225-8dda-45a3-959b-d23a0f8f53d7"), + CharacteristicData{ expected_size: 0, + name: String::from_str("Automatic Mode Button").unwrap() }); + lift_service_characteristics_map.insert( + uuid!("c1411224-8dda-45a3-959b-d23a0f8f53d7"), + CharacteristicData{ expected_size: 0, + name: String::from_str("Device Bluetooth Name").unwrap() }); + lift_service_characteristics_map.insert( + uuid!("c1401321-8dda-45a3-959b-d23a0f8f53d7"), + CharacteristicData{ expected_size: 0, + name: String::from_str("Status of Limit Switches").unwrap() }); + lift_service_characteristics_map.insert( + uuid!("c1401322-8dda-45a3-959b-d23a0f8f53d7"), + CharacteristicData{ expected_size: 0, + name: String::from_str("Status of Motors").unwrap() }); + lift_service_characteristics_map.insert( + uuid!("c1401323-8dda-45a3-959b-d23a0f8f53d7"), + CharacteristicData{ expected_size: 0, + name: String::from_str("Status of Lift Controller").unwrap() }); + lift_service_characteristics_map.insert( + uuid!("c1401324-8dda-45a3-959b-d23a0f8f53d7"), + CharacteristicData{ expected_size: 0, + name: String::from_str("Reason Code for Lift Controller Status").unwrap() }); + + retval.insert(uuid!("c1400000-8dda-45a3-959b-d23a0f8f53d7"), + ServiceData { characteristics: lift_service_characteristics_map, + name: String::from_str("Lift Control Service").unwrap() }); + + let mut expanded_service_characteristics_map = HashMap::new(); + expanded_service_characteristics_map.insert( + uuid!("c1401421-8dda-45a3-959b-d23a0f8f53d7"), + CharacteristicData{ expected_size: 0, + name: String::from_str("Log Transmit Trigger").unwrap() }); + expanded_service_characteristics_map.insert( + uuid!("c1401422-8dda-45a3-959b-d23a0f8f53d7"), + CharacteristicData{ expected_size: 0, + name: String::from_str("Log Data Packet").unwrap() }); + expanded_service_characteristics_map.insert( + uuid!("c1411221-8dda-45a3-959b-d23a0f8f53d7"), + CharacteristicData{ expected_size: 0, + name: String::from_str("WiFi SSID").unwrap() }); + expanded_service_characteristics_map.insert( + uuid!("c1411222-8dda-45a3-959b-d23a0f8f53d7"), + CharacteristicData{ expected_size: 0, + name: String::from_str("WiFi Password").unwrap() }); + + retval.insert( + uuid!("c1410000-8dda-45a3-959b-d23a0f8f53d7"), + ServiceData { characteristics: HashMap::new(), + name: String::from_str("Expanded Control Service").unwrap() }); + return retval; +} + #[tokio::main] async fn main() -> anyhow::Result<()> { pretty_env_logger::init(); @@ -16,12 +111,13 @@ async fn main() -> anyhow::Result<()> { if adapter_list.is_empty() { eprintln!("No Bluetooth adapters found"); } + let uuidMap = build_map(); let command = std::env::args().nth(1).expect("help"); let param = std::env::args().nth(2).unwrap_or(String::from("aa:bb:cc:dd:ee:ff")); let mut help = false; let mut scan = false; let mut device = false; - + match command.as_str() { "help" => {help = true}, "scan" => {scan = true }, @@ -77,19 +173,42 @@ async fn main() -> anyhow::Result<()> { "Now connected ({:?}) to peripheral {:?}...", is_connected, &local_name ); - + peripheral.discover_services().await?; println!("Discover peripheral {:?} services...", &local_name); for service in peripheral.services() { + let mut characteristicInfo = &HashMap::::new(); + let serviceName; + let unknownServiceName = &String::from_str("Unknown Service").unwrap(); + if let Some(serviceLookup) = uuidMap.get(&service.uuid) { + serviceName = &serviceLookup.name; + characteristicInfo = &serviceLookup.characteristics; + } + else { + serviceName = &unknownServiceName; + } println!( - "Service UUID {}, primary: {}", - service.uuid, service.primary + "Service UUID {}, name {}", + service.uuid, serviceName ); for characteristic in service.characteristics { - println!(" Characteristic {:?} has {:?}", characteristic.uuid,characteristic.properties); + let characteristicName; + let characteristicSize; + let unknownCharacteristicName = &String::from_str("Unknown Characteristic").unwrap(); + if let Some(characteristicLookup) = characteristicInfo.get(&characteristic.uuid) { + characteristicName = &characteristicLookup.name; + characteristicSize = characteristicLookup.expected_size; + } + else { + characteristicName = unknownCharacteristicName; + characteristicSize = 0; + } + println!(" Characteristic {:?} ({:?}) has {:?}", characteristic.uuid,characteristicName,characteristic.properties); if characteristic.properties.contains(CharPropFlags::READ) { let data = peripheral.read(&characteristic).await?; - println!(" and data: {:?}",data) + println!(" and {:?} bytes of data data when expecting {:?}",data.len(),characteristicSize); + println!(" raw data: {:?}",data); + } } }