@@ -149,14 +149,41 @@ void NimBLEHIDDevice::setBatteryLevel(uint8_t level, bool notify) {
149
149
}
150
150
} // setBatteryLevel
151
151
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
+
152
173
/* *
153
174
* @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.
156
179
* @details This will create the characteristic if not already created.
157
180
*/
158
181
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 ;
160
187
if (inputReportChr == nullptr ) {
161
188
inputReportChr =
162
189
m_hidSvc->createCharacteristic (inputReportChrUuid,
@@ -174,13 +201,17 @@ NimBLECharacteristic* NimBLEHIDDevice::getInputReport(uint8_t reportId) {
174
201
/* *
175
202
* @brief Get the output report characteristic.
176
203
* @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.
178
207
* @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.
180
208
*/
181
209
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 ;
184
215
if (outputReportChr == nullptr ) {
185
216
outputReportChr =
186
217
m_hidSvc->createCharacteristic (inputReportChrUuid,
@@ -189,7 +220,6 @@ NimBLECharacteristic* NimBLEHIDDevice::getOutputReport(uint8_t reportId) {
189
220
NimBLEDescriptor* outputReportDsc = outputReportChr->createDescriptor (
190
221
featureReportDscUuid,
191
222
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
192
-
193
223
uint8_t desc1_val[] = {reportId, 0x02 };
194
224
outputReportDsc->setValue (desc1_val, 2 );
195
225
}
@@ -200,11 +230,17 @@ NimBLECharacteristic* NimBLEHIDDevice::getOutputReport(uint8_t reportId) {
200
230
/* *
201
231
* @brief Get the feature report characteristic.
202
232
* @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.
204
236
* @details This will create the characteristic if not already created.
205
237
*/
206
238
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 ;
208
244
if (featureReportChr == nullptr ) {
209
245
featureReportChr = m_hidSvc->createCharacteristic (
210
246
inputReportChrUuid,
0 commit comments