Updating to do checking of seen UUIDs vs those expected in the Spec.

This commit is contained in:
Daniel Mayfield
2025-09-03 18:44:01 -04:00
parent 740168232b
commit 0c8834ccb3
3 changed files with 129 additions and 8 deletions

5
Cargo.lock generated
View File

@ -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",

View File

@ -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"

View File

@ -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<Uuid,CharacteristicData>,
name: String
}
fn build_map() -> HashMap<Uuid,ServiceData> {
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::<Uuid,CharacteristicData>::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);
}
}
}