Skip to content

Commit 8e84d34

Browse files
authored
feat(hid_service): Update to store / reuse report characteristics (#356)
* feat(hid_service): Update to store / reuse report characteristics * fix sa * update example and add removal functions
1 parent b3c0d2d commit 8e84d34

File tree

2 files changed

+117
-2
lines changed

2 files changed

+117
-2
lines changed

components/hid_service/example/main/hid_service_example.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ extern "C" void app_main(void) {
106106
hid_service.set_report_map(descriptor);
107107

108108
// use the HID service to make an input report characteristic
109-
auto input_report = hid_service.input_report(input_report_id);
109+
[[maybe_unused]] auto input_report = hid_service.input_report(input_report_id);
110110

111111
// use the HID service to make an output report characteristic
112112
[[maybe_unused]] auto output_report = hid_service.output_report(output_report_id);
@@ -217,7 +217,11 @@ extern "C" void app_main(void) {
217217
// send an input report
218218
auto report = gamepad_input_report.get_report();
219219
logger.debug("Sending report data ({}): {::#02x}", report.size(), report);
220-
input_report->notify(report);
220+
221+
// Get the stored pointer (we could use the one above, but this is just to
222+
// show how to get it)
223+
auto report_char = hid_service.input_report(input_report_id);
224+
report_char->notify(report);
221225

222226
// sleep
223227
std::this_thread::sleep_until(start + 1s);

components/hid_service/include/hid_service.hpp

+111
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,17 @@ class HidService : public espp::BaseComponent {
150150
/// is related to the characteristic.
151151
/// @return The input report characteristic.
152152
NimBLECharacteristic *input_report(uint8_t report_id) {
153+
std::lock_guard<std::mutex> lock(input_report_characteristics_mutex_);
154+
155+
// look up the report ID in the list of input report characteristics
156+
for (const auto &report_char : input_report_characteristics_) {
157+
// cppcheck-suppress useStlAlgorithm
158+
if (report_char.first == report_id) {
159+
return report_char.second;
160+
}
161+
}
162+
163+
// we got here, so the report ID was not found
153164
auto input_report_char = service_->createCharacteristic(
154165
NimBLEUUID(REPORT_UUID),
155166
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ_ENC);
@@ -160,15 +171,49 @@ class HidService : public espp::BaseComponent {
160171
uint8_t desc_value[] = {report_id, 0x01};
161172
desc->setValue(desc_value, sizeof(desc_value));
162173

174+
// now add the report ID to the list of input report characteristics
175+
input_report_characteristics_.emplace_back(report_id, input_report_char);
176+
163177
return input_report_char;
164178
}
165179

180+
/// @brief Remove an input report characteristic.
181+
/// @param report_id The report ID of the input report characteristic to
182+
/// remove.
183+
/// @note This will delete the characteristic, and remove it from the list.
184+
/// Any stored pointers to the characteristic will be invalid after this
185+
/// call.
186+
void remove_input_report(uint8_t report_id) {
187+
std::lock_guard<std::mutex> lock(input_report_characteristics_mutex_);
188+
auto it =
189+
std::find_if(input_report_characteristics_.begin(), input_report_characteristics_.end(),
190+
[report_id](const ReportCharacteristic &report_char) {
191+
return report_char.first == report_id;
192+
});
193+
if (it != input_report_characteristics_.end()) {
194+
static constexpr bool delete_char = true;
195+
service_->removeCharacteristic(it->second, delete_char);
196+
input_report_characteristics_.erase(it);
197+
}
198+
}
199+
166200
/// @brief Create an output report characteristic.
167201
/// @param report_id The report ID. This should be the same as the report
168202
/// ID in the report descriptor for the output object that
169203
/// is related to the characteristic.
170204
/// @return The output report characteristic.
171205
NimBLECharacteristic *output_report(uint8_t report_id) {
206+
std::lock_guard<std::mutex> lock(output_report_characteristics_mutex_);
207+
208+
// look up the report ID in the list of output report characteristics
209+
for (const auto &report_char : output_report_characteristics_) {
210+
// cppcheck-suppress useStlAlgorithm
211+
if (report_char.first == report_id) {
212+
return report_char.second;
213+
}
214+
}
215+
216+
// we got here, so the report ID was not found
172217
auto output_report_char = service_->createCharacteristic(
173218
NimBLEUUID(REPORT_UUID), NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE |
174219
NIMBLE_PROPERTY::WRITE_NR | NIMBLE_PROPERTY::READ_ENC |
@@ -182,15 +227,49 @@ class HidService : public espp::BaseComponent {
182227
uint8_t desc_value[] = {report_id, 0x02};
183228
desc->setValue(desc_value, sizeof(desc_value));
184229

230+
// now add the report ID to the list of output report characteristics
231+
output_report_characteristics_.emplace_back(report_id, output_report_char);
232+
185233
return output_report_char;
186234
}
187235

236+
/// @brief Remove an output report characteristic.
237+
/// @param report_id The report ID of the output report characteristic to
238+
/// remove.
239+
/// @note This will delete the characteristic, and remove it from the list.
240+
/// Any stored pointers to the characteristic will be invalid after this
241+
/// call.
242+
void remove_output_report(uint8_t report_id) {
243+
std::lock_guard<std::mutex> lock(output_report_characteristics_mutex_);
244+
auto it =
245+
std::find_if(output_report_characteristics_.begin(), output_report_characteristics_.end(),
246+
[report_id](const ReportCharacteristic &report_char) {
247+
return report_char.first == report_id;
248+
});
249+
if (it != output_report_characteristics_.end()) {
250+
static constexpr bool delete_char = true;
251+
service_->removeCharacteristic(it->second, delete_char);
252+
output_report_characteristics_.erase(it);
253+
}
254+
}
255+
188256
/// @brief Create a feature report characteristic.
189257
/// @param report_id The report ID. This should be the same as the report
190258
/// ID in the report descriptor for the feature object that
191259
/// is related to the characteristic.
192260
/// @return The feature report characteristic.
193261
NimBLECharacteristic *feature_report(uint8_t report_id) {
262+
std::lock_guard<std::mutex> lock(feature_report_characteristics_mutex_);
263+
264+
// look up the report ID in the list of feature report characteristics
265+
for (const auto &report_char : feature_report_characteristics_) {
266+
// cppcheck-suppress useStlAlgorithm
267+
if (report_char.first == report_id) {
268+
return report_char.second;
269+
}
270+
}
271+
272+
// we got here, so the report ID was not found
194273
auto feature_report_char = service_->createCharacteristic(
195274
NimBLEUUID(REPORT_UUID), NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE |
196275
NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
@@ -203,9 +282,32 @@ class HidService : public espp::BaseComponent {
203282
uint8_t desc_value[] = {report_id, 0x03};
204283
desc->setValue(desc_value, sizeof(desc_value));
205284

285+
// now add the report ID to the list of feature report characteristics
286+
feature_report_characteristics_.emplace_back(report_id, feature_report_char);
287+
206288
return feature_report_char;
207289
}
208290

291+
/// @brief Remove a feature report characteristic.
292+
/// @param report_id The report ID of the feature report characteristic to
293+
/// remove.
294+
/// @note This will delete the characteristic, and remove it from the list.
295+
/// Any stored pointers to the characteristic will be invalid after this
296+
/// call.
297+
void remove_feature_report(uint8_t report_id) {
298+
std::lock_guard<std::mutex> lock(feature_report_characteristics_mutex_);
299+
auto it =
300+
std::find_if(feature_report_characteristics_.begin(), feature_report_characteristics_.end(),
301+
[report_id](const ReportCharacteristic &report_char) {
302+
return report_char.first == report_id;
303+
});
304+
if (it != feature_report_characteristics_.end()) {
305+
static constexpr bool delete_char = true;
306+
service_->removeCharacteristic(it->second, delete_char);
307+
feature_report_characteristics_.erase(it);
308+
}
309+
}
310+
209311
protected:
210312
static constexpr uint16_t SERVICE_UUID = 0x1812;
211313
static constexpr uint16_t HID_INFORMATION_UUID = 0x2a4a;
@@ -238,6 +340,15 @@ class HidService : public espp::BaseComponent {
238340
protocol_mode_->setValue(pMode, 1);
239341
}
240342

343+
typedef std::pair<uint8_t, NimBLECharacteristic *> ReportCharacteristic;
344+
345+
std::mutex input_report_characteristics_mutex_;
346+
std::vector<ReportCharacteristic> input_report_characteristics_;
347+
std::mutex output_report_characteristics_mutex_;
348+
std::vector<ReportCharacteristic> output_report_characteristics_;
349+
std::mutex feature_report_characteristics_mutex_;
350+
std::vector<ReportCharacteristic> feature_report_characteristics_;
351+
241352
NimBLEService *service_{nullptr};
242353
NimBLECharacteristic *hid_info_{nullptr}; // 0x2a4a
243354
NimBLECharacteristic *report_map_{nullptr}; // 0x2a4b

0 commit comments

Comments
 (0)