1use embassy_sync::blocking_mutex::raw::RawMutex;
11use heapless::String;
12use static_cell::StaticCell;
13
14use crate::prelude::*;
15
16const DEVICE_NAME_MAX_LENGTH: usize = 22;
18
19#[cfg(not(feature = "security"))]
28pub const GAP_SERVICE_ATTRIBUTE_COUNT: usize = 6;
29#[cfg(all(feature = "security", feature = "central"))]
31pub const GAP_SERVICE_ATTRIBUTE_COUNT: usize = 8;
32
33pub enum GapConfig<'a> {
35 Peripheral(PeripheralConfig<'a>),
37 Central(CentralConfig<'a>),
39}
40
41pub struct PeripheralConfig<'a> {
43 pub name: &'a str,
45 pub appearance: &'a BluetoothUuid16,
49 }
52
53pub struct CentralConfig<'a> {
55 pub name: &'a str,
57 pub appearance: &'a BluetoothUuid16,
61 }
63
64impl<'a> GapConfig<'a> {
65 pub fn default(name: &'a str) -> Self {
69 GapConfig::Peripheral(PeripheralConfig {
70 name,
71 appearance: &appearance::UNKNOWN,
72 })
73 }
74
75 pub fn build<M: RawMutex, const MAX: usize>(
77 self,
78 table: &mut AttributeTable<'a, M, MAX>,
79 ) -> Result<(), &'static str> {
80 match self {
81 GapConfig::Peripheral(config) => config.build(table),
82 GapConfig::Central(config) => config.build(table),
83 }
84 }
85}
86
87impl<'a> PeripheralConfig<'a> {
88 fn build<M: RawMutex, const MAX: usize>(self, table: &mut AttributeTable<'a, M, MAX>) -> Result<(), &'static str> {
90 static PERIPHERAL_NAME: StaticCell<String<DEVICE_NAME_MAX_LENGTH>> = StaticCell::new();
91 let peripheral_name = PERIPHERAL_NAME.init(String::new());
92 peripheral_name
93 .push_str(self.name)
94 .map_err(|_| "Device name is too long. Max length is 22 bytes")?;
95
96 let mut gap_builder = table.add_service(Service::new(service::GAP));
97 gap_builder.add_characteristic_ro(characteristic::DEVICE_NAME, peripheral_name);
98 gap_builder.add_characteristic_ro(characteristic::APPEARANCE, self.appearance);
99 #[cfg(all(feature = "security", feature = "central"))]
100 gap_builder.add_characteristic_ro(characteristic::CENTRAL_ADDRESS_RESOLUTION, &1u8);
101 gap_builder.build();
102
103 table.add_service(Service::new(service::GATT));
104
105 Ok(())
106 }
107}
108
109impl<'a> CentralConfig<'a> {
110 fn build<M: RawMutex, const MAX: usize>(self, table: &mut AttributeTable<'a, M, MAX>) -> Result<(), &'static str> {
112 static CENTRAL_NAME: StaticCell<String<DEVICE_NAME_MAX_LENGTH>> = StaticCell::new();
113 let central_name = CENTRAL_NAME.init(String::new());
114 central_name
115 .push_str(self.name)
116 .map_err(|_| "Device name is too long. Max length is 22 bytes")?;
117
118 let mut gap_builder = table.add_service(Service::new(service::GAP));
119 gap_builder.add_characteristic_ro(characteristic::DEVICE_NAME, central_name);
120 gap_builder.add_characteristic_ro(characteristic::APPEARANCE, self.appearance);
121 #[cfg(all(feature = "security", feature = "central"))]
122 gap_builder.add_characteristic_ro(characteristic::CENTRAL_ADDRESS_RESOLUTION, &1u8);
123 gap_builder.build();
124
125 table.add_service(Service::new(service::GATT));
126
127 Ok(())
128 }
129}