diff --git a/src/ble.rs b/src/ble.rs index b5a11fc..ff5f22d 100644 --- a/src/ble.rs +++ b/src/ble.rs @@ -39,67 +39,16 @@ pub enum BleSendable { SpatemRaw(io::msg::RawMsgRx), } -// GAP + 4 GATT attributes + our service(s) -const _ATTRIBUTE_TABLE_SIZE: usize = GAP_SERVICE_ATTRIBUTE_COUNT + 4 + CITSEvents::ATTRIBUTE_COUNT; - -pub struct Server<'values> { - server: AttributeServer< - 'values, - embassy_sync::blocking_mutex::raw::NoopRawMutex, - DefaultPacketPool, - _ATTRIBUTE_TABLE_SIZE, - 1, - CONNECTIONS_MAX, - >, +#[gatt_server] +struct Server { + generic: Generic, c_its_events: CITSEvents, } -impl<'values> Server<'values> { - // we implement this ourselves to add the "SERVICE_CHANGED" GATT characteristic, - // otherwise client devices won't update the service's characteristics when they change. - fn new_with_config(config: PeripheralConfig<'values>) -> Result { - let mut table: AttributeTable< - '_, - embassy_sync::blocking_mutex::raw::NoopRawMutex, - _ATTRIBUTE_TABLE_SIZE, - > = AttributeTable::new(); - - // manual implementation of: gap.build(&mut table)?; - if !config.name.is_ascii() || config.name.len() > 22 { - return Err("Device name is too long. Max length is 22 bytes"); - } - - let mut gap_builder = table.add_service(Service::new(service::GAP)); - gap_builder.add_characteristic_ro(characteristic::DEVICE_NAME, config.name.as_bytes()); - gap_builder.add_characteristic_ro(characteristic::APPEARANCE, config.appearance); - gap_builder.build(); - - // add custom GATT service - let mut gatt_builder = table.add_service(Service::new(service::GATT)); - gatt_builder.add_characteristic_ro(characteristic::SERVICE_CHANGED, &[1, 0, 255, 255]); // [0x0001, 0xFFFF] in little-endian - gatt_builder.build(); - - let c_its_events = CITSEvents::new(&mut table); - - Ok(Self { - server: AttributeServer::new(table), - c_its_events, - }) - } -} - -impl<'values> core::ops::Deref for Server<'values> { - type Target = AttributeServer< - 'values, - embassy_sync::blocking_mutex::raw::NoopRawMutex, - DefaultPacketPool, - _ATTRIBUTE_TABLE_SIZE, - 1, - CONNECTIONS_MAX, - >; - fn deref(&self) -> &Self::Target { - &self.server - } +#[gatt_service(uuid = "1801")] +pub(crate) struct Generic { + #[characteristic(uuid = characteristic::SERVICE_CHANGED, indicate, read, value = 0x0100FFFF)] + service_changed: u32, } #[gatt_service(uuid = "c0b70000-d4f4-4000-ada8-f99a02ee315c")] @@ -114,7 +63,7 @@ struct CITSEvents { raw_notify: [u8; io::msg::RawNotify::PROTO_SIZE], #[cfg(feature = "cam")] - // #[descriptor(uuid = descriptors::MEASUREMENT_DESCRIPTION, name = "CAM", read, value = "RawMsgRx proto msg", type = &'static str)] + #[descriptor(uuid = descriptors::MEASUREMENT_DESCRIPTION, name = "CAM", read, value = "RawMsgRx proto msg", type = &'static str)] #[characteristic(uuid = "c0b70001-d4f4-4003-ada8-f99a02ee315c", read, value = [0u8; io::msg::RawMsgRx::PROTO_SIZE])] cam_raw: [u8; io::msg::RawMsgRx::PROTO_SIZE], #[cfg(feature = "cam")] @@ -123,7 +72,7 @@ struct CITSEvents { cam_event: [u8; io::msg::CamEvent::PROTO_SIZE], #[cfg(feature = "denm")] - // #[descriptor(uuid = descriptors::MEASUREMENT_DESCRIPTION, name = "DENM", read, value = "RawMsgRx proto msg", type = &'static str)] + #[descriptor(uuid = descriptors::MEASUREMENT_DESCRIPTION, name = "DENM", read, value = "RawMsgRx proto msg", type = &'static str)] #[characteristic(uuid = "c0b70001-d4f4-4005-ada8-f99a02ee315c", read, value = [0u8; io::msg::RawMsgRx::PROTO_SIZE])] denm_raw: [u8; io::msg::RawMsgRx::PROTO_SIZE], #[cfg(feature = "denm")] @@ -132,11 +81,11 @@ struct CITSEvents { denm_event: [u8; io::msg::DenmEvent::PROTO_SIZE], #[cfg(feature = "spat")] - // #[descriptor(uuid = descriptors::MEASUREMENT_DESCRIPTION, name = "MAPEM", read, value = "RawMsgRx proto msg", type = &'static str)] + #[descriptor(uuid = descriptors::MEASUREMENT_DESCRIPTION, name = "MAPEM", read, value = "RawMsgRx proto msg", type = &'static str)] #[characteristic(uuid = "c0b70001-d4f4-4007-ada8-f99a02ee315c", read, value = [0u8; io::msg::RawMsgRx::PROTO_SIZE])] mapem_raw: [u8; io::msg::RawMsgRx::PROTO_SIZE], #[cfg(feature = "spat")] - // #[descriptor(uuid = descriptors::MEASUREMENT_DESCRIPTION, name = "SPATEM", read, value = "RawMsgRx proto msg", type = &'static str)] + #[descriptor(uuid = descriptors::MEASUREMENT_DESCRIPTION, name = "SPATEM", read, value = "RawMsgRx proto msg", type = &'static str)] #[characteristic(uuid = "c0b70001-d4f4-4008-ada8-f99a02ee315c", read, value = [0u8; io::msg::RawMsgRx::PROTO_SIZE])] spatem_raw: [u8; io::msg::RawMsgRx::PROTO_SIZE], } @@ -167,7 +116,6 @@ pub async fn run( esp_radio::ble::controller::BleConnector<'static>, CONTROLLER_SLOTS, >, - name: alloc::string::String, ) { let mut resources: HostResources = HostResources::new(); @@ -193,18 +141,23 @@ pub async fn run( "Starting advertising and GATT service for {}", features.join(",") ); - let server = Server::new_with_config(PeripheralConfig { - name: &name, - appearance: &appearance::UNKNOWN, // maybe appearance::outdoor_sports_activity::LOCATION_AND_NAVIGATION_DISPLAY ? - }) + let server = Server::new_with_config(GapConfig::Peripheral(PeripheralConfig { + name: "ESP32 C-ITS", + appearance: &appearance::UNKNOWN, // TODO MESH_DEVICE?? outdoor_sports_activity::LOCATION_AND_NAVIGATION_DISPLAY + })) .unwrap(); + let handle_start = 0x0100_u16; // little-endian + let handle_end = 0xFFFF_u16; + let concatenated: u32 = ((handle_start as u32) << 16) | handle_end as u32; + info!("Concatenated: {concatenated:?}"); + let test = server.set(&server.generic.service_changed, &concatenated); + info!("We were able to set service changed? {test:?}"); + let _ = embassy_futures::join::join(ble_task(runner), async { loop { match advertise(&mut peripheral, &server).await { Ok(conn) => { - info!("BLE: New client connected"); - // set up tasks when the connection is established to a central, so they don't run when no one is connected. let a = gatt_events_task(&server, &conn); let b = publishing_task(&server, &conn); @@ -247,7 +200,7 @@ async fn advertise<'values, 'server, C: Controller>( server: &'server Server<'values>, ) -> Result, BleHostError> { let mut advertiser_data = [0; 35]; - let service_uuid = Uuid::from(0xc0b7_0000_d4f4_4000_ada8_f99a_02ee_315c_u128) + let service_uuid = Uuid::from(0xc0b70000d4f44000ada8f99a02ee315cu128) .as_raw() .try_into() .unwrap(); @@ -255,6 +208,7 @@ async fn advertise<'values, 'server, C: Controller>( &[ AdStructure::Flags(LE_GENERAL_DISCOVERABLE | BR_EDR_NOT_SUPPORTED), AdStructure::ServiceUuids128(&[service_uuid]), + AdStructure::ServiceUuids16(&[service::GATT.to_le_bytes()]), ], &mut advertiser_data[..], )?; diff --git a/src/main.rs b/src/main.rs index 9ed637c..d69a9ba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -219,14 +219,7 @@ async fn main(spawner: Spawner) -> ! { #[cfg(feature = "ble")] { let controller = ble::make_controller(peripherals.BT); - let serial = &mac.as_bytes()[4..7]; - let name = alloc::format!( - "ESP32 C-ITS {:02x}{:02x}{:02x}", - serial[0], - serial[1], - serial[2] - ); - spawner.spawn(ble::run(controller, name).expect("Failed to spawn BLE task")); + spawner.spawn(ble::run(controller).expect("Failed to spawn BLE task")); } // Setup GNSS: