Skip to content

Creating an HID output report doesn't work #279

@TheCrypt0

Description

@TheCrypt0

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions