From b1671f1aac45ebc4aa92b83cc20ed31c25637f39 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Sat, 25 Jan 2025 16:07:53 +0100 Subject: [PATCH] fix: use async version of send for gatt replies * Print warning if outbound channel is full on reply drop --- examples/apps/src/ble_bas_peripheral.rs | 31 ++++++++++++++++++------- host/src/gatt.rs | 22 +++++++++++++++++- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/examples/apps/src/ble_bas_peripheral.rs b/examples/apps/src/ble_bas_peripheral.rs index b2d1282b..5e1aae01 100644 --- a/examples/apps/src/ble_bas_peripheral.rs +++ b/examples/apps/src/ble_bas_peripheral.rs @@ -119,15 +119,30 @@ async fn gatt_events_task(server: &Server<'_>, conn: &Connection<'_>) -> Result< // the protocol details match data.process(server).await { // Server processing emits - Ok(Some(GattEvent::Read(event))) => { - if event.handle() == level.handle { - let value = server.get(&level); - info!("[gatt] Read Event to Level Characteristic: {:?}", value); + Ok(Some(event)) => { + match &event { + GattEvent::Read(event) => { + if event.handle() == level.handle { + let value = server.get(&level); + info!("[gatt] Read Event to Level Characteristic: {:?}", value); + } + } + GattEvent::Write(event) => { + if event.handle() == level.handle { + info!("[gatt] Write Event to Level Characteristic: {:?}", event.data()); + } + } } - } - Ok(Some(GattEvent::Write(event))) => { - if event.handle() == level.handle { - info!("[gatt] Write Event to Level Characteristic: {:?}", event.data()); + + // This step is also performed at drop(), but writing it explicitly is necessary + // in order to ensure reply is sent. + match event.accept() { + Ok(reply) => { + reply.send().await; + } + Err(e) => { + warn!("[gatt] error sending response: {:?}", e); + } } } Ok(_) => {} diff --git a/host/src/gatt.rs b/host/src/gatt.rs index b4d3e771..43daf6d1 100644 --- a/host/src/gatt.rs +++ b/host/src/gatt.rs @@ -103,6 +103,24 @@ pub enum GattEvent<'stack, 'server> { Write(WriteEvent<'stack, 'server>), } +impl<'stack, 'server> GattEvent<'stack, 'server> { + /// Accept the event, making it processed by the server. + pub fn accept(self) -> Result, Error> { + match self { + Self::Read(e) => e.accept(), + Self::Write(e) => e.accept(), + } + } + + /// Reject the event with the provided error code, it will not be processed by the attribute server. + pub fn reject(self, err: AttErrorCode) -> Result, Error> { + match self { + Self::Read(e) => e.reject(err), + Self::Write(e) => e.reject(err), + } + } +} + /// An event returned while processing GATT requests. pub struct ReadEvent<'stack, 'server> { value_handle: u16, @@ -290,7 +308,9 @@ impl<'stack> Reply<'stack> { impl Drop for Reply<'_> { fn drop(&mut self) { if let Some(pdu) = self.pdu.take() { - let _ = self.connection.try_send(pdu); + if self.connection.try_send(pdu).is_err() { + warn!("[gatt] error sending reply (outbound buffer full)"); + } } } }