esp32_nimble/server/
ble_hid_device.rs

1use alloc::sync::Arc;
2
3use crate::{
4    BLECharacteristic, BLEServer, BLEService, DescriptorProperties, NimbleProperties,
5    cpfd::*,
6    utilities::{BleUuid, mutex::Mutex},
7};
8
9const BLE_SVC_DIS_CHR_UUID16_MANUFACTURER_NAME: BleUuid = BleUuid::from_uuid16(0x2A29);
10const BLE_SVC_BAS_UUID16: BleUuid = BleUuid::from_uuid16(0x180F);
11const BLE_SVC_BAS_CHR_UUID16_BATTERY_LEVEL: BleUuid = BleUuid::from_uuid16(0x2A19);
12
13#[allow(dead_code)]
14pub struct BLEHIDDevice {
15    device_info_service: Arc<Mutex<BLEService>>,
16    pnp_characteristic: Arc<Mutex<BLECharacteristic>>,
17    manufacturer_characteristic: Option<Arc<Mutex<BLECharacteristic>>>,
18
19    hid_service: Arc<Mutex<BLEService>>,
20    hid_info_characteristic: Arc<Mutex<BLECharacteristic>>,
21    report_map_characteristic: Arc<Mutex<BLECharacteristic>>,
22    hid_control_characteristic: Arc<Mutex<BLECharacteristic>>,
23    protocol_mode_characteristic: Arc<Mutex<BLECharacteristic>>,
24
25    battery_service: Arc<Mutex<BLEService>>,
26    battery_level_characteristic: Arc<Mutex<BLECharacteristic>>,
27}
28
29impl BLEHIDDevice {
30    pub fn new(server: &mut BLEServer) -> Self {
31        let device_info_service = server.create_service(BleUuid::from_uuid16(0x180a));
32
33        let pnp_characteristic = device_info_service
34            .lock()
35            .create_characteristic(BleUuid::from_uuid16(0x2a50), NimbleProperties::READ);
36
37        let hid_service = server.create_service(BleUuid::from_uuid16(0x1812));
38
39        let hid_info_characteristic = hid_service
40            .lock()
41            .create_characteristic(BleUuid::Uuid16(0x2a4a), NimbleProperties::READ);
42        let report_map_characteristic = hid_service
43            .lock()
44            .create_characteristic(BleUuid::Uuid16(0x2a4b), NimbleProperties::READ);
45        let hid_control_characteristic = hid_service
46            .lock()
47            .create_characteristic(BleUuid::Uuid16(0x2a4c), NimbleProperties::WRITE_NO_RSP);
48        let protocol_mode_characteristic = hid_service.lock().create_characteristic(
49            BleUuid::Uuid16(0x2a4e),
50            NimbleProperties::WRITE_NO_RSP | NimbleProperties::READ,
51        );
52
53        let battery_service = server.create_service(BLE_SVC_BAS_UUID16);
54        let battery_level_characteristic = battery_service.lock().create_characteristic(
55            BLE_SVC_BAS_CHR_UUID16_BATTERY_LEVEL,
56            NimbleProperties::READ | NimbleProperties::NOTIFY,
57        );
58        battery_level_characteristic.lock().cpfd(Cpfd {
59            format: ChrFormat::Uint8,
60            exponent: 0,
61            unit: ChrUnit::Percentage,
62            name_space: 1,
63            description: 0,
64        });
65
66        Self {
67            device_info_service,
68            pnp_characteristic,
69            manufacturer_characteristic: None,
70            hid_service,
71            hid_info_characteristic,
72            report_map_characteristic,
73            hid_control_characteristic,
74            protocol_mode_characteristic,
75            battery_service,
76            battery_level_characteristic,
77        }
78    }
79
80    /// Sets the Plug n Play characteristic value.
81    pub fn report_map(&mut self, map: &[u8]) {
82        self.report_map_characteristic.lock().set_value(map);
83    }
84
85    pub fn manufacturer(&mut self, name: &str) {
86        let chr = self.manufacturer_characteristic.get_or_insert_with(|| {
87            self.device_info_service.lock().create_characteristic(
88                BLE_SVC_DIS_CHR_UUID16_MANUFACTURER_NAME,
89                NimbleProperties::READ,
90            )
91        });
92        chr.lock().set_value(name.as_bytes());
93    }
94
95    pub fn pnp(&mut self, sig: u8, vid: u16, pid: u16, version: u16) {
96        let mut pnp_characteristic = self.pnp_characteristic.lock();
97        let value = pnp_characteristic.value_mut();
98        value.clear();
99        value.extend(&[sig]);
100        value.extend(&vid.to_be_bytes());
101        value.extend(&pid.to_be_bytes());
102        value.extend(&version.to_be_bytes());
103    }
104
105    /// Sets the HID Information characteristic value.1
106    pub fn hid_info(&mut self, country: u8, flags: u8) {
107        let info = [0x11, 0x1, country, flags];
108        self.hid_info_characteristic.lock().set_value(&info);
109    }
110
111    /// Create input report characteristic
112    pub fn input_report(&mut self, report_id: u8) -> Arc<Mutex<BLECharacteristic>> {
113        let input_report_characteristic = self.hid_service.lock().create_characteristic(
114            BleUuid::from_uuid16(0x2a4d),
115            NimbleProperties::READ | NimbleProperties::NOTIFY | NimbleProperties::READ_ENC,
116        );
117        let input_report_descriptor = input_report_characteristic.lock().create_descriptor(
118            BleUuid::Uuid16(0x2908),
119            DescriptorProperties::READ | DescriptorProperties::READ_ENC,
120        );
121
122        let desc1_val = [report_id, 0x01];
123        input_report_descriptor.lock().set_value(&desc1_val);
124
125        input_report_characteristic
126    }
127
128    pub fn output_report(&mut self, report_id: u8) -> Arc<Mutex<BLECharacteristic>> {
129        let output_report_characteristic = self.hid_service.lock().create_characteristic(
130            BleUuid::from_uuid16(0x2a4d),
131            NimbleProperties::READ
132                | NimbleProperties::WRITE
133                | NimbleProperties::WRITE_NO_RSP
134                | NimbleProperties::READ_ENC
135                | NimbleProperties::WRITE_ENC,
136        );
137        let output_report_descriptor = output_report_characteristic.lock().create_descriptor(
138            BleUuid::Uuid16(0x2908),
139            DescriptorProperties::READ
140                | DescriptorProperties::WRITE
141                | DescriptorProperties::READ_ENC
142                | DescriptorProperties::WRITE_ENC,
143        );
144
145        let desc1_val = [report_id, 0x02];
146        output_report_descriptor.lock().set_value(&desc1_val);
147
148        output_report_characteristic
149    }
150
151    pub fn feature_report(&mut self, report_id: u8) -> Arc<Mutex<BLECharacteristic>> {
152        let feature_report_characteristic = self.hid_service.lock().create_characteristic(
153            BleUuid::from_uuid16(0x2a4d),
154            NimbleProperties::READ
155                | NimbleProperties::WRITE
156                | NimbleProperties::READ_ENC
157                | NimbleProperties::WRITE_ENC,
158        );
159        let feature_report_descriptor = feature_report_characteristic.lock().create_descriptor(
160            BleUuid::Uuid16(0x2908),
161            DescriptorProperties::READ
162                | DescriptorProperties::WRITE
163                | DescriptorProperties::READ_ENC
164                | DescriptorProperties::WRITE_ENC,
165        );
166
167        let desc1_val = [report_id, 0x03];
168        feature_report_descriptor.lock().set_value(&desc1_val);
169
170        feature_report_characteristic
171    }
172
173    /// Creates a keyboard boot input report characteristic
174    pub fn boot_input(&self) -> Arc<Mutex<BLECharacteristic>> {
175        self.hid_service
176            .lock()
177            .create_characteristic(BleUuid::from_uuid16(0x2a22), NimbleProperties::NOTIFY)
178    }
179
180    /// Creates a keyboard boot input report characteristic
181    pub fn boot_output(&self) -> Arc<Mutex<BLECharacteristic>> {
182        self.hid_service.lock().create_characteristic(
183            BleUuid::from_uuid16(0x2a32),
184            NimbleProperties::READ | NimbleProperties::WRITE | NimbleProperties::WRITE_NO_RSP,
185        )
186    }
187
188    /// Returns the HID control point characteristic.
189    pub fn hid_control(&self) -> &Arc<Mutex<BLECharacteristic>> {
190        &self.hid_control_characteristic
191    }
192
193    /// Returns the protocol mode characteristic.
194    pub fn protocol_mode(&self) -> &Arc<Mutex<BLECharacteristic>> {
195        &self.protocol_mode_characteristic
196    }
197
198    /// Set the battery level characteristic value.
199    pub fn set_battery_level(&mut self, level: u8) {
200        self.battery_level_characteristic.lock().set_value(&[level]);
201    }
202
203    /// Returns a pointer to the HID service.
204    pub fn hid_service(&self) -> &Arc<Mutex<BLEService>> {
205        &self.hid_service
206    }
207}