Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve characteristic interactions #151

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
9469199
Add gatt_traits code from nrf-softdevice repo
petekubiak Oct 28, 2024
3bd5d74
Add GattServerInterface trait
petekubiak Oct 28, 2024
f1904d0
[WIP] Begin implementing characteristic functions on service
petekubiak Oct 28, 2024
96b5e05
Tidy up for draft
petekubiak Oct 28, 2024
ff36d52
Revert "Add GattServerInterface trait"
petekubiak Oct 30, 2024
d891a68
[WIP] Link characteristic type to handle with PhantomData
petekubiak Oct 30, 2024
6eacfe1
Fix issue with adding device name RO characteristic
petekubiak Oct 31, 2024
91860ef
[WIP] Begin updating examples
petekubiak Nov 1, 2024
d324467
Store a copy of GAP data to ensure required lifetime
petekubiak Nov 4, 2024
b6641fa
Address missing docs errors
petekubiak Nov 4, 2024
ce7a768
[WIP] Add read and write callbacks for attributes
petekubiak Nov 4, 2024
4835725
Remove false optional appearance from characteristic UUID argument
petekubiak Nov 6, 2024
7472d41
[WIP] Add on_read argument to gatt_service macro
petekubiak Nov 7, 2024
b551c7c
Add on_read and on_write arguments to characteristic attributes
petekubiak Nov 7, 2024
fa55978
Change callbacks to take reference to connection rather than ownership
petekubiak Nov 7, 2024
cb8915a
Implement calling callbacks on read and write events
petekubiak Nov 7, 2024
54dc667
Add usage of callbacks to examples and tests
petekubiak Nov 7, 2024
6959861
Add write property to example app characteristic to demonstrate write…
petekubiak Nov 7, 2024
2934ea8
Set ESP32 logging back to info level and allow trace from application
petekubiak Nov 7, 2024
4a9c320
Remove unused code
petekubiak Nov 7, 2024
edd3a8a
Merge remote-tracking branch 'origin/main' into consolidate-character…
petekubiak Nov 7, 2024
1c58d4b
Add debug to write callback in gatt_derive example
petekubiak Nov 7, 2024
ae68984
Replace cloned value with constant in test
petekubiak Nov 7, 2024
000d1e1
Bump version numbers to signify breaking changes
petekubiak Nov 7, 2024
9f7bfc4
Update AttErrorCode to match BT spec v6.0 ATT_ERROR_RSP PDU
petekubiak Nov 8, 2024
e6bca74
Reinstate docstrings for AttErrorCode variants
petekubiak Nov 8, 2024
016e68f
Change write callback to allow accept/reject control over write
petekubiak Nov 8, 2024
9577581
Align conn/connection naming
petekubiak Nov 8, 2024
39ed273
Add comments for unsafe blocks in gatt_traits
petekubiak Nov 8, 2024
c924901
Give from_gatt a Result return type to remove embedded unwraps
petekubiak Nov 8, 2024
23b13fb
Revert "Bump version numbers to signify breaking changes"
petekubiak Nov 8, 2024
1faee8d
Remove optional arguments from API and implement setting callbacks in…
petekubiak Nov 8, 2024
5fe0463
Add examples of callbacks to service macro docstring
petekubiak Nov 8, 2024
a6d1738
Move initialisation of device name memory to GapConfig
petekubiak Nov 8, 2024
49d1991
Merge branch 'main' into consolidate-characteristic-interactions
petekubiak Nov 11, 2024
ccbab50
Fix gatt_derive test for expected rejection of first write request
petekubiak Nov 11, 2024
00f2d0d
Merge branch 'consolidate-characteristic-interactions' of github.com:…
petekubiak Nov 11, 2024
2e2984c
Fix inverted logic in testing of write callback rejection mechanism
petekubiak Nov 11, 2024
3ec80b5
Fix the other inverted logic in testing of write callback rejection m…
petekubiak Nov 11, 2024
394cba9
Return an error from AttributeTable::set() rather than asserting data…
petekubiak Nov 11, 2024
1d49296
Remove panics from gatt_traits and update docstrings
petekubiak Nov 11, 2024
9ff71f1
Handle from_gatt error in attribute.rs rather than unwrapping
petekubiak Nov 11, 2024
adb1c9b
Change notify function to take characteristic reference rather than o…
petekubiak Nov 12, 2024
3603109
Update example to match modified notify function signature
petekubiak Nov 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/apps/src/ble_bas_central.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ where
let service = services.first().unwrap().clone();

info!("Looking for value handle");
let c = client
let c: Characteristic<u8> = client
.characteristic_by_uuid(&service, &Uuid::new_short(0x2a19))
.await
.unwrap();
Expand Down
22 changes: 13 additions & 9 deletions examples/apps/src/ble_bas_peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ where
let server = Server::new_with_config(
stack,
GapConfig::Peripheral(PeripheralConfig {
name: "TrouBLE",
name: b"TrouBLE",
appearance: &appearance::GENERIC_POWER,
}),
);
Expand All @@ -61,16 +61,20 @@ async fn ble_task<C: Controller>(mut runner: Runner<'_, C>) -> Result<(), BleHos
runner.run().await
}

