Allow the same report ID in multiple input/output/feature reports

This commit is contained in:
afpineda 2025-01-03 13:01:45 +01:00 committed by h2zero
parent ad12a48e9e
commit aae70dfd21
2 changed files with 8 additions and 24 deletions

View file

@ -150,21 +150,20 @@ void NimBLEHIDDevice::setBatteryLevel(uint8_t level, bool notify) {
} // setBatteryLevel } // setBatteryLevel
/** /**
* @brief Locate the characteristic for a report ID. * @brief Locate the characteristic for a report ID and a report type.
* *
* @param [in] reportId Report identifier to locate. * @param [in] reportId Report identifier to locate.
* @param [out] reportType Type of report (input/output/feature). Not meaningful if the return value is nullptr. * @param [in] reportType Type of report (input/output/feature).
* @return NimBLECharacteristic* The characteristic. * @return NimBLECharacteristic* The characteristic.
* @return nullptr If the characteristic does not exist. * @return nullptr If the characteristic does not exist.
*/ */
NimBLECharacteristic* NimBLEHIDDevice::locateReportCharacteristicById(uint8_t reportId, uint8_t& reportType) { NimBLECharacteristic* NimBLEHIDDevice::locateReportCharacteristicByIdAndType(uint8_t reportId, uint8_t reportType) {
NimBLECharacteristic* candidate = m_hidSvc->getCharacteristic(inputReportChrUuid, 0); NimBLECharacteristic* candidate = m_hidSvc->getCharacteristic(inputReportChrUuid, 0);
for (uint16_t i = 1; (candidate != nullptr) && (i != 0); i++) { for (uint16_t i = 1; (candidate != nullptr) && (i != 0); i++) {
NimBLEDescriptor* dsc = candidate->getDescriptorByUUID(featureReportDscUuid); NimBLEDescriptor* dsc = candidate->getDescriptorByUUID(featureReportDscUuid);
NimBLEAttValue desc1_val_att = dsc->getValue(); NimBLEAttValue desc1_val_att = dsc->getValue();
const uint8_t* desc1_val = desc1_val_att.data(); const uint8_t* desc1_val = desc1_val_att.data();
reportType = desc1_val[1]; if ((desc1_val[0] == reportId) && (desc1_val[1] == reportType)) return candidate;
if (desc1_val[0] == reportId) return candidate;
candidate = m_hidSvc->getCharacteristic(inputReportChrUuid, i); candidate = m_hidSvc->getCharacteristic(inputReportChrUuid, i);
} }
return nullptr; return nullptr;
@ -175,15 +174,10 @@ NimBLECharacteristic* NimBLEHIDDevice::locateReportCharacteristicById(uint8_t re
* @param [in] reportId Input report ID, the same as in report map for input object related to the characteristic. * @param [in] reportId Input report ID, the same as in report map for input object related to the characteristic.
* @return NimBLECharacteristic* A pointer to the input report characteristic. * @return NimBLECharacteristic* A pointer to the input report characteristic.
* Store this value to avoid computational overhead. * Store this value to avoid computational overhead.
* @return nullptr If the report is already created as an output or feature report.
* @details This will create the characteristic if not already created. * @details This will create the characteristic if not already created.
*/ */
NimBLECharacteristic* NimBLEHIDDevice::getInputReport(uint8_t reportId) { NimBLECharacteristic* NimBLEHIDDevice::getInputReport(uint8_t reportId) {
uint8_t reportType; NimBLECharacteristic* inputReportChr = locateReportCharacteristicByIdAndType(reportId, 0x01);
NimBLECharacteristic* inputReportChr = locateReportCharacteristicById(reportId, reportType);
if ((inputReportChr != nullptr) && (reportType != 0x01))
// ERROR: this reportId exists, but it is not an input report
return nullptr;
if (inputReportChr == nullptr) { if (inputReportChr == nullptr) {
inputReportChr = inputReportChr =
m_hidSvc->createCharacteristic(inputReportChrUuid, m_hidSvc->createCharacteristic(inputReportChrUuid,
@ -203,15 +197,10 @@ NimBLECharacteristic* NimBLEHIDDevice::getInputReport(uint8_t reportId) {
* @param [in] reportId Output report ID, the same as in report map for output object related to the characteristic. * @param [in] reportId Output report ID, the same as in report map for output object related to the characteristic.
* @return NimBLECharacteristic* A pointer to the output report characteristic. * @return NimBLECharacteristic* A pointer to the output report characteristic.
* Store this value to avoid computational overhead. * Store this value to avoid computational overhead.
* @return nullptr If the report is already created as an input or feature report.
* @details This will create the characteristic if not already created. * @details This will create the characteristic if not already created.
*/ */
NimBLECharacteristic* NimBLEHIDDevice::getOutputReport(uint8_t reportId) { NimBLECharacteristic* NimBLEHIDDevice::getOutputReport(uint8_t reportId) {
uint8_t reportType; NimBLECharacteristic* outputReportChr = locateReportCharacteristicByIdAndType(reportId, 0x02);
NimBLECharacteristic* outputReportChr = locateReportCharacteristicById(reportId, reportType);
if ((outputReportChr != nullptr) && (reportType != 0x02))
// ERROR: this reportId exists, but it is not an output report
return nullptr;
if (outputReportChr == nullptr) { if (outputReportChr == nullptr) {
outputReportChr = outputReportChr =
m_hidSvc->createCharacteristic(inputReportChrUuid, m_hidSvc->createCharacteristic(inputReportChrUuid,
@ -232,15 +221,10 @@ NimBLECharacteristic* NimBLEHIDDevice::getOutputReport(uint8_t reportId) {
* @param [in] reportId Feature report ID, the same as in report map for feature object related to the characteristic. * @param [in] reportId Feature report ID, the same as in report map for feature object related to the characteristic.
* @return NimBLECharacteristic* A pointer to feature report characteristic. * @return NimBLECharacteristic* A pointer to feature report characteristic.
* Store this value to avoid computational overhead. * Store this value to avoid computational overhead.
* @return nullptr If the report is already created as an input or output report.
* @details This will create the characteristic if not already created. * @details This will create the characteristic if not already created.
*/ */
NimBLECharacteristic* NimBLEHIDDevice::getFeatureReport(uint8_t reportId) { NimBLECharacteristic* NimBLEHIDDevice::getFeatureReport(uint8_t reportId) {
uint8_t reportType; NimBLECharacteristic* featureReportChr = locateReportCharacteristicByIdAndType(reportId, 0x03);
NimBLECharacteristic* featureReportChr = locateReportCharacteristicById(reportId, reportType);
if ((featureReportChr != nullptr) && (reportType != 0x03))
// ERROR: this reportId exists, but it is not a feature report
return nullptr;
if (featureReportChr == nullptr) { if (featureReportChr == nullptr) {
featureReportChr = m_hidSvc->createCharacteristic( featureReportChr = m_hidSvc->createCharacteristic(
inputReportChrUuid, inputReportChrUuid,

View file

@ -82,7 +82,7 @@ class NimBLEHIDDevice {
NimBLECharacteristic* m_protocolModeChr{nullptr}; // 0x2a4e NimBLECharacteristic* m_protocolModeChr{nullptr}; // 0x2a4e
NimBLECharacteristic* m_batteryLevelChr{nullptr}; // 0x2a19 NimBLECharacteristic* m_batteryLevelChr{nullptr}; // 0x2a19
NimBLECharacteristic* locateReportCharacteristicById(uint8_t reportId, uint8_t& reportType); NimBLECharacteristic* locateReportCharacteristicByIdAndType(uint8_t reportId, uint8_t reportType);
}; };
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) #endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)