From c8b684dd9015c0a0970829cd6e8c3856d1a553b1 Mon Sep 17 00:00:00 2001 From: Andreas Tsouchlos Date: Tue, 30 Sep 2025 10:43:49 +0200 Subject: [PATCH] Add (not yet functional) ble_gatt_server.rs --- src/bin/ble_gatt_server.rs | 162 +++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 src/bin/ble_gatt_server.rs diff --git a/src/bin/ble_gatt_server.rs b/src/bin/ble_gatt_server.rs new file mode 100644 index 0000000..b86d33a --- /dev/null +++ b/src/bin/ble_gatt_server.rs @@ -0,0 +1,162 @@ +#![no_std] +#![no_main] +#![macro_use] + +use defmt_rtt as _; // global logger +use embassy_nrf as _; // time driver +use panic_probe as _; + +use embassy_nrf::interrupt::*; + +use core::mem; + +use defmt::{info, *}; +use embassy_executor::Spawner; +use nrf_softdevice::ble::advertisement_builder::{ + Flag, LegacyAdvertisementBuilder, LegacyAdvertisementPayload, ServiceList, ServiceUuid16, +}; +use nrf_softdevice::ble::{gatt_server, peripheral}; +use nrf_softdevice::{raw, Softdevice}; + +use embassy_nrf::gpio::{Level, Output, OutputDrive}; + +#[embassy_executor::task] +async fn softdevice_task(sd: &'static Softdevice) -> ! { + sd.run().await +} + +#[nrf_softdevice::gatt_service(uuid = "180f")] +struct BatteryService { + #[characteristic(uuid = "2a19", read, notify)] + battery_level: u8, +} + +#[nrf_softdevice::gatt_service(uuid = "9e7312e0-2354-11eb-9f10-fbc30a62cf38")] +struct FooService { + #[characteristic( + uuid = "9e7312e0-2354-11eb-9f10-fbc30a63cf38", + read, + write, + notify, + indicate + )] + foo: u16, +} + +#[nrf_softdevice::gatt_server] +struct Server { + bas: BatteryService, + foo: FooService, +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + info!("Configuring embassy"); + + let mut embassy_config = embassy_nrf::config::Config::default(); + embassy_config.gpiote_interrupt_priority = Priority::P2; + embassy_config.time_interrupt_priority = Priority::P2; + + let p = embassy_nrf::init(embassy_config); + let mut led = Output::new(p.P0_18, Level::Low, OutputDrive::Standard); + led.set_high(); + + info!("Hello World!"); + + // let config = nrf_softdevice::Config { + // clock: Some(raw::nrf_clock_lf_cfg_t { + // source: raw::NRF_CLOCK_LF_SRC_RC as u8, + // rc_ctiv: 16, + // rc_temp_ctiv: 2, + // accuracy: raw::NRF_CLOCK_LF_ACCURACY_500_PPM as u8, + // }), + // conn_gap: Some(raw::ble_gap_conn_cfg_t { + // conn_count: 1, + // event_length: 24, + // }), + // conn_gatt: Some(raw::ble_gatt_conn_cfg_t { att_mtu: 256 }), + // gatts_attr_tab_size: Some(raw::ble_gatts_cfg_attr_tab_size_t { + // attr_tab_size: raw::BLE_GATTS_ATTR_TAB_SIZE_DEFAULT, + // }), + // gap_role_count: Some(raw::ble_gap_cfg_role_count_t { + // adv_set_count: 1, + // periph_role_count: 1, + // // central_role_count: 3, + // // central_sec_count: 0, + // // _bitfield_1: raw::ble_gap_cfg_role_count_t::new_bitfield_1(0), + // }), + // gap_device_name: Some(raw::ble_gap_cfg_device_name_t { + // p_value: b"HelloRust" as *const u8 as _, + // current_len: 9, + // max_len: 9, + // write_perm: unsafe { mem::zeroed() }, + // _bitfield_1: raw::ble_gap_cfg_device_name_t::new_bitfield_1( + // raw::BLE_GATTS_VLOC_STACK as u8, + // ), + // }), + // ..Default::default() + // }; + // + // let sd = Softdevice::enable(&config); + // let server = unwrap!(Server::new(sd)); + // unwrap!(spawner.spawn(softdevice_task(sd))); + // + // static ADV_DATA: LegacyAdvertisementPayload = LegacyAdvertisementBuilder::new() + // .flags(&[Flag::GeneralDiscovery, Flag::LE_Only]) + // .services_16(ServiceList::Complete, &[ServiceUuid16::BATTERY]) + // .full_name("HelloRust") + // .build(); + // + // static SCAN_DATA: LegacyAdvertisementPayload = LegacyAdvertisementBuilder::new() + // .services_128( + // ServiceList::Complete, + // &[0x9e7312e0_2354_11eb_9f10_fbc30a62cf38_u128.to_le_bytes()], + // ) + // .build(); + // + // loop { + // info!("Creating config"); + // let config = peripheral::Config::default(); + // info!("Creating adv object"); + // let adv = peripheral::ConnectableAdvertisement::ScannableUndirected { + // adv_data: &ADV_DATA, + // scan_data: &SCAN_DATA, + // }; + // info!("Starting advertising"); + // let conn = unwrap!(peripheral::advertise_connectable(sd, adv, &config).await); + // + // info!("advertising done!"); + // + // // Run the GATT server on the connection. This returns when the connection gets disconnected. + // // + // // Event enums (ServerEvent's) are generated by nrf_softdevice::gatt_server + // // proc macro when applied to the Server struct above + // let e = gatt_server::run(&conn, &server, |e| match e { + // ServerEvent::Bas(e) => match e { + // BatteryServiceEvent::BatteryLevelCccdWrite { notifications } => { + // info!("battery notifications: {}", notifications) + // } + // }, + // ServerEvent::Foo(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); + // } + // } + // FooServiceEvent::FooCccdWrite { + // indications, + // notifications, + // } => { + // info!( + // "foo indications: {}, notifications: {}", + // indications, notifications + // ) + // } + // }, + // }) + // .await; + // + // info!("gatt_server run exited with error: {:?}", e); + // } +}