From 3b869f8e25ace92d4444a4ae3351c9cb10691060 Mon Sep 17 00:00:00 2001 From: Albert Skog Date: Thu, 30 Sep 2021 15:07:45 +0200 Subject: add support for indications --- nrf-softdevice-macro/src/lib.rs | 30 +++++++++++++++++++++++++++++ nrf-softdevice/src/ble/gatt_server.rs | 36 +++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/nrf-softdevice-macro/src/lib.rs b/nrf-softdevice-macro/src/lib.rs index d2e4789..fad3e93 100644 --- a/nrf-softdevice-macro/src/lib.rs +++ b/nrf-softdevice-macro/src/lib.rs @@ -122,6 +122,7 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { let get_fn = format_ident!("{}_get", ch.name); let set_fn = format_ident!("{}_set", ch.name); let notify_fn = format_ident!("{}_notify", ch.name); + let indicate_fn = format_ident!("{}_indicate", ch.name); let uuid = ch.args.uuid; let read = ch.args.read; @@ -212,6 +213,35 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { } )); + code_event_enum.extend(quote_spanned!(ch.span=> + #case_enabled, + #case_disabled, + )); + code_on_write.extend(quote_spanned!(ch.span=> + if handle == self.#cccd_handle { + if data.len() != 0 && data[0] & 0x01 != 0 { + return Some(#event_enum_name::#case_enabled); + } else { + return Some(#event_enum_name::#case_disabled); + } + } + )); + } + if indicate { + let case_enabled = format_ident!("{}IndicationsEnabled", name_pascal); + let case_disabled = format_ident!("{}IndicationsDisabled", name_pascal); + + code_impl.extend(quote_spanned!(ch.span=> + fn #indicate_fn( + &self, + conn: &#ble::Connection, + val: #ty, + ) -> Result<(), #ble::gatt_server::IndicateValueError> { + let buf = #ty_as_val::to_gatt(&val); + #ble::gatt_server::indicate_value(conn, self.#value_handle, buf) + } + )); + code_event_enum.extend(quote_spanned!(ch.span=> #case_enabled, #case_disabled, diff --git a/nrf-softdevice/src/ble/gatt_server.rs b/nrf-softdevice/src/ble/gatt_server.rs index 58663cc..d6d7f13 100644 --- a/nrf-softdevice/src/ble/gatt_server.rs +++ b/nrf-softdevice/src/ble/gatt_server.rs @@ -266,6 +266,42 @@ pub fn notify_value(conn: &Connection, handle: u16, val: &[u8]) -> Result<(), No Ok(()) } +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum IndicateValueError { + Disconnected, + Raw(RawError), +} + +impl From for IndicateValueError { + fn from(err: RawError) -> Self { + Self::Raw(err) + } +} + +impl From for IndicateValueError { + fn from(_: DisconnectedError) -> Self { + Self::Disconnected + } +} + +pub fn indicate_value(conn: &Connection, handle: u16, val: &[u8]) -> Result<(), IndicateValueError> { + let conn_handle = conn.with_state(|state| state.check_connected())?; + + let mut len: u16 = val.len() as _; + let params = raw::ble_gatts_hvx_params_t { + handle, + type_: raw::BLE_GATT_HVX_INDICATION as u8, + offset: 0, + p_data: val.as_ptr() as _, + p_len: &mut len, + }; + let ret = unsafe { raw::sd_ble_gatts_hvx(conn_handle, ¶ms) }; + RawError::convert(ret)?; + + Ok(()) +} + pub(crate) unsafe fn on_evt(ble_evt: *const raw::ble_evt_t) { let gatts_evt = get_union_field(ble_evt, &(*ble_evt).evt.gatts_evt); match (*ble_evt).header.evt_id as u32 { -- cgit v1.2.3 From 72157ab77cc7f89664c7be73800231b878beee90 Mon Sep 17 00:00:00 2001 From: Albert Skog Date: Thu, 30 Sep 2021 15:32:13 +0200 Subject: fix formatting --- nrf-softdevice/src/ble/gatt_server.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/nrf-softdevice/src/ble/gatt_server.rs b/nrf-softdevice/src/ble/gatt_server.rs index d6d7f13..325752c 100644 --- a/nrf-softdevice/src/ble/gatt_server.rs +++ b/nrf-softdevice/src/ble/gatt_server.rs @@ -285,7 +285,11 @@ impl From for IndicateValueError { } } -pub fn indicate_value(conn: &Connection, handle: u16, val: &[u8]) -> Result<(), IndicateValueError> { +pub fn indicate_value( + conn: &Connection, + handle: u16, + val: &[u8], +) -> Result<(), IndicateValueError> { let conn_handle = conn.with_state(|state| state.check_connected())?; let mut len: u16 = val.len() as _; -- cgit v1.2.3 From e7b1b20c514ac99773b57a9a2a2b5d16285c4dc3 Mon Sep 17 00:00:00 2001 From: Albert Skog Date: Fri, 1 Oct 2021 13:02:49 +0200 Subject: check correct bit for enable indications --- nrf-softdevice-macro/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nrf-softdevice-macro/src/lib.rs b/nrf-softdevice-macro/src/lib.rs index fad3e93..2ffff5f 100644 --- a/nrf-softdevice-macro/src/lib.rs +++ b/nrf-softdevice-macro/src/lib.rs @@ -248,7 +248,7 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { )); code_on_write.extend(quote_spanned!(ch.span=> if handle == self.#cccd_handle { - if data.len() != 0 && data[0] & 0x01 != 0 { + if data.len() != 0 && data[0] & 0x02 != 0 { return Some(#event_enum_name::#case_enabled); } else { return Some(#event_enum_name::#case_disabled); -- cgit v1.2.3 From 2921750bd85d1890ae294fc67f80ff436eb88e8e Mon Sep 17 00:00:00 2001 From: Albert Skog Date: Fri, 8 Oct 2021 21:17:50 +0200 Subject: fix for charsacteristics with both notify and indicate --- nrf-softdevice-macro/src/lib.rs | 85 +++++++++++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 25 deletions(-) diff --git a/nrf-softdevice-macro/src/lib.rs b/nrf-softdevice-macro/src/lib.rs index 2ffff5f..2f4b766 100644 --- a/nrf-softdevice-macro/src/lib.rs +++ b/nrf-softdevice-macro/src/lib.rs @@ -198,10 +198,8 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { } )); } - if notify { - let case_enabled = format_ident!("{}NotificationsEnabled", name_pascal); - let case_disabled = format_ident!("{}NotificationsDisabled", name_pascal); + if notify { code_impl.extend(quote_spanned!(ch.span=> fn #notify_fn( &self, @@ -213,24 +211,27 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { } )); - code_event_enum.extend(quote_spanned!(ch.span=> - #case_enabled, - #case_disabled, - )); - code_on_write.extend(quote_spanned!(ch.span=> - if handle == self.#cccd_handle { - if data.len() != 0 && data[0] & 0x01 != 0 { - return Some(#event_enum_name::#case_enabled); - } else { - return Some(#event_enum_name::#case_disabled); + if !indicate { + let case_enabled = format_ident!("{}NotificationsEnabled", name_pascal); + let case_disabled = format_ident!("{}NotificationsDisabled", name_pascal); + + code_event_enum.extend(quote_spanned!(ch.span=> + #case_enabled, + #case_disabled, + )); + code_on_write.extend(quote_spanned!(ch.span=> + if handle == self.#cccd_handle { + if data.len() != 0 && data[0] & 0x01 != 0 { + return Some(#event_enum_name::#case_enabled); + } else { + return Some(#event_enum_name::#case_disabled); + } } - } - )); + )); + } } - if indicate { - let case_enabled = format_ident!("{}IndicationsEnabled", name_pascal); - let case_disabled = format_ident!("{}IndicationsDisabled", name_pascal); + if indicate { code_impl.extend(quote_spanned!(ch.span=> fn #indicate_fn( &self, @@ -242,16 +243,50 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { } )); + if !notify { + let case_enabled = format_ident!("{}IndicationsEnabled", name_pascal); + let case_disabled = format_ident!("{}IndicationsDisabled", name_pascal); + + code_event_enum.extend(quote_spanned!(ch.span=> + #case_enabled, + #case_disabled, + )); + code_on_write.extend(quote_spanned!(ch.span=> + if handle == self.#cccd_handle { + if data.len() != 0 && data[0] & 0x02 != 0 { + return Some(#event_enum_name::#case_enabled); + } else { + return Some(#event_enum_name::#case_disabled); + } + } + )); + } + } + + if indicate && notify { + let case_disabled_disabled = + format_ident!("{}IndicationsDisabledNotificationsDisabled", name_pascal); + let case_disabled_enabled = + format_ident!("{}IndicationsDisabledNotificationsEnabled", name_pascal); + let case_enabled_disabled = + format_ident!("{}IndicationsEnabledNotificationsDisabled", name_pascal); + let case_enabled_enabled = + format_ident!("{}IndicationsEnabledNotificationsEnabled", name_pascal); + code_event_enum.extend(quote_spanned!(ch.span=> - #case_enabled, - #case_disabled, + #case_disabled_disabled, + #case_disabled_enabled, + #case_enabled_disabled, + #case_enabled_enabled, )); code_on_write.extend(quote_spanned!(ch.span=> - if handle == self.#cccd_handle { - if data.len() != 0 && data[0] & 0x02 != 0 { - return Some(#event_enum_name::#case_enabled); - } else { - return Some(#event_enum_name::#case_disabled); + if handle == self.#cccd_handle && data.len() != 0 { + match data[0] & 0x03 { + 0x00 => return Some(#event_enum_name::#case_disabled_disabled), + 0x01 => return Some(#event_enum_name::#case_disabled_enabled), + 0x02 => return Some(#event_enum_name::#case_enabled_disabled), + 0x03 => return Some(#event_enum_name::#case_enabled_enabled), + _ => {}, } } )); -- cgit v1.2.3 From ae537dcbf67dc2366574c583740b2c7823c733d1 Mon Sep 17 00:00:00 2001 From: Albert Skog Date: Fri, 15 Oct 2021 10:12:17 +0200 Subject: add comments --- nrf-softdevice/src/ble/gatt_server.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nrf-softdevice/src/ble/gatt_server.rs b/nrf-softdevice/src/ble/gatt_server.rs index 325752c..63c65a6 100644 --- a/nrf-softdevice/src/ble/gatt_server.rs +++ b/nrf-softdevice/src/ble/gatt_server.rs @@ -249,6 +249,7 @@ impl From for NotifyValueError { } } +/// Multiple notifications can be queued. Will fail when the queue is full. pub fn notify_value(conn: &Connection, handle: u16, val: &[u8]) -> Result<(), NotifyValueError> { let conn_handle = conn.with_state(|state| state.check_connected())?; @@ -285,6 +286,7 @@ impl From for IndicateValueError { } } +/// This will fail if an indication is already in progress pub fn indicate_value( conn: &Connection, handle: u16, -- cgit v1.2.3 From fd48489c0ffc58c8ae02d32d9904162a2777df3c Mon Sep 17 00:00:00 2001 From: Albert Skog Date: Fri, 15 Oct 2021 11:24:36 +0200 Subject: make CCCD write a single event --- examples/src/bin/ble_bas_peripheral.rs | 24 +++++++++----- examples/src/bin/ble_peripheral_onoff.rs | 5 +-- nrf-softdevice-macro/src/lib.rs | 54 ++++++++++++-------------------- 3 files changed, 40 insertions(+), 43 deletions(-) diff --git a/examples/src/bin/ble_bas_peripheral.rs b/examples/src/bin/ble_bas_peripheral.rs index 8793c82..8d76ec3 100644 --- a/examples/src/bin/ble_bas_peripheral.rs +++ b/examples/src/bin/ble_bas_peripheral.rs @@ -28,7 +28,13 @@ async fn softdevice_task(sd: &'static Softdevice) { struct BatteryService { #[characteristic(uuid = "2a19", read, write, notify)] battery_level: u8, - #[characteristic(uuid = "3a4a1f7e-22d8-11eb-a3aa-1b3b1d4e4a0d", read, write, notify)] + #[characteristic( + uuid = "3a4a1f7e-22d8-11eb-a3aa-1b3b1d4e4a0d", + read, + write, + notify, + indicate + )] foo: u16, } @@ -70,14 +76,18 @@ async fn bluetooth_task(sd: &'static Softdevice) { info!("send notification error: {:?}", e); } } - BatteryServiceEvent::BatteryLevelNotificationsEnabled => { - info!("battery notifications enabled") + BatteryServiceEvent::BatteryLevelCccdWrite { notifications } => { + info!("battery notifications: {}", notifications) } - BatteryServiceEvent::BatteryLevelNotificationsDisabled => { - info!("battery notifications disabled") + BatteryServiceEvent::FooCccdWrite { + indications, + notifications, + } => { + info!( + "foo indications: {}, notifications: {}", + indications, notifications + ) } - BatteryServiceEvent::FooNotificationsEnabled => info!("foo notifications enabled"), - BatteryServiceEvent::FooNotificationsDisabled => info!("foo notifications disabled"), }) .await; diff --git a/examples/src/bin/ble_peripheral_onoff.rs b/examples/src/bin/ble_peripheral_onoff.rs index e3f3943..47b9dfd 100644 --- a/examples/src/bin/ble_peripheral_onoff.rs +++ b/examples/src/bin/ble_peripheral_onoff.rs @@ -63,8 +63,9 @@ async fn run_bluetooth(sd: &'static Softdevice, server: &FooService) { info!("send notification error: {:?}", e); } } - FooServiceEvent::FooNotificationsEnabled => info!("notifications enabled"), - FooServiceEvent::FooNotificationsDisabled => info!("notifications disabled"), + FooServiceEvent::FooCccdWrite { notifications } => { + info!("foo notifications: {}", notifications) + } }) .await; diff --git a/nrf-softdevice-macro/src/lib.rs b/nrf-softdevice-macro/src/lib.rs index 2f4b766..e1cec67 100644 --- a/nrf-softdevice-macro/src/lib.rs +++ b/nrf-softdevice-macro/src/lib.rs @@ -212,19 +212,17 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { )); if !indicate { - let case_enabled = format_ident!("{}NotificationsEnabled", name_pascal); - let case_disabled = format_ident!("{}NotificationsDisabled", name_pascal); + let case_cccd_write = format_ident!("{}CccdWrite", name_pascal); code_event_enum.extend(quote_spanned!(ch.span=> - #case_enabled, - #case_disabled, + #case_cccd_write{notifications: bool}, )); code_on_write.extend(quote_spanned!(ch.span=> - if handle == self.#cccd_handle { - if data.len() != 0 && data[0] & 0x01 != 0 { - return Some(#event_enum_name::#case_enabled); - } else { - return Some(#event_enum_name::#case_disabled); + if handle == self.#cccd_handle && data.len() != 0 { + match data[0] & 0x01 { + 0x00 => return Some(#event_enum_name::#case_cccd_write{notifications: false}), + 0x01 => return Some(#event_enum_name::#case_cccd_write{notifications: true}), + _ => {}, } } )); @@ -244,19 +242,17 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { )); if !notify { - let case_enabled = format_ident!("{}IndicationsEnabled", name_pascal); - let case_disabled = format_ident!("{}IndicationsDisabled", name_pascal); + let case_cccd_write = format_ident!("{}CccdWrite", name_pascal); code_event_enum.extend(quote_spanned!(ch.span=> - #case_enabled, - #case_disabled, + #case_cccd_write{indications: bool}, )); code_on_write.extend(quote_spanned!(ch.span=> - if handle == self.#cccd_handle { - if data.len() != 0 && data[0] & 0x02 != 0 { - return Some(#event_enum_name::#case_enabled); - } else { - return Some(#event_enum_name::#case_disabled); + if handle == self.#cccd_handle && data.len() != 0 { + match data[0] & 0x02 { + 0x00 => return Some(#event_enum_name::#case_cccd_write{indications: false}), + 0x02 => return Some(#event_enum_name::#case_cccd_write{indications: true}), + _ => {}, } } )); @@ -264,28 +260,18 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { } if indicate && notify { - let case_disabled_disabled = - format_ident!("{}IndicationsDisabledNotificationsDisabled", name_pascal); - let case_disabled_enabled = - format_ident!("{}IndicationsDisabledNotificationsEnabled", name_pascal); - let case_enabled_disabled = - format_ident!("{}IndicationsEnabledNotificationsDisabled", name_pascal); - let case_enabled_enabled = - format_ident!("{}IndicationsEnabledNotificationsEnabled", name_pascal); + let case_cccd_write = format_ident!("{}CccdWrite", name_pascal); code_event_enum.extend(quote_spanned!(ch.span=> - #case_disabled_disabled, - #case_disabled_enabled, - #case_enabled_disabled, - #case_enabled_enabled, + #case_cccd_write{indications: bool, notifications: bool}, )); code_on_write.extend(quote_spanned!(ch.span=> if handle == self.#cccd_handle && data.len() != 0 { match data[0] & 0x03 { - 0x00 => return Some(#event_enum_name::#case_disabled_disabled), - 0x01 => return Some(#event_enum_name::#case_disabled_enabled), - 0x02 => return Some(#event_enum_name::#case_enabled_disabled), - 0x03 => return Some(#event_enum_name::#case_enabled_enabled), + 0x00 => return Some(#event_enum_name::#case_cccd_write{indications: false, notifications: false}), + 0x01 => return Some(#event_enum_name::#case_cccd_write{indications: false, notifications: true}), + 0x02 => return Some(#event_enum_name::#case_cccd_write{indications: true, notifications: false}), + 0x03 => return Some(#event_enum_name::#case_cccd_write{indications: true, notifications: true}), _ => {}, } } -- cgit v1.2.3