Skip to content

Commit f849485

Browse files
afpinedah2zero
authored andcommitted
Fix NimBLEHIDDevice not being able to create more than one in/out/feature report + temporal coupling (#812)
* Add ".development" to gitignore Arduino IDE requires this file when developing an Arduino library, but that file must not be included in the release. * Fix get Input/Output/Feature Report
1 parent 2879798 commit f849485

File tree

3 files changed

+49
-10
lines changed

3 files changed

+49
-10
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
docs/doxydocs
2+
.development

src/NimBLEHIDDevice.cpp

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -149,14 +149,41 @@ void NimBLEHIDDevice::setBatteryLevel(uint8_t level, bool notify) {
149149
}
150150
} // setBatteryLevel
151151

152+
/**
153+
* @brief Locate the characteristic for a report ID.
154+
*
155+
* @param [in] reportId Report identifier to locate.
156+
* @param [out] reportType Type of report (input/output/feature). Not meaningful if the return value is nullptr.
157+
* @return NimBLECharacteristic* The characteristic.
158+
* @return nullptr If the characteristic does not exist.
159+
*/
160+
NimBLECharacteristic* NimBLEHIDDevice::locateReportCharacteristicById(uint8_t reportId, uint8_t& reportType) {
161+
NimBLECharacteristic* candidate = m_hidSvc->getCharacteristic(inputReportChrUuid, 0);
162+
for (uint16_t i = 1; (candidate != nullptr) && (i != 0); i++) {
163+
NimBLEDescriptor* dsc = candidate->getDescriptorByUUID(featureReportDscUuid);
164+
NimBLEAttValue desc1_val_att = dsc->getValue();
165+
const uint8_t* desc1_val = desc1_val_att.data();
166+
reportType = desc1_val[1];
167+
if (desc1_val[0] == reportId) return candidate;
168+
candidate = m_hidSvc->getCharacteristic(inputReportChrUuid, i);
169+
}
170+
return nullptr;
171+
}
172+
152173
/**
153174
* @brief Get the input report characteristic.
154-
* @param [in] reportId input report ID, the same as in report map for input object related to the characteristic.
155-
* @return A pointer to the input report characteristic.
175+
* @param [in] reportId Input report ID, the same as in report map for input object related to the characteristic.
176+
* @return NimBLECharacteristic* A pointer to the input report characteristic.
177+
* Store this value to avoid computational overhead.
178+
* @return nullptr If the report is already created as an output or feature report.
156179
* @details This will create the characteristic if not already created.
157180
*/
158181
NimBLECharacteristic* NimBLEHIDDevice::getInputReport(uint8_t reportId) {
159-
NimBLECharacteristic* inputReportChr = m_hidSvc->getCharacteristic(inputReportChrUuid);
182+
uint8_t reportType;
183+
NimBLECharacteristic* inputReportChr = locateReportCharacteristicById(reportId, reportType);
184+
if ((inputReportChr != nullptr) && (reportType != 0x01))
185+
// ERROR: this reportId exists, but it is not an input report
186+
return nullptr;
160187
if (inputReportChr == nullptr) {
161188
inputReportChr =
162189
m_hidSvc->createCharacteristic(inputReportChrUuid,
@@ -174,13 +201,17 @@ NimBLECharacteristic* NimBLEHIDDevice::getInputReport(uint8_t reportId) {
174201
/**
175202
* @brief Get the output report characteristic.
176203
* @param [in] reportId Output report ID, the same as in report map for output object related to the characteristic.
177-
* @return A pointer to the output report characteristic.
204+
* @return NimBLECharacteristic* A pointer to the output report characteristic.
205+
* Store this value to avoid computational overhead.
206+
* @return nullptr If the report is already created as an input or feature report.
178207
* @details This will create the characteristic if not already created.
179-
* @note The output report characteristic is optional and should only be created after the input report characteristic.
180208
*/
181209
NimBLECharacteristic* NimBLEHIDDevice::getOutputReport(uint8_t reportId) {
182-
// Same uuid as input so this needs to be the second instance
183-
NimBLECharacteristic* outputReportChr = m_hidSvc->getCharacteristic(inputReportChrUuid, 1);
210+
uint8_t reportType;
211+
NimBLECharacteristic* outputReportChr = locateReportCharacteristicById(reportId, reportType);
212+
if ((outputReportChr != nullptr) && (reportType != 0x02))
213+
// ERROR: this reportId exists, but it is not an output report
214+
return nullptr;
184215
if (outputReportChr == nullptr) {
185216
outputReportChr =
186217
m_hidSvc->createCharacteristic(inputReportChrUuid,
@@ -189,7 +220,6 @@ NimBLECharacteristic* NimBLEHIDDevice::getOutputReport(uint8_t reportId) {
189220
NimBLEDescriptor* outputReportDsc = outputReportChr->createDescriptor(
190221
featureReportDscUuid,
191222
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
192-
193223
uint8_t desc1_val[] = {reportId, 0x02};
194224
outputReportDsc->setValue(desc1_val, 2);
195225
}
@@ -200,11 +230,17 @@ NimBLECharacteristic* NimBLEHIDDevice::getOutputReport(uint8_t reportId) {
200230
/**
201231
* @brief Get the feature report characteristic.
202232
* @param [in] reportId Feature report ID, the same as in report map for feature object related to the characteristic.
203-
* @return A pointer to feature report characteristic.
233+
* @return NimBLECharacteristic* A pointer to feature report characteristic.
234+
* Store this value to avoid computational overhead.
235+
* @return nullptr If the report is already created as an input or output report.
204236
* @details This will create the characteristic if not already created.
205237
*/
206238
NimBLECharacteristic* NimBLEHIDDevice::getFeatureReport(uint8_t reportId) {
207-
NimBLECharacteristic* featureReportChr = m_hidSvc->getCharacteristic(inputReportChrUuid);
239+
uint8_t reportType;
240+
NimBLECharacteristic* featureReportChr = locateReportCharacteristicById(reportId, reportType);
241+
if ((featureReportChr != nullptr) && (reportType != 0x03))
242+
// ERROR: this reportId exists, but it is not a feature report
243+
return nullptr;
208244
if (featureReportChr == nullptr) {
209245
featureReportChr = m_hidSvc->createCharacteristic(
210246
inputReportChrUuid,

src/NimBLEHIDDevice.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ class NimBLEHIDDevice {
8181
NimBLECharacteristic* m_hidControlChr{nullptr}; // 0x2a4c
8282
NimBLECharacteristic* m_protocolModeChr{nullptr}; // 0x2a4e
8383
NimBLECharacteristic* m_batteryLevelChr{nullptr}; // 0x2a19
84+
85+
NimBLECharacteristic* locateReportCharacteristicById(uint8_t reportId, uint8_t& reportType);
8486
};
8587

8688
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)

0 commit comments

Comments
 (0)