esp-nimble-cpp icon indicating copy to clipboard operation
esp-nimble-cpp copied to clipboard

Creating an HID output report doesn't work

Open TheCrypt0 opened this issue 1 year ago • 10 comments

Hi, I have a firmware that should emulate a BLE keyboard (and receive back the LEDs status for caps lock, num lock, etc.) but after updating to version 2.0.2, I cannot attach the callbacks to the output report anymore because getOutputReport returns nullptr.

The setup is very similar to this (taken from https://github.dev/Mystfit/ESP32-BLE-CompositeHID ):

void KeyboardDevice::init(NimBLEHIDDevice* hid)
{
    _input = hid->getInputReport(_config.getReportId());
    _mediaInput = hid->getInputReport(MEDIA_KEYS_REPORT_ID);
    _output = hid->getOutputReport(_config.getReportId());
    _callbacks = new KeyboardCallbacks(this);
    _output->setCallbacks(_callbacks);

    setCharacteristics(_input, _output);
}

By debugging the code, it's clear where the code fails:

/**
 * @brief Get the output report 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.
 *                               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.
 */
NimBLECharacteristic* NimBLEHIDDevice::getOutputReport(uint8_t reportId) {
    uint8_t               reportType;
    NimBLECharacteristic* outputReportChr = locateReportCharacteristicById(reportId, reportType);
    if ((outputReportChr != nullptr) && (reportType != 0x02)) // <------ **HERE**, the reportType is never 0x02
        // ERROR: this reportId exists, but it is not an output report
        return nullptr;
    if (outputReportChr == nullptr) {
        outputReportChr =
            m_hidSvc->createCharacteristic(inputReportChrUuid,
                                           NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR |
                                               NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
        NimBLEDescriptor* outputReportDsc = outputReportChr->createDescriptor(
            featureReportDscUuid,
            NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
        uint8_t desc1_val[] = {reportId, 0x02};
        outputReportDsc->setValue(desc1_val, 2);
    }

    return outputReportChr;
} // getOutputReport

Here's how the same function was in version 1.4.x.

/**
 * @brief Create output report characteristic
 * @param [in] reportID Output report ID, the same as in report map for output object related to the characteristic
 * @return Pointer to new output report characteristic
 */
NimBLECharacteristic* NimBLEHIDDevice::outputReport(uint8_t reportID) {
	NimBLECharacteristic *outputReportCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
	NimBLEDescriptor *outputReportDescriptor = outputReportCharacteristic->createDescriptor((uint16_t)0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);

	uint8_t desc1_val[] = {reportID, 0x02};
	outputReportDescriptor->setValue((uint8_t*)desc1_val, 2);

	return outputReportCharacteristic;
}

Do you know if this is something fixable from my part or it needs an update to the library? Thank you, I really appreciate your support.

TheCrypt0 avatar Dec 31 '24 00:12 TheCrypt0