Skip to content

Commit

Permalink
add convenience for read-only characteristics
Browse files Browse the repository at this point in the history
  • Loading branch information
lulf committed Mar 15, 2024
1 parent 79030bf commit 686fefc
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 38 deletions.
18 changes: 7 additions & 11 deletions examples/nrf-sdc/src/bin/ble_bas_peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use static_cell::StaticCell;
use trouble_host::{
adapter::{Adapter, HostResources},
advertise::{AdStructure, AdvertiseConfig, BR_EDR_NOT_SUPPORTED, LE_GENERAL_DISCOVERABLE},
attribute::{AttributeTable, Characteristic, CharacteristicProp, Service, Uuid},
attribute::{AttributeTable, CharacteristicProp, Service, Uuid},
PacketQos,
};

Expand Down Expand Up @@ -129,17 +129,13 @@ async fn main(spawner: Spawner) {
let mut table: AttributeTable<'_, NoopRawMutex, 10> = AttributeTable::new();

// Generic Access Service (mandatory)
let mut id = [b'T', b'r', b'o', b'u', b'b', b'l', b'e'];
let mut appearance = [0x80, 0x07];
let id = b"Trouble";
let appearance = [0x80, 0x07];
let mut bat_level = [0; 1];
let handle = {
let mut svc = table.add_service(Service::new(0x1800));
let _ = svc.add_characteristic(Characteristic::new(0x2a00, &[CharacteristicProp::Read], &mut id[..]));
let _ = svc.add_characteristic(Characteristic::new(
0x2a01,
&[CharacteristicProp::Read],
&mut appearance[..],
));
let _ = svc.add_characteristic_ro(0x2a00, id);
let _ = svc.add_characteristic_ro(0x2a01, &appearance[..]);
drop(svc);

// Generic attribute service (mandatory)
Expand All @@ -148,11 +144,11 @@ async fn main(spawner: Spawner) {
// Battery service
let mut svc = table.add_service(Service::new(0x180f));

svc.add_characteristic(Characteristic::new(
svc.add_characteristic(
0x2a19,
&[CharacteristicProp::Read, CharacteristicProp::Notify],
&mut bat_level,
))
)
};

let server = adapter.gatt_server(&table);
Expand Down
68 changes: 41 additions & 27 deletions host/src/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ pub enum AttributeData<'d> {
Service {
uuid: Uuid,
},
ReadOnlyData {
props: CharacteristicProps,
value: &'d [u8],
},
Data {
props: CharacteristicProps,
value: &'d mut [u8],
Expand Down Expand Up @@ -89,6 +93,16 @@ impl<'d> AttributeData<'d> {
return Err(AttErrorCode::ReadNotPermitted);
}
match self {
Self::ReadOnlyData { props, value } => {
if offset > value.len() {
return Ok(0);
}
let len = data.len().min(value.len() - offset);
if len > 0 {
data[..len].copy_from_slice(&value[offset..offset + len]);
}
Ok(len)
}
Self::Data { props, value } => {
if offset > value.len() {
return Ok(0);
Expand Down Expand Up @@ -188,8 +202,7 @@ impl<'d> AttributeData<'d> {
*indications = data[0] & 0x02 != 0;
Ok(())
}
Self::Declaration { .. } => Err(AttErrorCode::WriteNotPermitted),
Self::Service { .. } => Err(AttErrorCode::WriteNotPermitted),
_ => Err(AttErrorCode::WriteNotPermitted),
}
}
}
Expand Down Expand Up @@ -347,7 +360,12 @@ pub struct ServiceBuilder<'r, 'd, M: RawMutex, const MAX: usize> {
}

impl<'r, 'd, M: RawMutex, const MAX: usize> ServiceBuilder<'r, 'd, M, MAX> {
pub fn add_characteristic(&mut self, c: Characteristic<'d>) -> CharacteristicHandle {
fn add_characteristic_internal(
&mut self,
uuid: Uuid,
props: CharacteristicProps,
data: AttributeData<'d>,
) -> CharacteristicHandle {
// First the characteristic declaration
let next = self.table.handle + 1;
let cccd = self.table.handle + 2;
Expand All @@ -356,25 +374,22 @@ impl<'r, 'd, M: RawMutex, const MAX: usize> ServiceBuilder<'r, 'd, M, MAX> {
handle: 0,
last_handle_in_group: 0,
data: AttributeData::Declaration {
props: c.props,
props: props,
handle: next,
uuid: c.uuid,
uuid,
},
});

// Then the value declaration
self.table.push(Attribute {
uuid: c.uuid,
uuid,
handle: 0,
last_handle_in_group: 0,
data: AttributeData::Data {
props: c.props,
value: c.storage,
},
data,
});

// Add optional CCCD handle
let cccd_handle = if c.props.any(&[CharacteristicProp::Notify, CharacteristicProp::Indicate]) {
let cccd_handle = if props.any(&[CharacteristicProp::Notify, CharacteristicProp::Indicate]) {
self.table.push(Attribute {
uuid: CHARACTERISTIC_CCCD_UUID16,
handle: 0,
Expand All @@ -394,6 +409,21 @@ impl<'r, 'd, M: RawMutex, const MAX: usize> ServiceBuilder<'r, 'd, M, MAX> {
cccd_handle,
}
}

pub fn add_characteristic<U: Into<Uuid>>(
&mut self,
uuid: U,
props: &[CharacteristicProp],
storage: &'d mut [u8],
) -> CharacteristicHandle {
let props = props.into();
self.add_characteristic_internal(uuid.into(), props, AttributeData::Data { props, value: storage })
}

pub fn add_characteristic_ro<U: Into<Uuid>>(&mut self, uuid: U, value: &'d [u8]) -> CharacteristicHandle {
let props = [CharacteristicProp::Read].into();
self.add_characteristic_internal(uuid.into(), props, AttributeData::ReadOnlyData { props, value })
}
}

impl<'r, 'd, M: RawMutex, const MAX: usize> Drop for ServiceBuilder<'r, 'd, M, MAX> {
Expand Down Expand Up @@ -445,22 +475,6 @@ impl Service {
}
}

impl<'d> Characteristic<'d> {
pub fn new<U: Into<Uuid>>(uuid: U, props: &[CharacteristicProp], storage: &'d mut [u8]) -> Self {
Self {
uuid: uuid.into(),
props: props.into(),
storage,
}
}
}

pub struct Characteristic<'d> {
pub uuid: Uuid,
pub props: CharacteristicProps,
pub storage: &'d mut [u8],
}

#[derive(Clone, Copy)]
pub struct CharacteristicProps(u8);

Expand Down

0 comments on commit 686fefc

Please sign in to comment.