From f291131f082a37a4a36eca84e5322b9ea1718749 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 5 Oct 2021 13:25:06 +0200 Subject: Refactor GATT handling to support multiple services * Make run() return all GATT events and leave the responsibility of calling the service handler to the application * Generate code for each service that converts from the generic event into the type-specific event. --- nrf-softdevice-macro/src/lib.rs | 33 ++++++++++++++++++++++----------- nrf-softdevice/src/ble/gatt_server.rs | 19 +++++++++++++++---- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/nrf-softdevice-macro/src/lib.rs b/nrf-softdevice-macro/src/lib.rs index d2e4789..c232aac 100644 --- a/nrf-softdevice-macro/src/lib.rs +++ b/nrf-softdevice-macro/src/lib.rs @@ -109,11 +109,20 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { let mut code_impl = TokenStream2::new(); let mut code_register_chars = TokenStream2::new(); let mut code_register_init = TokenStream2::new(); - let mut code_on_write = TokenStream2::new(); + let mut code_on_event = TokenStream2::new(); let mut code_event_enum = TokenStream2::new(); let ble = quote!(::nrf_softdevice::ble); + let service_handle = format_ident!("service_handle"); + fields.push(syn::Field { + ident: Some(service_handle), + ty: syn::Type::Verbatim(quote!(u16).into()), + attrs: Vec::new(), + colon_token: Default::default(), + vis: syn::Visibility::Inherited, + }); + for ch in &chars { let name_pascal = inflector::cases::pascalcase::to_pascal_case(&ch.name); let char_name = format_ident!("{}", ch.name); @@ -191,9 +200,9 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { code_event_enum.extend(quote_spanned!(ch.span=> #case_write(#ty), )); - code_on_write.extend(quote_spanned!(ch.span=> - if handle == self.#value_handle { - return Some(#event_enum_name::#case_write(#ty_as_val::from_gatt(&data))); + code_on_event.extend(quote_spanned!(ch.span=> + if event.handle == self.#value_handle { + handler(#event_enum_name::#case_write(#ty_as_val::from_gatt(event.data))); } )); } @@ -216,12 +225,13 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { #case_enabled, #case_disabled, )); - code_on_write.extend(quote_spanned!(ch.span=> - if handle == self.#cccd_handle { + code_on_event.extend(quote_spanned!(ch.span=> + if event.handle == self.#cccd_handle { + let data = event.data; if data.len() != 0 && data[0] & 0x01 != 0 { - return Some(#event_enum_name::#case_enabled); + handler(#event_enum_name::#case_enabled); } else { - return Some(#event_enum_name::#case_disabled); + handler(#event_enum_name::#case_disabled); } } )); @@ -252,13 +262,14 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { #code_register_chars Ok(Self { + service_handle, #code_register_init }) } - fn on_write(&self, handle: u16, data: &[u8]) -> Option { - #code_on_write - None + fn on_event<'m, F>(&self, event: &#ble::gatt_server::GattEvent<'m>, mut handler: F) + where F: FnMut(Self::Event) { + #code_on_event } } diff --git a/nrf-softdevice/src/ble/gatt_server.rs b/nrf-softdevice/src/ble/gatt_server.rs index 58663cc..2f65d5c 100644 --- a/nrf-softdevice/src/ble/gatt_server.rs +++ b/nrf-softdevice/src/ble/gatt_server.rs @@ -28,15 +28,23 @@ pub struct CharacteristicHandles { pub sccd_handle: u16, } +pub struct GattEvent<'a> { + pub handle: u16, + pub data: &'a [u8], +} + pub trait Server: Sized { type Event; fn uuid() -> Uuid; + fn register(service_handle: u16, register_char: F) -> Result where F: FnMut(Characteristic, &[u8]) -> Result; - fn on_write(&self, handle: u16, data: &[u8]) -> Option; + fn on_event<'m, F>(&self, event: &GattEvent<'m>, f: F) + where + F: FnMut(Self::Event); } #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -139,9 +147,9 @@ impl From for RunError { } } -pub async fn run(conn: &Connection, server: &S, mut f: F) -> Result<(), RunError> +pub async fn run<'m, F>(conn: &Connection, mut f: F) -> Result<(), RunError> where - F: FnMut(S::Event), + F: FnMut(GattEvent<'m>), { let conn_handle = conn.with_state(|state| state.check_connected())?; portal(conn_handle) @@ -163,7 +171,10 @@ where panic!("gatt_server auth_required not yet supported"); } - server.on_write(params.handle, v).map(|e| f(e)); + f(GattEvent { + handle: params.handle, + data: &v, + }); } _ => {} } -- cgit v1.2.3 From 230d133f4d6e02d2631a3fcdcebe7675764c17fb Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 5 Oct 2021 15:55:11 +0200 Subject: Update an example --- examples/src/bin/ble_bas_peripheral.rs | 44 ++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/examples/src/bin/ble_bas_peripheral.rs b/examples/src/bin/ble_bas_peripheral.rs index 8793c82..2b8fe8a 100644 --- a/examples/src/bin/ble_bas_peripheral.rs +++ b/examples/src/bin/ble_bas_peripheral.rs @@ -14,7 +14,7 @@ use defmt::*; use embassy::executor::Executor; use embassy::util::Forever; -use nrf_softdevice::ble::{gatt_server, peripheral}; +use nrf_softdevice::ble::{gatt_server::{self, Server}, peripheral}; use nrf_softdevice::{raw, Softdevice}; static EXECUTOR: Forever = Forever::new(); @@ -57,27 +57,31 @@ async fn bluetooth_task(sd: &'static Softdevice) { info!("advertising done!"); // Run the GATT server on the connection. This returns when the connection gets disconnected. - let res = gatt_server::run(&conn, &server, |e| match e { - BatteryServiceEvent::BatteryLevelWrite(val) => { - info!("wrote battery level: {}", val); - if let Err(e) = server.battery_level_notify(&conn, val + 1) { - info!("send notification error: {:?}", e); + let res = gatt_server::run(&conn, |e| { + server.on_event(&e, |e| match e { + BatteryServiceEvent::BatteryLevelWrite(val) => { + info!("wrote battery level: {}", val); + if let Err(e) = server.battery_level_notify(&conn, val + 1) { + info!("send notification error: {:?}", e); + } } - } - BatteryServiceEvent::FooWrite(val) => { - info!("wrote battery level: {}", val); - if let Err(e) = server.foo_notify(&conn, val + 1) { - info!("send notification error: {:?}", e); + BatteryServiceEvent::FooWrite(val) => { + info!("wrote battery level: {}", val); + if let Err(e) = server.foo_notify(&conn, val + 1) { + info!("send notification error: {:?}", e); + } } - } - BatteryServiceEvent::BatteryLevelNotificationsEnabled => { - info!("battery notifications enabled") - } - BatteryServiceEvent::BatteryLevelNotificationsDisabled => { - info!("battery notifications disabled") - } - BatteryServiceEvent::FooNotificationsEnabled => info!("foo notifications enabled"), - BatteryServiceEvent::FooNotificationsDisabled => info!("foo notifications disabled"), + BatteryServiceEvent::BatteryLevelNotificationsEnabled => { + info!("battery notifications enabled") + } + BatteryServiceEvent::BatteryLevelNotificationsDisabled => { + info!("battery notifications disabled") + } + BatteryServiceEvent::FooNotificationsEnabled => info!("foo notifications enabled"), + BatteryServiceEvent::FooNotificationsDisabled => { + info!("foo notifications disabled") + } + }) }) .await; -- cgit v1.2.3 From 8d78ed20f1313d00d8727f41383413a13c23d457 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 6 Oct 2021 18:43:55 +0200 Subject: Simplify API --- examples/src/bin/ble_bas_peripheral.rs | 52 ++++++++++++++++++---------------- nrf-softdevice-macro/src/lib.rs | 18 ++++++------ nrf-softdevice/src/ble/gatt_server.rs | 9 +++--- 3 files changed, 41 insertions(+), 38 deletions(-) diff --git a/examples/src/bin/ble_bas_peripheral.rs b/examples/src/bin/ble_bas_peripheral.rs index 2b8fe8a..c8b70a0 100644 --- a/examples/src/bin/ble_bas_peripheral.rs +++ b/examples/src/bin/ble_bas_peripheral.rs @@ -14,7 +14,10 @@ use defmt::*; use embassy::executor::Executor; use embassy::util::Forever; -use nrf_softdevice::ble::{gatt_server::{self, Server}, peripheral}; +use nrf_softdevice::ble::{ + gatt_server::{self, Server}, + peripheral, +}; use nrf_softdevice::{raw, Softdevice}; static EXECUTOR: Forever = Forever::new(); @@ -57,31 +60,32 @@ async fn bluetooth_task(sd: &'static Softdevice) { info!("advertising done!"); // Run the GATT server on the connection. This returns when the connection gets disconnected. - let res = gatt_server::run(&conn, |e| { - server.on_event(&e, |e| match e { - BatteryServiceEvent::BatteryLevelWrite(val) => { - info!("wrote battery level: {}", val); - if let Err(e) = server.battery_level_notify(&conn, val + 1) { - info!("send notification error: {:?}", e); - } + let res = gatt_server::run(&conn, |e| match server.on_event(e) { + Some(BatteryServiceEvent::BatteryLevelWrite(val)) => { + info!("wrote battery level: {}", val); + if let Err(e) = server.battery_level_notify(&conn, val + 1) { + info!("send notification error: {:?}", e); } - BatteryServiceEvent::FooWrite(val) => { - info!("wrote battery level: {}", val); - if let Err(e) = server.foo_notify(&conn, val + 1) { - info!("send notification error: {:?}", e); - } + } + Some(BatteryServiceEvent::FooWrite(val)) => { + info!("wrote battery level: {}", val); + if let Err(e) = server.foo_notify(&conn, val + 1) { + info!("send notification error: {:?}", e); } - BatteryServiceEvent::BatteryLevelNotificationsEnabled => { - info!("battery notifications enabled") - } - BatteryServiceEvent::BatteryLevelNotificationsDisabled => { - info!("battery notifications disabled") - } - BatteryServiceEvent::FooNotificationsEnabled => info!("foo notifications enabled"), - BatteryServiceEvent::FooNotificationsDisabled => { - info!("foo notifications disabled") - } - }) + } + Some(BatteryServiceEvent::BatteryLevelNotificationsEnabled) => { + info!("battery notifications enabled") + } + Some(BatteryServiceEvent::BatteryLevelNotificationsDisabled) => { + info!("battery notifications disabled") + } + Some(BatteryServiceEvent::FooNotificationsEnabled) => { + info!("foo notifications enabled") + } + Some(BatteryServiceEvent::FooNotificationsDisabled) => { + info!("foo notifications disabled") + } + None => {} }) .await; diff --git a/nrf-softdevice-macro/src/lib.rs b/nrf-softdevice-macro/src/lib.rs index c232aac..6cefa94 100644 --- a/nrf-softdevice-macro/src/lib.rs +++ b/nrf-softdevice-macro/src/lib.rs @@ -109,7 +109,7 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { let mut code_impl = TokenStream2::new(); let mut code_register_chars = TokenStream2::new(); let mut code_register_init = TokenStream2::new(); - let mut code_on_event = TokenStream2::new(); + let mut code_on_write = TokenStream2::new(); let mut code_event_enum = TokenStream2::new(); let ble = quote!(::nrf_softdevice::ble); @@ -200,9 +200,9 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { code_event_enum.extend(quote_spanned!(ch.span=> #case_write(#ty), )); - code_on_event.extend(quote_spanned!(ch.span=> + code_on_write.extend(quote_spanned!(ch.span=> if event.handle == self.#value_handle { - handler(#event_enum_name::#case_write(#ty_as_val::from_gatt(event.data))); + return Some(#event_enum_name::#case_write(#ty_as_val::from_gatt(event.data))); } )); } @@ -225,13 +225,13 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { #case_enabled, #case_disabled, )); - code_on_event.extend(quote_spanned!(ch.span=> + code_on_write.extend(quote_spanned!(ch.span=> if event.handle == self.#cccd_handle { let data = event.data; if data.len() != 0 && data[0] & 0x01 != 0 { - handler(#event_enum_name::#case_enabled); + return Some(#event_enum_name::#case_enabled); } else { - handler(#event_enum_name::#case_disabled); + return Some(#event_enum_name::#case_disabled); } } )); @@ -267,9 +267,9 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { }) } - fn on_event<'m, F>(&self, event: &#ble::gatt_server::GattEvent<'m>, mut handler: F) - where F: FnMut(Self::Event) { - #code_on_event + fn on_write<'m>(&self, event: #ble::gatt_server::GattEvent<'m>) -> Some { + #code_on_write + None } } diff --git a/nrf-softdevice/src/ble/gatt_server.rs b/nrf-softdevice/src/ble/gatt_server.rs index 2f65d5c..4200c22 100644 --- a/nrf-softdevice/src/ble/gatt_server.rs +++ b/nrf-softdevice/src/ble/gatt_server.rs @@ -28,9 +28,10 @@ pub struct CharacteristicHandles { pub sccd_handle: u16, } +#[derive(Clone)] pub struct GattEvent<'a> { - pub handle: u16, - pub data: &'a [u8], + handle: u16, + data: &'a [u8], } pub trait Server: Sized { @@ -42,9 +43,7 @@ pub trait Server: Sized { where F: FnMut(Characteristic, &[u8]) -> Result; - fn on_event<'m, F>(&self, event: &GattEvent<'m>, f: F) - where - F: FnMut(Self::Event); + fn on_write<'m>(&self, event: GattEvent<'m>) -> Option; } #[derive(Debug, PartialEq, Eq, Clone, Copy)] -- cgit v1.2.3 From ab48ad7f39900bdc9865ea65e800c16e6e128185 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 6 Oct 2021 18:45:40 +0200 Subject: Simplify further --- nrf-softdevice-macro/src/lib.rs | 10 ---------- nrf-softdevice/src/ble/gatt_server.rs | 4 ++-- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/nrf-softdevice-macro/src/lib.rs b/nrf-softdevice-macro/src/lib.rs index 6cefa94..8e52bf1 100644 --- a/nrf-softdevice-macro/src/lib.rs +++ b/nrf-softdevice-macro/src/lib.rs @@ -114,15 +114,6 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { let ble = quote!(::nrf_softdevice::ble); - let service_handle = format_ident!("service_handle"); - fields.push(syn::Field { - ident: Some(service_handle), - ty: syn::Type::Verbatim(quote!(u16).into()), - attrs: Vec::new(), - colon_token: Default::default(), - vis: syn::Visibility::Inherited, - }); - for ch in &chars { let name_pascal = inflector::cases::pascalcase::to_pascal_case(&ch.name); let char_name = format_ident!("{}", ch.name); @@ -262,7 +253,6 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { #code_register_chars Ok(Self { - service_handle, #code_register_init }) } diff --git a/nrf-softdevice/src/ble/gatt_server.rs b/nrf-softdevice/src/ble/gatt_server.rs index 4200c22..ba6bc9c 100644 --- a/nrf-softdevice/src/ble/gatt_server.rs +++ b/nrf-softdevice/src/ble/gatt_server.rs @@ -30,8 +30,8 @@ pub struct CharacteristicHandles { #[derive(Clone)] pub struct GattEvent<'a> { - handle: u16, - data: &'a [u8], + pub handle: u16, + pub data: &'a [u8], } pub trait Server: Sized { -- cgit v1.2.3 From ded290c788d79a9c90059c8eceae2e442116ad3c Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 6 Oct 2021 18:47:57 +0200 Subject: Rename to on_event --- nrf-softdevice-macro/src/lib.rs | 10 +++++----- nrf-softdevice/src/ble/gatt_server.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/nrf-softdevice-macro/src/lib.rs b/nrf-softdevice-macro/src/lib.rs index 8e52bf1..f91a7d9 100644 --- a/nrf-softdevice-macro/src/lib.rs +++ b/nrf-softdevice-macro/src/lib.rs @@ -109,7 +109,7 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { let mut code_impl = TokenStream2::new(); let mut code_register_chars = TokenStream2::new(); let mut code_register_init = TokenStream2::new(); - let mut code_on_write = TokenStream2::new(); + let mut code_on_event = TokenStream2::new(); let mut code_event_enum = TokenStream2::new(); let ble = quote!(::nrf_softdevice::ble); @@ -191,7 +191,7 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { code_event_enum.extend(quote_spanned!(ch.span=> #case_write(#ty), )); - code_on_write.extend(quote_spanned!(ch.span=> + code_on_event.extend(quote_spanned!(ch.span=> if event.handle == self.#value_handle { return Some(#event_enum_name::#case_write(#ty_as_val::from_gatt(event.data))); } @@ -216,7 +216,7 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { #case_enabled, #case_disabled, )); - code_on_write.extend(quote_spanned!(ch.span=> + code_on_event.extend(quote_spanned!(ch.span=> if event.handle == self.#cccd_handle { let data = event.data; if data.len() != 0 && data[0] & 0x01 != 0 { @@ -257,8 +257,8 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { }) } - fn on_write<'m>(&self, event: #ble::gatt_server::GattEvent<'m>) -> Some { - #code_on_write + fn on_event<'m>(&self, event: #ble::gatt_server::GattEvent<'m>) -> Option { + #code_on_event None } } diff --git a/nrf-softdevice/src/ble/gatt_server.rs b/nrf-softdevice/src/ble/gatt_server.rs index ba6bc9c..124c3ff 100644 --- a/nrf-softdevice/src/ble/gatt_server.rs +++ b/nrf-softdevice/src/ble/gatt_server.rs @@ -43,7 +43,7 @@ pub trait Server: Sized { where F: FnMut(Characteristic, &[u8]) -> Result; - fn on_write<'m>(&self, event: GattEvent<'m>) -> Option; + fn on_event<'m>(&self, event: GattEvent<'m>) -> Option; } #[derive(Debug, PartialEq, Eq, Clone, Copy)] -- cgit v1.2.3 From 714f3ad657a65315a70437fe133ff088fa2bac11 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 7 Oct 2021 08:29:36 +0200 Subject: Rename back to on_write --- examples/src/bin/ble_bas_peripheral.rs | 2 +- nrf-softdevice-macro/src/lib.rs | 10 +++++----- nrf-softdevice/src/ble/gatt_server.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/src/bin/ble_bas_peripheral.rs b/examples/src/bin/ble_bas_peripheral.rs index c8b70a0..4fc773d 100644 --- a/examples/src/bin/ble_bas_peripheral.rs +++ b/examples/src/bin/ble_bas_peripheral.rs @@ -60,7 +60,7 @@ async fn bluetooth_task(sd: &'static Softdevice) { info!("advertising done!"); // Run the GATT server on the connection. This returns when the connection gets disconnected. - let res = gatt_server::run(&conn, |e| match server.on_event(e) { + let res = gatt_server::run(&conn, |e| match server.on_write(e) { Some(BatteryServiceEvent::BatteryLevelWrite(val)) => { info!("wrote battery level: {}", val); if let Err(e) = server.battery_level_notify(&conn, val + 1) { diff --git a/nrf-softdevice-macro/src/lib.rs b/nrf-softdevice-macro/src/lib.rs index f91a7d9..6fabb64 100644 --- a/nrf-softdevice-macro/src/lib.rs +++ b/nrf-softdevice-macro/src/lib.rs @@ -109,7 +109,7 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { let mut code_impl = TokenStream2::new(); let mut code_register_chars = TokenStream2::new(); let mut code_register_init = TokenStream2::new(); - let mut code_on_event = TokenStream2::new(); + let mut code_on_write = TokenStream2::new(); let mut code_event_enum = TokenStream2::new(); let ble = quote!(::nrf_softdevice::ble); @@ -191,7 +191,7 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { code_event_enum.extend(quote_spanned!(ch.span=> #case_write(#ty), )); - code_on_event.extend(quote_spanned!(ch.span=> + code_on_write.extend(quote_spanned!(ch.span=> if event.handle == self.#value_handle { return Some(#event_enum_name::#case_write(#ty_as_val::from_gatt(event.data))); } @@ -216,7 +216,7 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { #case_enabled, #case_disabled, )); - code_on_event.extend(quote_spanned!(ch.span=> + code_on_write.extend(quote_spanned!(ch.span=> if event.handle == self.#cccd_handle { let data = event.data; if data.len() != 0 && data[0] & 0x01 != 0 { @@ -257,8 +257,8 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { }) } - fn on_event<'m>(&self, event: #ble::gatt_server::GattEvent<'m>) -> Option { - #code_on_event + fn on_write<'m>(&self, event: #ble::gatt_server::GattEvent<'m>) -> Option { + #code_on_write None } } diff --git a/nrf-softdevice/src/ble/gatt_server.rs b/nrf-softdevice/src/ble/gatt_server.rs index 124c3ff..ba6bc9c 100644 --- a/nrf-softdevice/src/ble/gatt_server.rs +++ b/nrf-softdevice/src/ble/gatt_server.rs @@ -43,7 +43,7 @@ pub trait Server: Sized { where F: FnMut(Characteristic, &[u8]) -> Result; - fn on_event<'m>(&self, event: GattEvent<'m>) -> Option; + fn on_write<'m>(&self, event: GattEvent<'m>) -> Option; } #[derive(Debug, PartialEq, Eq, Clone, Copy)] -- cgit v1.2.3 From 4d4123639336e23088eeb53b54d90d6f8d618195 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 7 Oct 2021 08:33:22 +0200 Subject: Give enum same visibility as service struct --- nrf-softdevice-macro/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nrf-softdevice-macro/src/lib.rs b/nrf-softdevice-macro/src/lib.rs index 6fabb64..5b10e03 100644 --- a/nrf-softdevice-macro/src/lib.rs +++ b/nrf-softdevice-macro/src/lib.rs @@ -231,6 +231,7 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { let uuid = args.uuid; struct_fields.named = syn::punctuated::Punctuated::from_iter(fields); + let visibility = struc.vis.clone(); let result = quote! { #struc @@ -263,7 +264,7 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { } } - enum #event_enum_name { + #visibility enum #event_enum_name { #code_event_enum } }; -- cgit v1.2.3 From 21617efac6256f1d0905dd4c9385507c03c56f97 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 7 Oct 2021 09:38:50 +0200 Subject: Make fn have the same visibility as struct fields --- nrf-softdevice-macro/src/lib.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/nrf-softdevice-macro/src/lib.rs b/nrf-softdevice-macro/src/lib.rs index 5b10e03..4fdc4c2 100644 --- a/nrf-softdevice-macro/src/lib.rs +++ b/nrf-softdevice-macro/src/lib.rs @@ -36,6 +36,7 @@ struct Characteristic { ty: syn::Type, args: CharacteristicArgs, span: Span, + vis: syn::Visibility, } #[proc_macro_attribute] @@ -90,6 +91,7 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { ty: field.ty.clone(), args, span: field.ty.span(), + vis: field.vis.clone(), }); false @@ -122,6 +124,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 fn_vis = ch.vis.clone(); let uuid = ch.args.uuid; let read = ch.args.read; @@ -159,14 +162,14 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { )); code_impl.extend(quote_spanned!(ch.span=> - fn #get_fn(&self) -> Result<#ty, #ble::gatt_server::GetValueError> { + #fn_vis fn #get_fn(&self) -> Result<#ty, #ble::gatt_server::GetValueError> { let sd = unsafe { ::nrf_softdevice::Softdevice::steal() }; let buf = &mut [0u8; #ty_as_val::MAX_SIZE]; let size = #ble::gatt_server::get_value(sd, self.#value_handle, buf)?; Ok(#ty_as_val::from_gatt(&buf[..size])) } - fn #set_fn(&self, val: #ty) -> Result<(), #ble::gatt_server::SetValueError> { + #fn_vis fn #set_fn(&self, val: #ty) -> Result<(), #ble::gatt_server::SetValueError> { let sd = unsafe { ::nrf_softdevice::Softdevice::steal() }; let buf = #ty_as_val::to_gatt(&val); #ble::gatt_server::set_value(sd, self.#value_handle, buf) @@ -202,7 +205,7 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { let case_disabled = format_ident!("{}NotificationsDisabled", name_pascal); code_impl.extend(quote_spanned!(ch.span=> - fn #notify_fn( + #fn_vis fn #notify_fn( &self, conn: &#ble::Connection, val: #ty, @@ -231,7 +234,7 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { let uuid = args.uuid; struct_fields.named = syn::punctuated::Punctuated::from_iter(fields); - let visibility = struc.vis.clone(); + let struc_vis = struc.vis.clone(); let result = quote! { #struc @@ -264,7 +267,7 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { } } - #visibility enum #event_enum_name { + #struc_vis enum #event_enum_name { #code_event_enum } }; @@ -323,6 +326,7 @@ pub fn gatt_client(args: TokenStream, item: TokenStream) -> TokenStream { ty: field.ty.clone(), args, span: field.ty.span(), + vis: field.vis.clone(), }); false -- cgit v1.2.3 From 40c9680b46580009feaa5c8b54477eb48e7ee038 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 7 Oct 2021 09:46:38 +0200 Subject: Fix remaining example --- examples/src/bin/ble_peripheral_onoff.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/examples/src/bin/ble_peripheral_onoff.rs b/examples/src/bin/ble_peripheral_onoff.rs index e3f3943..7670c44 100644 --- a/examples/src/bin/ble_peripheral_onoff.rs +++ b/examples/src/bin/ble_peripheral_onoff.rs @@ -18,7 +18,10 @@ use embassy_nrf::gpiote::PortInput; use embassy_nrf::interrupt::Priority; use futures::pin_mut; -use nrf_softdevice::ble::{gatt_server, peripheral}; +use nrf_softdevice::ble::{ + gatt_server::{self, Server}, + peripheral, +}; use nrf_softdevice::{raw, Softdevice}; static EXECUTOR: Forever = Forever::new(); @@ -56,15 +59,16 @@ async fn run_bluetooth(sd: &'static Softdevice, server: &FooService) { info!("advertising done!"); - let res = gatt_server::run(&conn, server, |e| match e { - FooServiceEvent::FooWrite(val) => { + let res = gatt_server::run(&conn, |e| match server.on_write(e) { + Some(FooServiceEvent::FooWrite(val)) => { info!("wrote foo level: {}", val); if let Err(e) = server.foo_notify(&conn, val + 1) { info!("send notification error: {:?}", e); } } - FooServiceEvent::FooNotificationsEnabled => info!("notifications enabled"), - FooServiceEvent::FooNotificationsDisabled => info!("notifications disabled"), + Some(FooServiceEvent::FooNotificationsEnabled) => info!("notifications enabled"), + Some(FooServiceEvent::FooNotificationsDisabled) => info!("notifications disabled"), + None => {} }) .await; -- cgit v1.2.3 From 2ee4c87061004a1c4e59f1445b5e9976c6d83e9b Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 8 Oct 2021 08:30:14 +0200 Subject: Split battery and foo service --- examples/src/bin/ble_bas_peripheral.rs | 59 ++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/examples/src/bin/ble_bas_peripheral.rs b/examples/src/bin/ble_bas_peripheral.rs index 4fc773d..b63d578 100644 --- a/examples/src/bin/ble_bas_peripheral.rs +++ b/examples/src/bin/ble_bas_peripheral.rs @@ -31,13 +31,18 @@ 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)] +} + +#[nrf_softdevice::gatt_server(uuid = "9e7312e0-2354-11eb-9f10-fbc30a62cf38")] +struct FooService { + #[characteristic(uuid = "9e7312e0-2354-11eb-9f10-fbc30a63cf38", read, write, notify)] foo: u16, } #[embassy::task] async fn bluetooth_task(sd: &'static Softdevice) { - let server: BatteryService = unwrap!(gatt_server::register(sd)); + let battery_service: BatteryService = unwrap!(gatt_server::register(sd)); + let foo_service: FooService = unwrap!(gatt_server::register(sd)); #[rustfmt::skip] let adv_data = &[ 0x02, 0x01, raw::BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE as u8, @@ -60,32 +65,38 @@ async fn bluetooth_task(sd: &'static Softdevice) { info!("advertising done!"); // Run the GATT server on the connection. This returns when the connection gets disconnected. - let res = gatt_server::run(&conn, |e| match server.on_write(e) { - Some(BatteryServiceEvent::BatteryLevelWrite(val)) => { - info!("wrote battery level: {}", val); - if let Err(e) = server.battery_level_notify(&conn, val + 1) { - info!("send notification error: {:?}", e); + let res = gatt_server::run(&conn, |e| { + match battery_service.on_write(e.clone()) { + Some(BatteryServiceEvent::BatteryLevelWrite(val)) => { + info!("wrote battery level: {}", val); + if let Err(e) = battery_service.battery_level_notify(&conn, val + 1) { + info!("send notification error: {:?}", e); + } } - } - Some(BatteryServiceEvent::FooWrite(val)) => { - info!("wrote battery level: {}", val); - if let Err(e) = server.foo_notify(&conn, val + 1) { - info!("send notification error: {:?}", e); + + Some(BatteryServiceEvent::BatteryLevelNotificationsEnabled) => { + info!("battery notifications enabled") } + Some(BatteryServiceEvent::BatteryLevelNotificationsDisabled) => { + info!("battery notifications disabled") + } + None => {} } - Some(BatteryServiceEvent::BatteryLevelNotificationsEnabled) => { - info!("battery notifications enabled") - } - Some(BatteryServiceEvent::BatteryLevelNotificationsDisabled) => { - info!("battery notifications disabled") - } - Some(BatteryServiceEvent::FooNotificationsEnabled) => { - info!("foo notifications enabled") - } - Some(BatteryServiceEvent::FooNotificationsDisabled) => { - info!("foo notifications disabled") + match foo_service.on_write(e) { + Some(FooServiceEvent::FooWrite(val)) => { + info!("wrote battery level: {}", val); + if let Err(e) = foo_service.foo_notify(&conn, val + 1) { + info!("send notification error: {:?}", e); + } + } + Some(FooServiceEvent::FooNotificationsEnabled) => { + info!("foo notifications enabled") + } + Some(FooServiceEvent::FooNotificationsDisabled) => { + info!("foo notifications disabled") + } + None => {} } - None => {} }) .await; -- cgit v1.2.3 From 59849798ace87c9acc3ef5e5e634114dd1ce7244 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 11 Oct 2021 09:53:34 +0200 Subject: Remove write from battery service --- examples/src/bin/ble_bas_peripheral.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/examples/src/bin/ble_bas_peripheral.rs b/examples/src/bin/ble_bas_peripheral.rs index b63d578..2f0328b 100644 --- a/examples/src/bin/ble_bas_peripheral.rs +++ b/examples/src/bin/ble_bas_peripheral.rs @@ -29,7 +29,7 @@ async fn softdevice_task(sd: &'static Softdevice) { #[nrf_softdevice::gatt_server(uuid = "180f")] struct BatteryService { - #[characteristic(uuid = "2a19", read, write, notify)] + #[characteristic(uuid = "2a19", read, notify)] battery_level: u8, } @@ -67,13 +67,6 @@ async fn bluetooth_task(sd: &'static Softdevice) { // Run the GATT server on the connection. This returns when the connection gets disconnected. let res = gatt_server::run(&conn, |e| { match battery_service.on_write(e.clone()) { - Some(BatteryServiceEvent::BatteryLevelWrite(val)) => { - info!("wrote battery level: {}", val); - if let Err(e) = battery_service.battery_level_notify(&conn, val + 1) { - info!("send notification error: {:?}", e); - } - } - Some(BatteryServiceEvent::BatteryLevelNotificationsEnabled) => { info!("battery notifications enabled") } -- cgit v1.2.3 From c9a0fbf3b7d9537463756efdad7a819cfff6756e Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 11 Oct 2021 09:53:42 +0200 Subject: Rename gatt_server to gatt_service --- examples/src/bin/ble_bas_peripheral.rs | 6 +++--- examples/src/bin/ble_peripheral_onoff.rs | 4 ++-- nrf-softdevice-macro/src/lib.rs | 12 ++++++------ nrf-softdevice/src/ble/gatt_server.rs | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/examples/src/bin/ble_bas_peripheral.rs b/examples/src/bin/ble_bas_peripheral.rs index 2f0328b..31a258e 100644 --- a/examples/src/bin/ble_bas_peripheral.rs +++ b/examples/src/bin/ble_bas_peripheral.rs @@ -15,7 +15,7 @@ use embassy::executor::Executor; use embassy::util::Forever; use nrf_softdevice::ble::{ - gatt_server::{self, Server}, + gatt_server::{self, Service}, peripheral, }; use nrf_softdevice::{raw, Softdevice}; @@ -27,13 +27,13 @@ async fn softdevice_task(sd: &'static Softdevice) { sd.run().await; } -#[nrf_softdevice::gatt_server(uuid = "180f")] +#[nrf_softdevice::gatt_service(uuid = "180f")] struct BatteryService { #[characteristic(uuid = "2a19", read, notify)] battery_level: u8, } -#[nrf_softdevice::gatt_server(uuid = "9e7312e0-2354-11eb-9f10-fbc30a62cf38")] +#[nrf_softdevice::gatt_service(uuid = "9e7312e0-2354-11eb-9f10-fbc30a62cf38")] struct FooService { #[characteristic(uuid = "9e7312e0-2354-11eb-9f10-fbc30a63cf38", read, write, notify)] foo: u16, diff --git a/examples/src/bin/ble_peripheral_onoff.rs b/examples/src/bin/ble_peripheral_onoff.rs index 7670c44..3666055 100644 --- a/examples/src/bin/ble_peripheral_onoff.rs +++ b/examples/src/bin/ble_peripheral_onoff.rs @@ -19,7 +19,7 @@ use embassy_nrf::interrupt::Priority; use futures::pin_mut; use nrf_softdevice::ble::{ - gatt_server::{self, Server}, + gatt_server::{self, Service}, peripheral, }; use nrf_softdevice::{raw, Softdevice}; @@ -31,7 +31,7 @@ async fn softdevice_task(sd: &'static Softdevice) { sd.run().await; } -#[nrf_softdevice::gatt_server(uuid = "9e7312e0-2354-11eb-9f10-fbc30a62cf38")] +#[nrf_softdevice::gatt_service(uuid = "9e7312e0-2354-11eb-9f10-fbc30a62cf38")] struct FooService { #[characteristic(uuid = "9e7312e0-2354-11eb-9f10-fbc30a63cf38", read, write, notify)] foo: u16, diff --git a/nrf-softdevice-macro/src/lib.rs b/nrf-softdevice-macro/src/lib.rs index 4fdc4c2..99ce3af 100644 --- a/nrf-softdevice-macro/src/lib.rs +++ b/nrf-softdevice-macro/src/lib.rs @@ -14,7 +14,7 @@ mod uuid; use crate::uuid::Uuid; #[derive(Debug, FromMeta)] -struct ServerArgs { +struct ServiceArgs { uuid: Uuid, } #[derive(Debug, FromMeta)] @@ -40,11 +40,11 @@ struct Characteristic { } #[proc_macro_attribute] -pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { +pub fn gatt_service(args: TokenStream, item: TokenStream) -> TokenStream { let args = syn::parse_macro_input!(args as syn::AttributeArgs); let mut struc = syn::parse_macro_input!(item as syn::ItemStruct); - let args = match ServerArgs::from_list(&args) { + let args = match ServiceArgs::from_list(&args) { Ok(v) => v, Err(e) => { return e.write_errors().into(); @@ -60,7 +60,7 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { .ident .span() .unwrap() - .error("gatt_server structs must have named fields, not tuples.") + .error("gatt_service structs must have named fields, not tuples.") .emit(); return TokenStream::new(); } @@ -243,7 +243,7 @@ pub fn gatt_server(args: TokenStream, item: TokenStream) -> TokenStream { #code_impl } - impl #ble::gatt_server::Server for #struct_name { + impl #ble::gatt_server::Service for #struct_name { type Event = #event_enum_name; fn uuid() -> #ble::Uuid { @@ -279,7 +279,7 @@ pub fn gatt_client(args: TokenStream, item: TokenStream) -> TokenStream { let args = syn::parse_macro_input!(args as syn::AttributeArgs); let mut struc = syn::parse_macro_input!(item as syn::ItemStruct); - let args = match ServerArgs::from_list(&args) { + let args = match ServiceArgs::from_list(&args) { Ok(v) => v, Err(e) => { return e.write_errors().into(); diff --git a/nrf-softdevice/src/ble/gatt_server.rs b/nrf-softdevice/src/ble/gatt_server.rs index ba6bc9c..aa66324 100644 --- a/nrf-softdevice/src/ble/gatt_server.rs +++ b/nrf-softdevice/src/ble/gatt_server.rs @@ -34,7 +34,7 @@ pub struct GattEvent<'a> { pub data: &'a [u8], } -pub trait Server: Sized { +pub trait Service: Sized { type Event; fn uuid() -> Uuid; @@ -58,7 +58,7 @@ impl From for RegisterError { } } -pub fn register(_sd: &Softdevice) -> Result { +pub fn register(_sd: &Softdevice) -> Result { let mut service_handle: u16 = 0; let ret = unsafe { raw::sd_ble_gatts_service_add( -- cgit v1.2.3 From 1f73a93a6ddce925ff749d63f4528e50e9efae02 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 11 Oct 2021 11:41:24 +0200 Subject: Add gatt_server macro for registering a GATT server Generate event type and on_write handling for server type, which in turn dispatches events to its services. Register and run now takes a valid Server instance as argument. --- examples/src/bin/ble_bas_peripheral.rs | 41 +++++++------- examples/src/bin/ble_peripheral_onoff.rs | 29 ++++++---- nrf-softdevice-macro/src/lib.rs | 97 ++++++++++++++++++++++++++++++-- nrf-softdevice/src/ble/gatt_server.rs | 29 +++++----- 4 files changed, 146 insertions(+), 50 deletions(-) diff --git a/examples/src/bin/ble_bas_peripheral.rs b/examples/src/bin/ble_bas_peripheral.rs index 31a258e..ff30375 100644 --- a/examples/src/bin/ble_bas_peripheral.rs +++ b/examples/src/bin/ble_bas_peripheral.rs @@ -14,10 +14,7 @@ use defmt::*; use embassy::executor::Executor; use embassy::util::Forever; -use nrf_softdevice::ble::{ - gatt_server::{self, Service}, - peripheral, -}; +use nrf_softdevice::ble::{gatt_server, peripheral}; use nrf_softdevice::{raw, Softdevice}; static EXECUTOR: Forever = Forever::new(); @@ -39,10 +36,16 @@ struct FooService { foo: u16, } +#[nrf_softdevice::gatt_server] +struct Server { + bas: BatteryService, + foo: FooService, +} + #[embassy::task] async fn bluetooth_task(sd: &'static Softdevice) { - let battery_service: BatteryService = unwrap!(gatt_server::register(sd)); - let foo_service: FooService = unwrap!(gatt_server::register(sd)); + let server: Server = unwrap!(gatt_server::register(sd)); + #[rustfmt::skip] let adv_data = &[ 0x02, 0x01, raw::BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE as u8, @@ -65,31 +68,29 @@ async fn bluetooth_task(sd: &'static Softdevice) { info!("advertising done!"); // Run the GATT server on the connection. This returns when the connection gets disconnected. - let res = gatt_server::run(&conn, |e| { - match battery_service.on_write(e.clone()) { - Some(BatteryServiceEvent::BatteryLevelNotificationsEnabled) => { + let res = gatt_server::run(&conn, &server, |e| match e { + ServerEvent::BatteryService(e) => match e { + BatteryServiceEvent::BatteryLevelNotificationsEnabled => { info!("battery notifications enabled") } - Some(BatteryServiceEvent::BatteryLevelNotificationsDisabled) => { + BatteryServiceEvent::BatteryLevelNotificationsDisabled => { info!("battery notifications disabled") } - None => {} - } - match foo_service.on_write(e) { - Some(FooServiceEvent::FooWrite(val)) => { - info!("wrote battery level: {}", val); - if let Err(e) = foo_service.foo_notify(&conn, val + 1) { + }, + ServerEvent::FooService(e) => match e { + FooServiceEvent::FooWrite(val) => { + info!("wrote foo: {}", val); + if let Err(e) = server.foo.foo_notify(&conn, val + 1) { info!("send notification error: {:?}", e); } } - Some(FooServiceEvent::FooNotificationsEnabled) => { + FooServiceEvent::FooNotificationsEnabled => { info!("foo notifications enabled") } - Some(FooServiceEvent::FooNotificationsDisabled) => { + FooServiceEvent::FooNotificationsDisabled => { info!("foo notifications disabled") } - None => {} - } + }, }) .await; diff --git a/examples/src/bin/ble_peripheral_onoff.rs b/examples/src/bin/ble_peripheral_onoff.rs index 3666055..82d0599 100644 --- a/examples/src/bin/ble_peripheral_onoff.rs +++ b/examples/src/bin/ble_peripheral_onoff.rs @@ -18,10 +18,7 @@ use embassy_nrf::gpiote::PortInput; use embassy_nrf::interrupt::Priority; use futures::pin_mut; -use nrf_softdevice::ble::{ - gatt_server::{self, Service}, - peripheral, -}; +use nrf_softdevice::ble::{gatt_server, peripheral}; use nrf_softdevice::{raw, Softdevice}; static EXECUTOR: Forever = Forever::new(); @@ -37,7 +34,12 @@ struct FooService { foo: u16, } -async fn run_bluetooth(sd: &'static Softdevice, server: &FooService) { +#[nrf_softdevice::gatt_server] +struct Server { + foo: FooService, +} + +async fn run_bluetooth(sd: &'static Softdevice, server: &Server) { #[rustfmt::skip] let adv_data = &[ 0x02, 0x01, raw::BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE as u8, @@ -59,16 +61,19 @@ async fn run_bluetooth(sd: &'static Softdevice, server: &FooService) { info!("advertising done!"); - let res = gatt_server::run(&conn, |e| match server.on_write(e) { - Some(FooServiceEvent::FooWrite(val)) => { + let res = gatt_server::run(&conn, server, |e| match e { + ServerEvent::FooService(FooServiceEvent::FooWrite(val)) => { info!("wrote foo level: {}", val); - if let Err(e) = server.foo_notify(&conn, val + 1) { + if let Err(e) = server.foo.foo_notify(&conn, val + 1) { info!("send notification error: {:?}", e); } } - Some(FooServiceEvent::FooNotificationsEnabled) => info!("notifications enabled"), - Some(FooServiceEvent::FooNotificationsDisabled) => info!("notifications disabled"), - None => {} + ServerEvent::FooService(FooServiceEvent::FooNotificationsEnabled) => { + info!("notifications enabled") + } + ServerEvent::FooService(FooServiceEvent::FooNotificationsDisabled) => { + info!("notifications disabled") + } }) .await; @@ -80,7 +85,7 @@ async fn run_bluetooth(sd: &'static Softdevice, server: &FooService) { #[embassy::task] async fn bluetooth_task(sd: &'static Softdevice, button1: AnyPin, button2: AnyPin) { - let server: FooService = unwrap!(gatt_server::register(sd)); + let server: Server = unwrap!(gatt_server::register(sd)); info!("Bluetooth is OFF"); info!("Press nrf52840-dk button 1 to enable, button 2 to disable"); diff --git a/nrf-softdevice-macro/src/lib.rs b/nrf-softdevice-macro/src/lib.rs index 99ce3af..4766954 100644 --- a/nrf-softdevice-macro/src/lib.rs +++ b/nrf-softdevice-macro/src/lib.rs @@ -39,6 +39,93 @@ struct Characteristic { vis: syn::Visibility, } +#[proc_macro_attribute] +pub fn gatt_server(_args: TokenStream, item: TokenStream) -> TokenStream { + let mut struc = syn::parse_macro_input!(item as syn::ItemStruct); + + let struct_fields = match &mut struc.fields { + syn::Fields::Named(n) => n, + _ => { + struc + .ident + .span() + .unwrap() + .error("gatt_server structs must have named fields, not tuples.") + .emit(); + return TokenStream::new(); + } + }; + let fields = struct_fields + .named + .iter() + .cloned() + .collect::>(); + + let struct_name = struc.ident.clone(); + let event_enum_name = format_ident!("{}Event", struct_name); + + let mut code_register_init = TokenStream2::new(); + let mut code_on_write = TokenStream2::new(); + let mut code_event_enum = TokenStream2::new(); + + let ble = quote!(::nrf_softdevice::ble); + + for field in fields.iter() { + let name = field.ident.as_ref().unwrap(); + let span = field.ty.span(); + code_register_init.extend(quote_spanned!(span=> + #name: #ble::gatt_server::register_service(sd)?, + )); + + if let syn::Type::Path(p) = &field.ty { + let event_enum_ty = p.path.get_ident().unwrap(); + let event_enum_variant = format_ident!("{}Event", event_enum_ty); + code_event_enum.extend(quote_spanned!(span=> + #event_enum_ty(#event_enum_variant), + )); + + code_on_write.extend(quote_spanned!(span=> + if let Some(e) = self.#name.on_write(handle, data) { + return Some(#event_enum_name::#event_enum_ty(e)); + } + )); + } + } + + struct_fields.named = syn::punctuated::Punctuated::from_iter(fields); + let struc_vis = struc.vis.clone(); + + let result = quote! { + #struc + + impl #struct_name { + } + + #struc_vis enum #event_enum_name { + #code_event_enum + } + + impl #ble::gatt_server::Server for #struct_name { + type Event = #event_enum_name; + + fn register(sd: &::nrf_softdevice::Softdevice) -> Result + { + Ok(Self { + #code_register_init + }) + } + + fn on_write(&self, handle: u16, data: &[u8]) -> Option { + use #ble::gatt_server::Service; + + #code_on_write + None + } + } + }; + result.into() +} + #[proc_macro_attribute] pub fn gatt_service(args: TokenStream, item: TokenStream) -> TokenStream { let args = syn::parse_macro_input!(args as syn::AttributeArgs); @@ -195,8 +282,8 @@ pub fn gatt_service(args: TokenStream, item: TokenStream) -> TokenStream { #case_write(#ty), )); code_on_write.extend(quote_spanned!(ch.span=> - if event.handle == self.#value_handle { - return Some(#event_enum_name::#case_write(#ty_as_val::from_gatt(event.data))); + if handle == self.#value_handle { + return Some(#event_enum_name::#case_write(#ty_as_val::from_gatt(data))); } )); } @@ -220,8 +307,8 @@ pub fn gatt_service(args: TokenStream, item: TokenStream) -> TokenStream { #case_disabled, )); code_on_write.extend(quote_spanned!(ch.span=> - if event.handle == self.#cccd_handle { - let data = event.data; + if handle == self.#cccd_handle { + let data = data; if data.len() != 0 && data[0] & 0x01 != 0 { return Some(#event_enum_name::#case_enabled); } else { @@ -261,7 +348,7 @@ pub fn gatt_service(args: TokenStream, item: TokenStream) -> TokenStream { }) } - fn on_write<'m>(&self, event: #ble::gatt_server::GattEvent<'m>) -> Option { + fn on_write(&self, handle: u16, data: &[u8]) -> Option { #code_on_write None } diff --git a/nrf-softdevice/src/ble/gatt_server.rs b/nrf-softdevice/src/ble/gatt_server.rs index aa66324..b744d9b 100644 --- a/nrf-softdevice/src/ble/gatt_server.rs +++ b/nrf-softdevice/src/ble/gatt_server.rs @@ -28,10 +28,10 @@ pub struct CharacteristicHandles { pub sccd_handle: u16, } -#[derive(Clone)] -pub struct GattEvent<'a> { - pub handle: u16, - pub data: &'a [u8], +pub trait Server: Sized { + type Event; + fn register(sd: &Softdevice) -> Result; + fn on_write(&self, handle: u16, data: &[u8]) -> Option; } pub trait Service: Sized { @@ -43,7 +43,7 @@ pub trait Service: Sized { where F: FnMut(Characteristic, &[u8]) -> Result; - fn on_write<'m>(&self, event: GattEvent<'m>) -> Option; + fn on_write(&self, handle: u16, data: &[u8]) -> Option; } #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -58,12 +58,17 @@ impl From for RegisterError { } } -pub fn register(_sd: &Softdevice) -> Result { +pub fn register(sd: &Softdevice) -> Result { + S::register(sd) +} + +pub fn register_service(_sd: &Softdevice) -> Result { + let uuid = S::uuid(); let mut service_handle: u16 = 0; let ret = unsafe { raw::sd_ble_gatts_service_add( raw::BLE_GATTS_SRVC_TYPE_PRIMARY as u8, - S::uuid().as_raw_ptr(), + uuid.as_raw_ptr(), &mut service_handle as _, ) }; @@ -146,9 +151,10 @@ impl From for RunError { } } -pub async fn run<'m, F>(conn: &Connection, mut f: F) -> Result<(), RunError> +pub async fn run<'m, F, S>(conn: &Connection, server: &S, mut f: F) -> Result<(), RunError> where - F: FnMut(GattEvent<'m>), + F: FnMut(S::Event), + S: Server, { let conn_handle = conn.with_state(|state| state.check_connected())?; portal(conn_handle) @@ -170,10 +176,7 @@ where panic!("gatt_server auth_required not yet supported"); } - f(GattEvent { - handle: params.handle, - data: &v, - }); + server.on_write(params.handle, &v).map(|e| f(e)); } _ => {} } -- cgit v1.2.3 From 37585e1ffafbfa5b32c9136472ddb3f4ae136856 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 11 Oct 2021 12:14:12 +0200 Subject: Derive event variant from struct field name --- examples/src/bin/ble_bas_peripheral.rs | 4 ++-- examples/src/bin/ble_peripheral_onoff.rs | 6 +++--- nrf-softdevice-macro/src/lib.rs | 8 ++++++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/examples/src/bin/ble_bas_peripheral.rs b/examples/src/bin/ble_bas_peripheral.rs index ff30375..511513b 100644 --- a/examples/src/bin/ble_bas_peripheral.rs +++ b/examples/src/bin/ble_bas_peripheral.rs @@ -69,7 +69,7 @@ async fn bluetooth_task(sd: &'static Softdevice) { // Run the GATT server on the connection. This returns when the connection gets disconnected. let res = gatt_server::run(&conn, &server, |e| match e { - ServerEvent::BatteryService(e) => match e { + ServerEvent::Bas(e) => match e { BatteryServiceEvent::BatteryLevelNotificationsEnabled => { info!("battery notifications enabled") } @@ -77,7 +77,7 @@ async fn bluetooth_task(sd: &'static Softdevice) { info!("battery notifications disabled") } }, - ServerEvent::FooService(e) => match e { + ServerEvent::Foo(e) => match e { FooServiceEvent::FooWrite(val) => { info!("wrote foo: {}", val); if let Err(e) = server.foo.foo_notify(&conn, val + 1) { diff --git a/examples/src/bin/ble_peripheral_onoff.rs b/examples/src/bin/ble_peripheral_onoff.rs index 82d0599..067f1d4 100644 --- a/examples/src/bin/ble_peripheral_onoff.rs +++ b/examples/src/bin/ble_peripheral_onoff.rs @@ -62,16 +62,16 @@ async fn run_bluetooth(sd: &'static Softdevice, server: &Server) { info!("advertising done!"); let res = gatt_server::run(&conn, server, |e| match e { - ServerEvent::FooService(FooServiceEvent::FooWrite(val)) => { + ServerEvent::Foo(FooServiceEvent::FooWrite(val)) => { info!("wrote foo level: {}", val); if let Err(e) = server.foo.foo_notify(&conn, val + 1) { info!("send notification error: {:?}", e); } } - ServerEvent::FooService(FooServiceEvent::FooNotificationsEnabled) => { + ServerEvent::Foo(FooServiceEvent::FooNotificationsEnabled) => { info!("notifications enabled") } - ServerEvent::FooService(FooServiceEvent::FooNotificationsDisabled) => { + ServerEvent::Foo(FooServiceEvent::FooNotificationsDisabled) => { info!("notifications disabled") } }) diff --git a/nrf-softdevice-macro/src/lib.rs b/nrf-softdevice-macro/src/lib.rs index 4766954..f78e0e6 100644 --- a/nrf-softdevice-macro/src/lib.rs +++ b/nrf-softdevice-macro/src/lib.rs @@ -78,15 +78,19 @@ pub fn gatt_server(_args: TokenStream, item: TokenStream) -> TokenStream { )); if let syn::Type::Path(p) = &field.ty { + let name_pascal = format_ident!( + "{}", + inflector::cases::pascalcase::to_pascal_case(&name.to_string()) + ); let event_enum_ty = p.path.get_ident().unwrap(); let event_enum_variant = format_ident!("{}Event", event_enum_ty); code_event_enum.extend(quote_spanned!(span=> - #event_enum_ty(#event_enum_variant), + #name_pascal(#event_enum_variant), )); code_on_write.extend(quote_spanned!(span=> if let Some(e) = self.#name.on_write(handle, data) { - return Some(#event_enum_name::#event_enum_ty(e)); + return Some(#event_enum_name::#name_pascal(e)); } )); } -- cgit v1.2.3 From bf4f7a143d38713922d9bd5ff1a983c4c7290c10 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 13 Oct 2021 21:31:44 +0200 Subject: Allow using cortex-m-rt 0.6 or 0.7 --- Cargo.lock | 2 +- nrf-softdevice/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 83526b3..47f9d92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -534,7 +534,7 @@ name = "nrf-softdevice" version = "0.1.0" dependencies = [ "cortex-m 0.7.3", - "cortex-m-rt 0.6.14", + "cortex-m-rt 0.7.0", "critical-section", "defmt", "embassy", diff --git a/nrf-softdevice/Cargo.toml b/nrf-softdevice/Cargo.toml index 1034aad..143e1d0 100644 --- a/nrf-softdevice/Cargo.toml +++ b/nrf-softdevice/Cargo.toml @@ -43,7 +43,7 @@ critical-section = { version = "0.2.1" } num_enum = { version = "0.5.1", default-features = false } embassy = { version = "0.1.0" } cortex-m = "0.7.2" -cortex-m-rt = "0.6.13" +cortex-m-rt = ">=0.6.15,<0.8" heapless = "0.7.1" fixed = "1.5.0" -- cgit v1.2.3