blob: ca7d03956f2829cade7701eb2871e274f337191f [file] [log] [blame] [edit]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use fidl_fuchsia_bluetooth_gatt2::{
self as fidl_gatt, Characteristic as FidlCharacteristic, ServiceInfo, ServiceKind,
};
use fuchsia_bluetooth::assigned_numbers::{
find_characteristic_number, find_descriptor_number, find_service_uuid,
};
use fuchsia_bluetooth::types::Uuid;
use std::fmt;
// TODO(armansito): Make these objects stateful so that GATT operations can be performed through
// them. Later, move these into a public bluetooth crate as a developer API.
/// Service
pub struct Service {
pub info: ServiceInfo,
// The characteristics of this service. None, if not yet discovered.
characteristics: Option<Vec<Characteristic>>,
}
impl Service {
pub fn new(info: ServiceInfo) -> Service {
Service { info: info, characteristics: None }
}
pub fn set_characteristics(&mut self, chrcs: Vec<FidlCharacteristic>) {
self.characteristics = Some(chrcs.into_iter().map(|info| Characteristic(info)).collect());
}
}
impl fmt::Display for Service {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let type_pretty = match &self.info.type_ {
Some(fidl_uuid) => {
let uuid = Uuid::from(fidl_uuid).to_string();
find_service_uuid(&uuid).map(|an| String::from(an.name)).unwrap_or(uuid)
}
None => String::from("(unknown type)"),
};
let kind_pretty = match self.info.kind {
Some(ServiceKind::Primary) => "primary",
Some(ServiceKind::Secondary) => "secondary",
None => "(unknown kind)",
};
let id = self.info.handle.map_or(0u64, |h| h.value);
write!(f, "[{} service: id: {}, type: {}]", kind_pretty, id, type_pretty)?;
if let Some(ref chrcs) = self.characteristics {
let mut i: i32 = 0;
for ref chrc in chrcs {
write!(f, "\n {}: {}", i, chrc)?;
i += 1;
}
}
Ok(())
}
}
struct Characteristic(FidlCharacteristic);
impl fmt::Display for Characteristic {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let type_pretty = match &self.0.type_ {
Some(fidl_uuid) => {
let uuid = Uuid::from(fidl_uuid).to_string();
find_characteristic_number(&uuid).map(|an| String::from(an.name)).unwrap_or(uuid)
}
None => String::from("(unknown)"),
};
let id = &self.0.handle.map_or(0u64, |h| h.value);
let props_pretty =
self.0.properties.map_or_else(|| String::from("unknown"), |p| props_to_string(p));
write!(f, "[chara.: id: {}, type: {}, prop.: {}]", id, type_pretty, props_pretty)?;
if let Some(ref descrs) = self.0.descriptors {
let mut i: i32 = 0;
for ref descr in descrs {
let type_pretty = match &descr.type_ {
Some(fidl_uuid) => {
let uuid = Uuid::from(fidl_uuid).to_string();
find_descriptor_number(&uuid)
.map(|an| String::from(an.name))
.unwrap_or(uuid)
}
None => String::from("unknown"),
};
let id = &descr.handle.map_or(0u64, |h| h.value);
write!(f, "\n {}: [descr.: id: {}, type: {}]", i, id, type_pretty)?;
i += 1;
}
}
Ok(())
}
}
fn props_to_string(props: fidl_gatt::CharacteristicPropertyBits) -> String {
let mut prop_strs = vec![];
if props.contains(fidl_gatt::CharacteristicPropertyBits::BROADCAST) {
prop_strs.push("broadcast");
}
if props.contains(fidl_gatt::CharacteristicPropertyBits::READ) {
prop_strs.push("read");
}
if props.contains(fidl_gatt::CharacteristicPropertyBits::WRITE_WITHOUT_RESPONSE) {
prop_strs.push("write (without response)");
}
if props.contains(fidl_gatt::CharacteristicPropertyBits::WRITE) {
prop_strs.push("write");
}
if props.contains(fidl_gatt::CharacteristicPropertyBits::NOTIFY) {
prop_strs.push("notify");
}
if props.contains(fidl_gatt::CharacteristicPropertyBits::INDICATE) {
prop_strs.push("indicate");
}
if props.contains(fidl_gatt::CharacteristicPropertyBits::AUTHENTICATED_SIGNED_WRITES) {
prop_strs.push("write (signed)");
}
if props.contains(fidl_gatt::CharacteristicPropertyBits::RELIABLE_WRITE) {
prop_strs.push("write (reliable)");
}
if props.contains(fidl_gatt::CharacteristicPropertyBits::WRITABLE_AUXILIARIES) {
prop_strs.push("writable aux.");
}
prop_strs.join(", ")
}