From 88fbbca3e3f3a63f0e757f925fe94ecd4591b60d Mon Sep 17 00:00:00 2001 From: Ali Moallem Date: Wed, 31 Jan 2024 20:20:29 +0330 Subject: [PATCH 1/7] feat: add Characteristic Presentation Format Descriptor --- nrf-softdevice/src/ble/gatt_server/builder.rs | 5 ++- .../src/ble/gatt_server/characteristic.rs | 37 ++++++++++++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/nrf-softdevice/src/ble/gatt_server/builder.rs b/nrf-softdevice/src/ble/gatt_server/builder.rs index 2912cc5f..48e7c745 100644 --- a/nrf-softdevice/src/ble/gatt_server/builder.rs +++ b/nrf-softdevice/src/ble/gatt_server/builder.rs @@ -10,7 +10,7 @@ extern crate alloc; #[cfg(feature = "alloc")] use alloc::boxed::Box; -use super::characteristic::{self, AttributeMetadata}; +use super::characteristic::{self, AttributeMetadata, PresentationFormat}; use super::{CharacteristicHandles, DescriptorHandle, IncludedServiceHandle, RegisterError, ServiceHandle}; use crate::ble::Uuid; use crate::{raw, RawError, Softdevice}; @@ -83,6 +83,7 @@ impl<'a> ServiceBuilder<'a> { let user_desc_md = char_md .user_description .and_then(|x| x.metadata.map(AttributeMetadata::into_raw)); + let cpfd_md = char_md.cpfd.map(PresentationFormat::into_raw); let cccd_md = char_md.cccd.map(AttributeMetadata::into_raw); let sccd_md = char_md.sccd.map(AttributeMetadata::into_raw); @@ -92,7 +93,7 @@ impl<'a> ServiceBuilder<'a> { p_char_user_desc: char_md.user_description.map_or(null(), |x| x.value.as_ptr()), char_user_desc_max_size: char_md.user_description.map_or(0, |x| x.max_len), char_user_desc_size: char_md.user_description.map_or(0, |x| x.value.len() as u16), - p_char_pf: null(), + p_char_pf: cpfd_md.as_ref().map_or(null(), |x| x as _), p_user_desc_md: user_desc_md.as_ref().map_or(null(), |x| x as _), p_cccd_md: cccd_md.as_ref().map_or(null(), |x| x as _), p_sccd_md: sccd_md.as_ref().map_or(null(), |x| x as _), diff --git a/nrf-softdevice/src/ble/gatt_server/characteristic.rs b/nrf-softdevice/src/ble/gatt_server/characteristic.rs index 134a4d90..ad05f77d 100644 --- a/nrf-softdevice/src/ble/gatt_server/characteristic.rs +++ b/nrf-softdevice/src/ble/gatt_server/characteristic.rs @@ -218,17 +218,51 @@ impl Properties { } } +#[derive(Default, Debug, PartialEq, Eq, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct PresentationFormat { + pub format: u8, + pub exponent: i8, + pub unit: u16, + pub name_space: u8, + pub description: u16, +} + +impl PresentationFormat { + pub(crate) fn into_raw(self) -> raw::ble_gatts_char_pf_t { + self.into_raw_inner(raw::BLE_GATTS_VLOC_STACK as u8) + } + + #[cfg(feature = "alloc")] + pub(crate) fn into_raw_user(self) -> raw::ble_gatts_char_pf_t { + self.into_raw_inner(raw::BLE_GATTS_VLOC_USER as u8) + } + + fn into_raw_inner(self, vloc: u8) -> raw::ble_gatts_char_pf_t { + raw::ble_gatts_char_pf_t { + format: self.format.into(), + exponent: self.exponent.into(), + unit: self.unit.into(), + name_space: self.name_space.into(), + desc: self.description.into(), + } + } +} + #[derive(Default, Debug, PartialEq, Eq, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Metadata { pub properties: Properties, pub user_description: Option, + pub cpfd: Option, pub cccd: Option, pub sccd: Option, } impl Metadata { - pub fn new(properties: Properties) -> Self { + pub fn new(properties: Properties, pf: Option) -> Self { + let cpfd = pf; + let cccd = if properties.indicate || properties.notify { Some(AttributeMetadata::default()) } else { @@ -243,6 +277,7 @@ impl Metadata { Metadata { properties, + cpfd, cccd, sccd, ..Default::default() From e0844fd70cd88425cf502b3a80eac9e650034a32 Mon Sep 17 00:00:00 2001 From: Ali Moallem Date: Wed, 31 Jan 2024 20:42:48 +0330 Subject: [PATCH 2/7] test: update examples according to CPFD --- examples/src/bin/ble_bond_peripheral.rs | 2 +- .../src/bin/ble_dis_bas_peripheral_builder.rs | 17 +++++++++++++---- nrf-softdevice-macro/src/lib.rs | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/examples/src/bin/ble_bond_peripheral.rs b/examples/src/bin/ble_bond_peripheral.rs index c12cb694..ee3cfe9e 100644 --- a/examples/src/bin/ble_bond_peripheral.rs +++ b/examples/src/bin/ble_bond_peripheral.rs @@ -125,7 +125,7 @@ impl BatteryService { let mut service_builder = ServiceBuilder::new(sd, BATTERY_SERVICE)?; let attr = Attribute::new(&[0u8]).security(SecurityMode::JustWorks); - let metadata = Metadata::new(Properties::new().read().notify()); + let metadata = Metadata::new(Properties::new().read().notify(), None); let characteristic_builder = service_builder.add_characteristic(BATTERY_LEVEL, attr, metadata)?; let characteristic_handles = characteristic_builder.build(); diff --git a/examples/src/bin/ble_dis_bas_peripheral_builder.rs b/examples/src/bin/ble_dis_bas_peripheral_builder.rs index 5717b6db..555c8cd2 100644 --- a/examples/src/bin/ble_dis_bas_peripheral_builder.rs +++ b/examples/src/bin/ble_dis_bas_peripheral_builder.rs @@ -12,7 +12,7 @@ use nrf_softdevice::ble::advertisement_builder::{ Flag, LegacyAdvertisementBuilder, LegacyAdvertisementPayload, ServiceList, ServiceUuid16, }; use nrf_softdevice::ble::gatt_server::builder::ServiceBuilder; -use nrf_softdevice::ble::gatt_server::characteristic::{Attribute, Metadata, Properties}; +use nrf_softdevice::ble::gatt_server::characteristic::{Attribute, Metadata, PresentationFormat, Properties}; use nrf_softdevice::ble::gatt_server::{CharacteristicHandles, RegisterError, WriteOp}; use nrf_softdevice::ble::{gatt_server, peripheral, Connection, Uuid}; use nrf_softdevice::{raw, Softdevice}; @@ -86,7 +86,7 @@ impl DeviceInformationService { ) -> Result, RegisterError> { if let Some(val) = val { let attr = Attribute::new(val); - let md = Metadata::new(Properties::new().read()); + let md = Metadata::new(Properties::new().read(), None); Ok(Some(sb.add_characteristic(uuid, attr, md)?.build())) } else { Ok(None) @@ -99,7 +99,7 @@ impl DeviceInformationService { unsafe { core::slice::from_raw_parts(pnp_id as *const _ as *const u8, core::mem::size_of::()) }; let attr = Attribute::new(val); - let md = Metadata::new(Properties::new().read()); + let md = Metadata::new(Properties::new().read(), None); Ok(sb.add_characteristic(PNP_ID, attr, md)?.build()) } } @@ -114,7 +114,16 @@ impl BatteryService { let mut service_builder = ServiceBuilder::new(sd, BATTERY_SERVICE)?; let attr = Attribute::new(&[0u8]); - let metadata = Metadata::new(Properties::new().read().notify()); + let metadata = Metadata::new( + Properties::new().read().notify(), + Some(PresentationFormat { + format: raw::BLE_GATT_CPF_FORMAT_UINT8 as u8, + exponent: 0, /* Value * 10 ^ 0 */ + unit: 0x27AD, /* Percentage */ + name_space: raw::BLE_GATT_CPF_NAMESPACE_BTSIG as u8, + description: raw::BLE_GATT_CPF_NAMESPACE_DESCRIPTION_UNKNOWN as u16, + }), + ); let characteristic_builder = service_builder.add_characteristic(BATTERY_LEVEL, attr, metadata)?; let characteristic_handles = characteristic_builder.build(); diff --git a/nrf-softdevice-macro/src/lib.rs b/nrf-softdevice-macro/src/lib.rs index 717d119a..4a429138 100644 --- a/nrf-softdevice-macro/src/lib.rs +++ b/nrf-softdevice-macro/src/lib.rs @@ -268,7 +268,7 @@ pub fn gatt_service(args: TokenStream, item: TokenStream) -> TokenStream { indicate: #indicate, ..Default::default() }; - let metadata = #ble::gatt_server::characteristic::Metadata::new(props); + let metadata = #ble::gatt_server::characteristic::Metadata::new(props, None); service_builder.add_characteristic(#uuid, attr, metadata)?.build() }; )); From abccf88c887718624f13d59694735a65ac391d07 Mon Sep 17 00:00:00 2001 From: Ali Moallem Date: Wed, 31 Jan 2024 20:48:31 +0330 Subject: [PATCH 3/7] fix: remove PresentationFormat impl warnings --- nrf-softdevice/src/ble/gatt_server/characteristic.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/nrf-softdevice/src/ble/gatt_server/characteristic.rs b/nrf-softdevice/src/ble/gatt_server/characteristic.rs index ad05f77d..5ec255ca 100644 --- a/nrf-softdevice/src/ble/gatt_server/characteristic.rs +++ b/nrf-softdevice/src/ble/gatt_server/characteristic.rs @@ -230,15 +230,6 @@ pub struct PresentationFormat { impl PresentationFormat { pub(crate) fn into_raw(self) -> raw::ble_gatts_char_pf_t { - self.into_raw_inner(raw::BLE_GATTS_VLOC_STACK as u8) - } - - #[cfg(feature = "alloc")] - pub(crate) fn into_raw_user(self) -> raw::ble_gatts_char_pf_t { - self.into_raw_inner(raw::BLE_GATTS_VLOC_USER as u8) - } - - fn into_raw_inner(self, vloc: u8) -> raw::ble_gatts_char_pf_t { raw::ble_gatts_char_pf_t { format: self.format.into(), exponent: self.exponent.into(), From 34f453c4aeb2def597ed23b7e484d760b966c66c Mon Sep 17 00:00:00 2001 From: Ali Moallem Date: Thu, 1 Feb 2024 19:53:54 +0330 Subject: [PATCH 4/7] refactor: change the presentation and security using style --- nrf-softdevice/src/ble/gatt_server/builder.rs | 4 +- .../src/ble/gatt_server/characteristic.rs | 48 ++++++++++--------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/nrf-softdevice/src/ble/gatt_server/builder.rs b/nrf-softdevice/src/ble/gatt_server/builder.rs index 48e7c745..14e7e91f 100644 --- a/nrf-softdevice/src/ble/gatt_server/builder.rs +++ b/nrf-softdevice/src/ble/gatt_server/builder.rs @@ -10,7 +10,7 @@ extern crate alloc; #[cfg(feature = "alloc")] use alloc::boxed::Box; -use super::characteristic::{self, AttributeMetadata, PresentationFormat}; +use super::characteristic::{self, AttributeMetadata, Presentation}; use super::{CharacteristicHandles, DescriptorHandle, IncludedServiceHandle, RegisterError, ServiceHandle}; use crate::ble::Uuid; use crate::{raw, RawError, Softdevice}; @@ -83,7 +83,7 @@ impl<'a> ServiceBuilder<'a> { let user_desc_md = char_md .user_description .and_then(|x| x.metadata.map(AttributeMetadata::into_raw)); - let cpfd_md = char_md.cpfd.map(PresentationFormat::into_raw); + let cpfd_md = char_md.cpfd.map(Presentation::into_raw); let cccd_md = char_md.cccd.map(AttributeMetadata::into_raw); let sccd_md = char_md.sccd.map(AttributeMetadata::into_raw); diff --git a/nrf-softdevice/src/ble/gatt_server/characteristic.rs b/nrf-softdevice/src/ble/gatt_server/characteristic.rs index 5ec255ca..16c88ac7 100644 --- a/nrf-softdevice/src/ble/gatt_server/characteristic.rs +++ b/nrf-softdevice/src/ble/gatt_server/characteristic.rs @@ -220,7 +220,7 @@ impl Properties { #[derive(Default, Debug, PartialEq, Eq, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct PresentationFormat { +pub struct Presentation { pub format: u8, pub exponent: i8, pub unit: u16, @@ -228,8 +228,17 @@ pub struct PresentationFormat { pub description: u16, } -impl PresentationFormat { +impl Presentation { pub(crate) fn into_raw(self) -> raw::ble_gatts_char_pf_t { + self.into_raw_inner(raw::BLE_GATTS_VLOC_STACK as u8) + } + + #[cfg(feature = "alloc")] + pub(crate) fn into_raw_user(self) -> raw::ble_gatts_char_pf_t { + self.into_raw_inner(raw::BLE_GATTS_VLOC_USER as u8) + } + + fn into_raw_inner(self, vloc: u8) -> raw::ble_gatts_char_pf_t { raw::ble_gatts_char_pf_t { format: self.format.into(), exponent: self.exponent.into(), @@ -245,15 +254,13 @@ impl PresentationFormat { pub struct Metadata { pub properties: Properties, pub user_description: Option, - pub cpfd: Option, + pub cpfd: Option, pub cccd: Option, pub sccd: Option, } impl Metadata { - pub fn new(properties: Properties, pf: Option) -> Self { - let cpfd = pf; - + pub fn new(properties: Properties) -> Self { let cccd = if properties.indicate || properties.notify { Some(AttributeMetadata::default()) } else { @@ -268,31 +275,28 @@ impl Metadata { Metadata { properties, - cpfd, cccd, sccd, ..Default::default() } } - pub fn with_security(properties: Properties, write_security: SecurityMode) -> Self { - let cccd = if properties.indicate || properties.notify { - Some(AttributeMetadata::default().write_security(write_security)) - } else { - None + pub fn presentation(self, presentation: Presentation) -> Self { + let cpfd = Some(presentation); + Metadata { cpfd, ..self } + } + + pub fn security(self, security: SecurityMode) -> Self { + let cccd = match self.cccd { + Some(cccd) => Some(cccd.write_security(security)), + None => None, }; - let sccd = if properties.broadcast { - Some(AttributeMetadata::default().write_security(write_security)) - } else { - None + let sccd = match self.sccd { + Some(sccd) => Some(sccd.write_security(security)), + None => None, }; - Metadata { - properties, - cccd, - sccd, - ..Default::default() - } + Metadata { cccd, sccd, ..self } } } From 7ade17d7509349a17926f4f81a119018699e378b Mon Sep 17 00:00:00 2001 From: Ali Moallem Date: Thu, 1 Feb 2024 20:03:05 +0330 Subject: [PATCH 5/7] test: change the examples according to new style using code --- examples/src/bin/ble_bond_peripheral.rs | 2 +- .../src/bin/ble_dis_bas_peripheral_builder.rs | 23 ++++++++----------- nrf-softdevice-macro/src/lib.rs | 2 +- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/examples/src/bin/ble_bond_peripheral.rs b/examples/src/bin/ble_bond_peripheral.rs index ee3cfe9e..c12cb694 100644 --- a/examples/src/bin/ble_bond_peripheral.rs +++ b/examples/src/bin/ble_bond_peripheral.rs @@ -125,7 +125,7 @@ impl BatteryService { let mut service_builder = ServiceBuilder::new(sd, BATTERY_SERVICE)?; let attr = Attribute::new(&[0u8]).security(SecurityMode::JustWorks); - let metadata = Metadata::new(Properties::new().read().notify(), None); + let metadata = Metadata::new(Properties::new().read().notify()); let characteristic_builder = service_builder.add_characteristic(BATTERY_LEVEL, attr, metadata)?; let characteristic_handles = characteristic_builder.build(); diff --git a/examples/src/bin/ble_dis_bas_peripheral_builder.rs b/examples/src/bin/ble_dis_bas_peripheral_builder.rs index 555c8cd2..252098fe 100644 --- a/examples/src/bin/ble_dis_bas_peripheral_builder.rs +++ b/examples/src/bin/ble_dis_bas_peripheral_builder.rs @@ -12,7 +12,7 @@ use nrf_softdevice::ble::advertisement_builder::{ Flag, LegacyAdvertisementBuilder, LegacyAdvertisementPayload, ServiceList, ServiceUuid16, }; use nrf_softdevice::ble::gatt_server::builder::ServiceBuilder; -use nrf_softdevice::ble::gatt_server::characteristic::{Attribute, Metadata, PresentationFormat, Properties}; +use nrf_softdevice::ble::gatt_server::characteristic::{Attribute, Metadata, Presentation, Properties}; use nrf_softdevice::ble::gatt_server::{CharacteristicHandles, RegisterError, WriteOp}; use nrf_softdevice::ble::{gatt_server, peripheral, Connection, Uuid}; use nrf_softdevice::{raw, Softdevice}; @@ -86,7 +86,7 @@ impl DeviceInformationService { ) -> Result, RegisterError> { if let Some(val) = val { let attr = Attribute::new(val); - let md = Metadata::new(Properties::new().read(), None); + let md = Metadata::new(Properties::new().read()); Ok(Some(sb.add_characteristic(uuid, attr, md)?.build())) } else { Ok(None) @@ -99,7 +99,7 @@ impl DeviceInformationService { unsafe { core::slice::from_raw_parts(pnp_id as *const _ as *const u8, core::mem::size_of::()) }; let attr = Attribute::new(val); - let md = Metadata::new(Properties::new().read(), None); + let md = Metadata::new(Properties::new().read()); Ok(sb.add_characteristic(PNP_ID, attr, md)?.build()) } } @@ -114,16 +114,13 @@ impl BatteryService { let mut service_builder = ServiceBuilder::new(sd, BATTERY_SERVICE)?; let attr = Attribute::new(&[0u8]); - let metadata = Metadata::new( - Properties::new().read().notify(), - Some(PresentationFormat { - format: raw::BLE_GATT_CPF_FORMAT_UINT8 as u8, - exponent: 0, /* Value * 10 ^ 0 */ - unit: 0x27AD, /* Percentage */ - name_space: raw::BLE_GATT_CPF_NAMESPACE_BTSIG as u8, - description: raw::BLE_GATT_CPF_NAMESPACE_DESCRIPTION_UNKNOWN as u16, - }), - ); + let metadata = Metadata::new(Properties::new().read().notify()).presentation(PresentationFormat { + format: raw::BLE_GATT_CPF_FORMAT_UINT8 as u8, + exponent: 0, /* Value * 10 ^ 0 */ + unit: 0x27AD, /* Percentage */ + name_space: raw::BLE_GATT_CPF_NAMESPACE_BTSIG as u8, + description: raw::BLE_GATT_CPF_NAMESPACE_DESCRIPTION_UNKNOWN as u16, + }); let characteristic_builder = service_builder.add_characteristic(BATTERY_LEVEL, attr, metadata)?; let characteristic_handles = characteristic_builder.build(); diff --git a/nrf-softdevice-macro/src/lib.rs b/nrf-softdevice-macro/src/lib.rs index 4a429138..717d119a 100644 --- a/nrf-softdevice-macro/src/lib.rs +++ b/nrf-softdevice-macro/src/lib.rs @@ -268,7 +268,7 @@ pub fn gatt_service(args: TokenStream, item: TokenStream) -> TokenStream { indicate: #indicate, ..Default::default() }; - let metadata = #ble::gatt_server::characteristic::Metadata::new(props, None); + let metadata = #ble::gatt_server::characteristic::Metadata::new(props); service_builder.add_characteristic(#uuid, attr, metadata)?.build() }; )); From 4bb0b62b6769b4ae894ce1b431656b7b040f1158 Mon Sep 17 00:00:00 2001 From: Ali Moallem Date: Thu, 1 Feb 2024 20:05:26 +0330 Subject: [PATCH 6/7] test: fix bug in example due to using old style --- examples/src/bin/ble_dis_bas_peripheral_builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/bin/ble_dis_bas_peripheral_builder.rs b/examples/src/bin/ble_dis_bas_peripheral_builder.rs index 252098fe..79a314c1 100644 --- a/examples/src/bin/ble_dis_bas_peripheral_builder.rs +++ b/examples/src/bin/ble_dis_bas_peripheral_builder.rs @@ -114,7 +114,7 @@ impl BatteryService { let mut service_builder = ServiceBuilder::new(sd, BATTERY_SERVICE)?; let attr = Attribute::new(&[0u8]); - let metadata = Metadata::new(Properties::new().read().notify()).presentation(PresentationFormat { + let metadata = Metadata::new(Properties::new().read().notify()).presentation(Presentation { format: raw::BLE_GATT_CPF_FORMAT_UINT8 as u8, exponent: 0, /* Value * 10 ^ 0 */ unit: 0x27AD, /* Percentage */ From 971c360d0a1c5b492eac5a88db9ff1c61d668b1c Mon Sep 17 00:00:00 2001 From: Ali Moallem Date: Thu, 1 Feb 2024 20:09:37 +0330 Subject: [PATCH 7/7] refactor: remove extra functions for Presentation structure --- nrf-softdevice/src/ble/gatt_server/characteristic.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/nrf-softdevice/src/ble/gatt_server/characteristic.rs b/nrf-softdevice/src/ble/gatt_server/characteristic.rs index 16c88ac7..39d41b78 100644 --- a/nrf-softdevice/src/ble/gatt_server/characteristic.rs +++ b/nrf-softdevice/src/ble/gatt_server/characteristic.rs @@ -230,15 +230,6 @@ pub struct Presentation { impl Presentation { pub(crate) fn into_raw(self) -> raw::ble_gatts_char_pf_t { - self.into_raw_inner(raw::BLE_GATTS_VLOC_STACK as u8) - } - - #[cfg(feature = "alloc")] - pub(crate) fn into_raw_user(self) -> raw::ble_gatts_char_pf_t { - self.into_raw_inner(raw::BLE_GATTS_VLOC_USER as u8) - } - - fn into_raw_inner(self, vloc: u8) -> raw::ble_gatts_char_pf_t { raw::ble_gatts_char_pf_t { format: self.format.into(), exponent: self.exponent.into(),