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. --- nrf-softdevice-macro/src/lib.rs | 97 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 92 insertions(+), 5 deletions(-) (limited to 'nrf-softdevice-macro') 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 } -- cgit v1.2.3