async fn gatt_task<C: Controller>(server: &Server<'_,'_, C>) {
async fn gatt_task<C: Controller>(server: &Server<'_, '_, C>) {
loop {
match server.next().await {
Ok(GattEvent::Write { handle, connection: _ }) => {
let _ = server.get(handle, |value| {
info!("[gatt] Write event on {:?}. Value written: {:?}", handle, value);
});
Ok(GattEvent::Write {
value_handle,
connection: _,
}) => {
info!("[gatt] Write event on {:?}", value_handle);
}
Ok(GattEvent::Read { handle, connection: _ }) => {
info!("[gatt] Read event on {:?}", handle);
Ok(GattEvent::Read {
value_handle,
connection: _,
}) => {
info!("[gatt] Read event on {:?}", value_handle);
}
Err(e) => {
error!("[gatt] Error processing GATT events: {:?}", e);
Expand Down Expand Up @@ -111,7 +115,7 @@ async fn advertise_task<C: Controller>(
Timer::after(Duration::from_secs(2)).await;
tick = tick.wrapping_add(1);
info!("[adv] notifying connection of tick {}", tick);
let _ = server.notify(server.battery_service.level, &conn, &[tick]).await;
let _ = server.notify(server.battery_service.level, &conn, &tick).await;
jamessizeland marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
2 changes: 2 additions & 0 deletions examples/apps/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ pub mod ble_bas_central;
pub mod ble_bas_peripheral;
pub mod ble_l2cap_central;
pub mod ble_l2cap_peripheral;

mod out;
6 changes: 3 additions & 3 deletions host-macro/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,11 @@ impl ServerBuilder {
}
}

#visibility fn get<F: FnMut(&[u8]) -> T, T>(&self, handle: Characteristic, f: F) -> Result<T, Error> {
self.server.server().table().get(handle, f)
#visibility fn get<T: trouble_host::types::gatt_traits::GattValue>(&self, handle: &Characteristic<T>) -> Result<T, Error> {
self.server.server().table().get(handle)
}

#visibility fn set(&self, handle: Characteristic, input: &[u8]) -> Result<(), Error> {
#visibility fn set<T: trouble_host::types::gatt_traits::GattValue>(&self, handle: &Characteristic<T>, input: &T) -> Result<(), Error> {
self.server.server().table().set(handle, input)
}
}
Expand Down
2 changes: 1 addition & 1 deletion host-macro/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ impl ServiceBuilder {
// add fields for each characteristic value handle
fields.push(syn::Field {
ident: Some(char_name.clone()),
ty: syn::Type::Verbatim(quote!(Characteristic)),
ty: syn::Type::Verbatim(quote!(Characteristic<#ty>)),
attrs: Vec::new(),
colon_token: Default::default(),
vis: ch.vis.clone(),
Expand Down
4 changes: 2 additions & 2 deletions host/src/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,12 +395,12 @@ impl<'d, M: RawMutex, const MAX: usize> AttributeTable<'d, M, MAX> {
/// The return value of the closure is returned in this function and is assumed to be infallible.
///
/// If the characteristic for the handle cannot be found, an error is returned.
pub fn get<F: FnMut(&[u8]) -> T, T: GattValue>(&self, handle: &Characteristic<T>, mut f: F) -> Result<T, Error> {
pub fn get<T: GattValue>(&self, handle: &Characteristic<T>) -> Result<T, Error> {
jamessizeland marked this conversation as resolved.
Show resolved Hide resolved
self.iterate(|mut it| {
while let Some(att) = it.next() {
if att.handle == handle.handle {
if let AttributeData::Data { props, value } = &mut att.data {
let v = f(value);
let v = <T as GattValue>::from_gatt(value);
return Ok(v);
}
}
Expand Down
23 changes: 18 additions & 5 deletions host/src/gap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@
//! In addition, this profile includes common format requirements for
//! parameters accessible on the user interface level.

use core::fmt::Write;

use crate::prelude::*;
use embassy_sync::blocking_mutex::raw::RawMutex;
use heapless::Vec;
use static_cell::StaticCell;

/// Advertising packet is limited to 31 bytes. 9 of these are used by other GAP data, leaving 22 for Device Name characteristic
const DEVICE_NAME_MAX_LENGTH: usize = 22;

pub mod appearance {
//! The representation of the external appearance of the device.
//!
Expand Down Expand Up @@ -63,7 +69,7 @@ pub enum GapConfig<'a> {
/// Configuration for a peripheral device GAP Service.
pub struct PeripheralConfig<'a> {
/// The name of the peripheral device.
pub name: &'a [u8; 22],
pub name: &'a Vec<u8, DEVICE_NAME_MAX_LENGTH>,
/// The representation of the external appearance of the device.
///
/// /// Example: `&appearance::GENERIC_SENSOR`
Expand All @@ -75,7 +81,7 @@ pub struct PeripheralConfig<'a> {
/// Configuration for a central device GAP Service.
pub struct CentralConfig<'a> {
/// The name of the central device.
pub name: &'a [u8; 22],
pub name: &'a Vec<u8, DEVICE_NAME_MAX_LENGTH>,
petekubiak marked this conversation as resolved.
Show resolved Hide resolved
/// The representation of the external appearance of the device.
///
/// Example: `&appearance::GENERIC_SENSOR`
Expand All @@ -88,9 +94,9 @@ impl<'a> GapConfig<'a> {
///
/// This configuration will use the `GENERIC_UNKNOWN` appearance.
pub fn default(name: &'a str) -> Self {
static NAME_BYTES: StaticCell<[u8; 22]> = StaticCell::new();
let name_bytes = NAME_BYTES.init([0; 22]);
name_bytes.copy_from_slice(name.as_bytes());
static NAME_BYTES: StaticCell<Vec<u8, DEVICE_NAME_MAX_LENGTH>> = StaticCell::new();
let name_bytes = NAME_BYTES.init(Vec::new());
fill_vec(name_bytes, name.as_bytes());
GapConfig::Peripheral(PeripheralConfig {
name: name_bytes,
appearance: &appearance::GENERIC_UNKNOWN,
Expand Down Expand Up @@ -124,3 +130,10 @@ impl<'a> GapConfig<'a> {
table.add_service(Service::new(GATT_UUID)); // GATT UUID (mandatory)
}
}

fn fill_vec<const N: usize>(vector: &mut Vec<u8, N>, bytes: &[u8]) {
let mut byte_index = 0;
while byte_index < bytes.len() && vector.push(bytes[byte_index]).is_ok() {
byte_index += 1;
}
}
14 changes: 7 additions & 7 deletions host/src/gatt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl<'reference, 'values, C: Controller, M: RawMutex, const MAX: usize, const L2
///
/// If attributes are written or read, an event will be returned describing the handle
/// and the connection causing the event.
pub async fn next<T: GattValue>(&self) -> Result<GattEvent<'reference, T>, Error> {
pub async fn next(&self) -> Result<GattEvent<'reference>, Error> {
loop {
let (handle, pdu) = self.rx.receive().await;
if let Some(connection) = self.connections.get_connected_handle(handle) {
Expand All @@ -76,17 +76,17 @@ impl<'reference, 'values, C: Controller, M: RawMutex, const MAX: usize, const L2
let event = match att {
AttReq::Write { handle, data } => Some(GattEvent::Write {
connection,
handle: self.server.table.find_characteristic_by_value_handle(handle)?,
value_handle: handle,
}),

AttReq::Read { handle } => Some(GattEvent::Read {
connection,
handle: self.server.table.find_characteristic_by_value_handle(handle)?,
value_handle: handle,
}),

AttReq::ReadBlob { handle, offset } => Some(GattEvent::Read {
connection,
handle: self.server.table.find_characteristic_by_value_handle(handle)?,
value_handle: handle,
}),
_ => None,
};
Expand Down Expand Up @@ -157,20 +157,20 @@ impl<'reference, 'values, C: Controller, M: RawMutex, const MAX: usize, const L2

/// An event returned while processing GATT requests.
#[derive(Clone)]
pub enum GattEvent<'reference, T: GattValue> {
pub enum GattEvent<'reference> {
/// A characteristic was read.
Read {
/// Connection that read the characteristic.
connection: Connection<'reference>,
/// Characteristic handle that was read.
handle: Characteristic<T>,
value_handle: u16,
},
/// A characteristic was written.
Write {
/// Connection that wrote the characteristic.
connection: Connection<'reference>,
/// Characteristic handle that was written.
handle: Characteristic<T>,
value_handle: u16,
},
}

Expand Down
2 changes: 1 addition & 1 deletion host/src/types/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Common types.
pub(crate) mod gatt_traits;
pub mod gatt_traits;
pub(crate) mod l2cap;
pub(crate) mod primitives;

Expand Down
4 changes: 2 additions & 2 deletions host/tests/gatt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ async fn gatt_client_server() {
let mut expected = value[0].wrapping_add(1);
let mut svc = table.add_service(Service::new(0x1800));
let _ = svc.add_characteristic_ro(0x2a00, id);
let _ = svc.add_characteristic_ro(0x2a01, &appearance[..]);
let _ = svc.add_characteristic_ro(0x2a01, &appearance);
svc.build();

// Generic attribute service (mandatory)
Expand Down Expand Up @@ -71,7 +71,7 @@ async fn gatt_client_server() {
handle,
}) => {
assert_eq!(handle, value_handle);
let _ = server.server().table().get(handle, |value| {
let _ = server.server().table().get(&handle, |value| {
assert_eq!(expected, value[0]);
expected += 1;
writes += 1;
Expand Down
Loading