11 Commits

Author SHA1 Message Date
h2zero
a5a70ac4b0 Fix crash when retrieving descriptors.
If more than one descriptor is found the task would be released beofore the process completed causing a race condition.
2025-01-06 15:28:20 -07:00
h2zero
2feaedb755 Release 2.0.3 2025-01-05 15:10:41 -07:00
h2zero
60290cd75c Increase timeout paramter in server example. 2025-01-05 15:00:54 -07:00
h2zero
2f6ab7589b Add missing migration information to docs. 2025-01-05 15:00:51 -07:00
thekurtovic
ed51076d0c NimBLEAdvertisementData emit error on failure, remove magic numbers. 2025-01-05 15:00:48 -07:00
h2zero
4972f3e08b Fix characteristic value unable to be updated in callback 2025-01-05 15:00:45 -07:00
h2zero
95a35ec081 Fix advertising data not set if scan response enabled later. 2025-01-05 15:00:41 -07:00
thekurtovic
a127aba925 Add checks in case NIMBLE_CPP_DEBUG_ASSERT is not defined. 2025-01-05 15:00:31 -07:00
afpineda
c655b21590 Allow the same report ID in multiple input/output/feature reports 2025-01-05 15:00:28 -07:00
h2zero
d10ffa19db Fix build error when using platformio library 2025-01-05 15:00:24 -07:00
thekurtovic
dc53052411 NimBLEScan increment m_callbackSent before callback.
Fixes heap corruption observed on CONFIG_HEAP_POISONING_COMPREHENSIVE.
2025-01-05 15:00:20 -07:00
19 changed files with 111 additions and 74 deletions

View File

@@ -1,6 +1,25 @@
# Changelog
All notable changes to this project will be documented in this file.
## [2.0.3] 2025-01-05
## Fixed
- Unused variable warning when log level is below info.
- Build error missing definition of CONFIG_NIMBLE_CPP_FREERTOS_TASK_BLOCK_BIT in platformio.
- Race condition in `NimBLEScan` that can cause a crash due to heap corruption if `NimBLEScan::stop` is called from the `onResult` callback.
- Advertisement data not set if scan response is enabled after the data is set.
- `NimBLECharacteristic`/`NimBLEDescriptor` not able to update their values in the `onRead` callback.
- Too short of a timeout being requested in NimBLE_Server example leading to frequent disconnects.
## Changed
- `NimBLEHIDDevice` now allows for the same report ID in multiple input/output/feature reports.
## Added
- Config for custom log colors pre level.
- Error logs in the case that NIMBLE_CPP_DEBUG_ASSERT is not defined.
- Error logs when setting advertisement data fails.
- Missing documentation in the migration guide about enabling automatic advertising on disconnect, which was disabled by default in 2.x.
## [2.0.2] 2024-12-21
## Fixed

View File

@@ -65,7 +65,8 @@ This returns a pointer to `const ble_addr_t` instead of a pointer to the address
## Server
- `NimBLEServer::disconnect` now returns `bool`, true = success, instead of `int` to be consistent with the rest of the library.
- `NimBLEServerCallbacks::onMTUChanged` renamed to `NimBLEServerCallbacks::onMTUChange` to be consistent with the client callback.
- `NimBLEServer::getPeerIDInfo` renamed to `NimBLEServer::getPeerInfoByHandle` to better describe it's use.
- `NimBLEServer::getPeerIDInfo` renamed to `NimBLEServer::getPeerInfoByHandle` to better describe it's use.
- Advertising is no longer automatically restarted when a peer disconnects, to re-enable this feature either call `NimBLEServer::advertiseOnDisconnect(true);` after creating the server or manually restart advertising in the `onDisconnect` callback.
<br/>
### Services

View File

@@ -48,7 +48,7 @@ PROJECT_NAME = esp-nimble-cpp
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 2.0.2
PROJECT_NUMBER = 2.0.3
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a

View File

@@ -26,7 +26,7 @@ class ServerCallbacks : public NimBLEServerCallbacks {
* Latency: number of intervals allowed to skip.
* Timeout: 10 millisecond increments.
*/
pServer->updateConnParams(connInfo.getConnHandle(), 24, 48, 0, 18);
pServer->updateConnParams(connInfo.getConnHandle(), 24, 48, 0, 180);
}
void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) override {

View File

@@ -1,5 +1,5 @@
## IDF Component Manager Manifest File
version: "2.0.2"
version: "2.0.3"
license: "Apache-2.0"
description: "C++ wrapper for the NimBLE BLE stack"
url: "https://github.com/h2zero/esp-nimble-cpp"

View File

@@ -1,6 +1,6 @@
{
"name": "esp-nimble-cpp",
"version": "2.0.1",
"version": "2.0.3",
"description": "C++ wrapper for the NimBLE BLE stack",
"keywords": [
"BLE",

View File

@@ -39,7 +39,7 @@ static const char* LOG_TAG = "NimBLEAdvertisementData";
* @param [in] length The size of data to be added to the payload.
*/
bool NimBLEAdvertisementData::addData(const uint8_t* data, size_t length) {
if ((m_payload.size() + length) > BLE_HS_ADV_MAX_SZ) {
if (m_payload.size() + length > BLE_HS_ADV_MAX_SZ) {
NIMBLE_LOGE(LOG_TAG, "Data length exceeded");
return false;
}
@@ -159,6 +159,7 @@ bool NimBLEAdvertisementData::addServiceUUID(const NimBLEUUID& serviceUUID) {
type = BLE_HS_ADV_TYPE_COMP_UUIDS128;
break;
default:
NIMBLE_LOGE(LOG_TAG, "Cannot add UUID, invalid size!");
return false;
}
@@ -169,10 +170,11 @@ bool NimBLEAdvertisementData::addServiceUUID(const NimBLEUUID& serviceUUID) {
}
if (length + getPayload().size() > BLE_HS_ADV_MAX_SZ) {
NIMBLE_LOGE(LOG_TAG, "Cannot add UUID, data length exceeded!");
return false;
}
uint8_t data[31];
uint8_t data[BLE_HS_ADV_MAX_SZ];
const uint8_t* uuid = serviceUUID.getValue();
if (dataLoc == -1) {
data[0] = 1 + bytes;
@@ -214,6 +216,7 @@ bool NimBLEAdvertisementData::removeServiceUUID(const NimBLEUUID& serviceUUID) {
type = BLE_HS_ADV_TYPE_COMP_UUIDS128;
break;
default:
NIMBLE_LOGE(LOG_TAG, "Cannot remove UUID, invalid size!");
return false;
}
@@ -266,12 +269,12 @@ bool NimBLEAdvertisementData::removeServices() {
* @return True if successful.
*/
bool NimBLEAdvertisementData::setManufacturerData(const uint8_t* data, size_t length) {
if (length > 29) {
if (length > BLE_HS_ADV_MAX_FIELD_SZ) {
NIMBLE_LOGE(LOG_TAG, "MFG data too long");
return false;
}
uint8_t mdata[31];
uint8_t mdata[BLE_HS_ADV_MAX_SZ];
mdata[0] = length + 1;
mdata[1] = BLE_HS_ADV_TYPE_MFG_DATA;
memcpy(&mdata[2], data, length);
@@ -302,12 +305,12 @@ bool NimBLEAdvertisementData::setManufacturerData(const std::vector<uint8_t>& da
* @return True if successful.
*/
bool NimBLEAdvertisementData::setURI(const std::string& uri) {
if (uri.length() > 29) {
if (uri.length() > BLE_HS_ADV_MAX_FIELD_SZ) {
NIMBLE_LOGE(LOG_TAG, "URI too long");
return false;
}
uint8_t data[31];
uint8_t data[BLE_HS_ADV_MAX_SZ];
uint8_t length = 2 + uri.length();
data[0] = length - 1;
data[1] = BLE_HS_ADV_TYPE_URI;
@@ -324,16 +327,16 @@ bool NimBLEAdvertisementData::setURI(const std::string& uri) {
* @return True if successful.
*/
bool NimBLEAdvertisementData::setName(const std::string& name, bool isComplete) {
if (name.length() > 29) {
if (name.length() > BLE_HS_ADV_MAX_FIELD_SZ) {
NIMBLE_LOGE(LOG_TAG, "Name too long - truncating");
isComplete = false;
}
uint8_t data[31];
uint8_t length = 2 + std::min<uint8_t>(name.length(), 29);
uint8_t data[BLE_HS_ADV_MAX_SZ];
uint8_t length = 2 + std::min<uint8_t>(name.length(), BLE_HS_ADV_MAX_FIELD_SZ);
data[0] = length - 1;
data[1] = isComplete ? BLE_HS_ADV_TYPE_COMP_NAME : BLE_HS_ADV_TYPE_INCOMP_NAME;
memcpy(&data[2], name.c_str(), std::min<uint8_t>(name.length(), 29));
memcpy(&data[2], name.c_str(), std::min<uint8_t>(name.length(), BLE_HS_ADV_MAX_FIELD_SZ));
return addData(data, length);
} // setName
@@ -411,14 +414,14 @@ bool NimBLEAdvertisementData::setPartialServices32(const std::vector<NimBLEUUID>
bool NimBLEAdvertisementData::setServices(bool complete, uint8_t size, const std::vector<NimBLEUUID>& uuids) {
uint8_t bytes = size / 8;
uint8_t length = 2; // start with 2 for length + type bytes
uint8_t data[31];
uint8_t data[BLE_HS_ADV_MAX_SZ];
for (const auto& uuid : uuids) {
if (uuid.bitSize() != size) {
NIMBLE_LOGE(LOG_TAG, "Service UUID(%d) invalid", size);
continue;
} else {
if (length + bytes >= 31) {
if (length + bytes >= BLE_HS_ADV_MAX_SZ) {
NIMBLE_LOGW(LOG_TAG, "Too many services - truncating");
complete = false;
break;
@@ -441,6 +444,7 @@ bool NimBLEAdvertisementData::setServices(bool complete, uint8_t size, const std
data[1] = (complete ? BLE_HS_ADV_TYPE_COMP_UUIDS128 : BLE_HS_ADV_TYPE_INCOMP_UUIDS128);
break;
default:
NIMBLE_LOGE(LOG_TAG, "Cannot set services, invalid size!");
return false;
}
@@ -458,7 +462,7 @@ bool NimBLEAdvertisementData::setServices(bool complete, uint8_t size, const std
bool NimBLEAdvertisementData::setServiceData(const NimBLEUUID& uuid, const uint8_t* data, size_t length) {
uint8_t uuidBytes = uuid.bitSize() / 8;
uint8_t sDataLen = 2 + uuidBytes + length;
if (sDataLen > 31) {
if (sDataLen > BLE_HS_ADV_MAX_SZ) {
NIMBLE_LOGE(LOG_TAG, "Service Data too long");
return false;
}
@@ -475,6 +479,7 @@ bool NimBLEAdvertisementData::setServiceData(const NimBLEUUID& uuid, const uint8
type = BLE_HS_ADV_TYPE_SVC_DATA_UUID128;
break;
default:
NIMBLE_LOGE(LOG_TAG, "Cannot set service data, invalid size!");
return false;
}
@@ -483,7 +488,7 @@ bool NimBLEAdvertisementData::setServiceData(const NimBLEUUID& uuid, const uint8
return true;
}
uint8_t sData[31];
uint8_t sData[BLE_HS_ADV_MAX_SZ];
sData[0] = uuidBytes + length + 1;
sData[1] = type;
memcpy(&sData[2], uuid.getValue(), uuidBytes);

View File

@@ -408,7 +408,7 @@ bool NimBLEAdvertising::refreshAdvertisingData() {
* @return True if the service was added successfully.
*/
bool NimBLEAdvertising::addServiceUUID(const NimBLEUUID& serviceUUID) {
if (!m_advData.addServiceUUID(serviceUUID) && m_scanResp) {
if (!m_advData.addServiceUUID(serviceUUID)) {
if (!m_scanData.addServiceUUID(serviceUUID)) {
return false;
}
@@ -466,7 +466,7 @@ bool NimBLEAdvertising::removeServices() {
* @return True if the appearance was set successfully.
*/
bool NimBLEAdvertising::setAppearance(uint16_t appearance) {
if (!m_advData.setAppearance(appearance) && m_scanResp) {
if (!m_advData.setAppearance(appearance)) {
if (!m_scanData.setAppearance(appearance)) {
return false;
}
@@ -484,7 +484,7 @@ bool NimBLEAdvertising::setAppearance(uint16_t appearance) {
* @details Range = 0x0006(7.5ms) to 0x0C80(4000ms), values not within the range will be limited to this range.
*/
bool NimBLEAdvertising::setPreferredParams(uint16_t minInterval, uint16_t maxInterval) {
if (!m_advData.setPreferredParams(minInterval, maxInterval) && m_scanResp) {
if (!m_advData.setPreferredParams(minInterval, maxInterval)) {
if (!m_scanData.setPreferredParams(minInterval, maxInterval)) {
return false;
}
@@ -499,7 +499,7 @@ bool NimBLEAdvertising::setPreferredParams(uint16_t minInterval, uint16_t maxInt
* @return True if the transmission power level was added successfully.
*/
bool NimBLEAdvertising::addTxPower() {
if (!m_advData.addTxPower() && m_scanResp) {
if (!m_advData.addTxPower()) {
if (!m_scanData.addTxPower()) {
return false;
}
@@ -537,7 +537,7 @@ bool NimBLEAdvertising::setName(const std::string& name) {
* @return True if the manufacturer data was set successfully.
*/
bool NimBLEAdvertising::setManufacturerData(const uint8_t* data, size_t length) {
if (!m_advData.setManufacturerData(data, length) && m_scanResp) {
if (!m_advData.setManufacturerData(data, length)) {
if (!m_scanData.setManufacturerData(data, length)) {
return false;
}
@@ -571,7 +571,7 @@ bool NimBLEAdvertising::setManufacturerData(const std::vector<uint8_t>& data) {
* @return True if the URI was set successfully.
*/
bool NimBLEAdvertising::setURI(const std::string& uri) {
if (!m_advData.setURI(uri) && m_scanResp) {
if (!m_advData.setURI(uri)) {
if (!m_scanData.setURI(uri)) {
return false;
}
@@ -590,7 +590,7 @@ bool NimBLEAdvertising::setURI(const std::string& uri) {
* @note If data length is 0 the service data will not be advertised.
*/
bool NimBLEAdvertising::setServiceData(const NimBLEUUID& uuid, const uint8_t* data, size_t length) {
if (!m_advData.setServiceData(uuid, data, length) && m_scanResp) {
if (!m_advData.setServiceData(uuid, data, length)) {
if (!m_scanData.setServiceData(uuid, data, length)) {
return false;
}

View File

@@ -25,6 +25,9 @@
# endif
# include "NimBLEAttValue.h"
# include "NimBLELog.h"
static const char* LOG_TAG = "NimBLEAttValue";
// Default constructor implementation.
NimBLEAttValue::NimBLEAttValue(uint16_t init_len, uint16_t max_len)
@@ -38,13 +41,17 @@ NimBLEAttValue::NimBLEAttValue(uint16_t init_len, uint16_t max_len)
# endif
{
NIMBLE_CPP_DEBUG_ASSERT(m_attr_value);
if (m_attr_value == nullptr) {
NIMBLE_LOGE(LOG_TAG, "Failed to calloc ctx");
}
}
// Value constructor implementation.
NimBLEAttValue::NimBLEAttValue(const uint8_t* value, uint16_t len, uint16_t max_len) : NimBLEAttValue(len, max_len) {
memcpy(m_attr_value, value, len);
m_attr_value[len] = '\0';
m_attr_len = len;
if (m_attr_value != nullptr) {
memcpy(m_attr_value, value, len);
m_attr_len = len;
}
}
// Destructor implementation.
@@ -81,6 +88,10 @@ NimBLEAttValue& NimBLEAttValue::operator=(const NimBLEAttValue& source) {
void NimBLEAttValue::deepCopy(const NimBLEAttValue& source) {
uint8_t* res = static_cast<uint8_t*>(realloc(m_attr_value, source.m_capacity + 1));
NIMBLE_CPP_DEBUG_ASSERT(res);
if (res == nullptr) {
NIMBLE_LOGE(LOG_TAG, "Failed to realloc deepCopy");
return;
}
ble_npl_hw_enter_critical();
m_attr_value = res;
@@ -106,7 +117,7 @@ NimBLEAttValue& NimBLEAttValue::append(const uint8_t* value, uint16_t len) {
}
if ((m_attr_len + len) > m_attr_max_len) {
NIMBLE_LOGE("NimBLEAttValue", "val > max, len=%u, max=%u", len, m_attr_max_len);
NIMBLE_LOGE(LOG_TAG, "val > max, len=%u, max=%u", len, m_attr_max_len);
return *this;
}
@@ -117,6 +128,10 @@ NimBLEAttValue& NimBLEAttValue::append(const uint8_t* value, uint16_t len) {
m_capacity = new_len;
}
NIMBLE_CPP_DEBUG_ASSERT(res);
if (res == nullptr) {
NIMBLE_LOGE(LOG_TAG, "Failed to realloc append");
return *this;
}
# if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
time_t t = time(nullptr);
@@ -135,4 +150,13 @@ NimBLEAttValue& NimBLEAttValue::append(const uint8_t* value, uint16_t len) {
return *this;
}
uint8_t NimBLEAttValue::operator[](int pos) const {
NIMBLE_CPP_DEBUG_ASSERT(pos < m_attr_len);
if (pos >= m_attr_len) {
NIMBLE_LOGE(LOG_TAG, "pos >= len, pos=%u, len=%u", pos, m_attr_len);
return 0;
}
return m_attr_value[pos];
}
#endif // CONFIG_BT_ENABLED

View File

@@ -24,7 +24,6 @@
# include <Arduino.h>
# endif
# include "NimBLELog.h"
# include <string>
# include <vector>
# include <ctime>
@@ -323,10 +322,7 @@ class NimBLEAttValue {
/*********************** Operators ************************/
/** @brief Subscript operator */
uint8_t operator[](int pos) const {
NIMBLE_CPP_DEBUG_ASSERT(pos < m_attr_len);
return m_attr_value[pos];
}
uint8_t operator[](int pos) const;
/** @brief Operator; Get the value as a std::vector<uint8_t>. */
operator std::vector<uint8_t>() const { return std::vector<uint8_t>(m_attr_value, m_attr_value + m_attr_len); }

View File

@@ -701,6 +701,7 @@ bool NimBLEExtAdvertisement::addServiceUUID(const NimBLEUUID& serviceUUID) {
type = BLE_HS_ADV_TYPE_COMP_UUIDS128;
break;
default:
NIMBLE_LOGE(LOG_TAG, "Cannot add UUID, invalid size!");
return false;
}
@@ -711,10 +712,11 @@ bool NimBLEExtAdvertisement::addServiceUUID(const NimBLEUUID& serviceUUID) {
}
if (length + getDataSize() > CONFIG_BT_NIMBLE_MAX_EXT_ADV_DATA_LEN) {
NIMBLE_LOGE(LOG_TAG, "Cannot add UUID, data length exceeded!");
return false;
}
uint8_t data[31];
uint8_t data[BLE_HS_ADV_MAX_SZ];
const uint8_t* uuid = serviceUUID.getValue();
if (dataLoc == -1) {
data[0] = 1 + bytes;
@@ -756,6 +758,7 @@ bool NimBLEExtAdvertisement::removeServiceUUID(const NimBLEUUID& serviceUUID) {
type = BLE_HS_ADV_TYPE_COMP_UUIDS128;
break;
default:
NIMBLE_LOGE(LOG_TAG, "Cannot remove UUID, invalid size!");
return false;
}
@@ -878,6 +881,7 @@ bool NimBLEExtAdvertisement::setServices(bool complete, uint8_t size, const std:
header[1] = complete ? BLE_HS_ADV_TYPE_COMP_UUIDS128 : BLE_HS_ADV_TYPE_INCOMP_UUIDS128;
break;
default:
NIMBLE_LOGE(LOG_TAG, "Cannot set services, invalid size!");
return false;
}
@@ -932,6 +936,7 @@ bool NimBLEExtAdvertisement::setServiceData(const NimBLEUUID& uuid, const uint8_
type = BLE_HS_ADV_TYPE_SVC_DATA_UUID128;
break;
default:
NIMBLE_LOGE(LOG_TAG, "Cannot set service data, invalid size!");
return false;
}

View File

@@ -150,21 +150,20 @@ void NimBLEHIDDevice::setBatteryLevel(uint8_t level, bool notify) {
} // 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 [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 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);
for (uint16_t i = 1; (candidate != nullptr) && (i != 0); i++) {
NimBLEDescriptor* dsc = candidate->getDescriptorByUUID(featureReportDscUuid);
NimBLEAttValue desc1_val_att = dsc->getValue();
const uint8_t* desc1_val = desc1_val_att.data();
reportType = desc1_val[1];
if (desc1_val[0] == reportId) return candidate;
if ((desc1_val[0] == reportId) && (desc1_val[1] == reportType)) return candidate;
candidate = m_hidSvc->getCharacteristic(inputReportChrUuid, i);
}
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.
* @return NimBLECharacteristic* A pointer to the input report characteristic.
* 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.
*/
NimBLECharacteristic* NimBLEHIDDevice::getInputReport(uint8_t reportId) {
uint8_t reportType;
NimBLECharacteristic* inputReportChr = locateReportCharacteristicById(reportId, reportType);
if ((inputReportChr != nullptr) && (reportType != 0x01))
// ERROR: this reportId exists, but it is not an input report
return nullptr;
NimBLECharacteristic* inputReportChr = locateReportCharacteristicByIdAndType(reportId, 0x01);
if (inputReportChr == nullptr) {
inputReportChr =
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.
* @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))
// ERROR: this reportId exists, but it is not an output report
return nullptr;
NimBLECharacteristic* outputReportChr = locateReportCharacteristicByIdAndType(reportId, 0x02);
if (outputReportChr == nullptr) {
outputReportChr =
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.
* @return NimBLECharacteristic* A pointer to feature report characteristic.
* 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.
*/
NimBLECharacteristic* NimBLEHIDDevice::getFeatureReport(uint8_t reportId) {
uint8_t reportType;
NimBLECharacteristic* featureReportChr = locateReportCharacteristicById(reportId, reportType);
if ((featureReportChr != nullptr) && (reportType != 0x03))
// ERROR: this reportId exists, but it is not a feature report
return nullptr;
NimBLECharacteristic* featureReportChr = locateReportCharacteristicByIdAndType(reportId, 0x03);
if (featureReportChr == nullptr) {
featureReportChr = m_hidSvc->createCharacteristic(
inputReportChrUuid,

View File

@@ -82,7 +82,7 @@ class NimBLEHIDDevice {
NimBLECharacteristic* m_protocolModeChr{nullptr}; // 0x2a4e
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)

View File

@@ -72,14 +72,8 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(
const auto pChr = (NimBLERemoteCharacteristic*)pTaskData->m_pInstance;
const NimBLEUUID* uuidFilter = filter->uuid;
if (error->status == BLE_HS_ENOTCONN) {
NIMBLE_LOGE(LOG_TAG, "<< Descriptor Discovery; Not connected");
NimBLEUtils::taskRelease(*pTaskData, error->status);
return error->status;
}
if (pChr->getHandle() != chr_val_handle) {
rc = BLE_HS_EDONE; // descriptor not for this characteristic
return 0; // Descriptor not for this characteristic
}
if (rc == 0) {
@@ -92,6 +86,7 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(
}
pChr->m_vDescriptors.push_back(new NimBLERemoteDescriptor(pChr, dsc));
return 0;
}
NimBLEUtils::taskRelease(*pTaskData, rc);

View File

@@ -147,7 +147,10 @@ int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle,
const ble_gatt_error* error,
const ble_gatt_chr* chr,
void* arg) {
NIMBLE_LOGD(LOG_TAG, "Characteristic Discovery >>");
NIMBLE_LOGD(LOG_TAG,
"Characteristic Discovery >> status: %d handle: %d",
error->status,
(error->status == 0) ? chr->def_handle : -1);
auto pTaskData = (NimBLETaskData*)arg;
const auto pSvc = (NimBLERemoteService*)pTaskData->m_pInstance;

View File

@@ -21,6 +21,7 @@
# include "NimBLERemoteValueAttribute.h"
# include "NimBLEClient.h"
# include "NimBLEUtils.h"
# include "NimBLELog.h"
# include <climits>

View File

@@ -119,19 +119,19 @@ int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) {
}
if (!advertisedDevice->m_callbackSent) {
pScan->m_pScanCallbacks->onDiscovered(advertisedDevice);
advertisedDevice->m_callbackSent++;
pScan->m_pScanCallbacks->onDiscovered(advertisedDevice);
}
// If not active scanning or scan response is not available
// or extended advertisement scanning, report the result to the callback now.
if (pScan->m_scanParams.passive || !isLegacyAdv || !advertisedDevice->isScannable()) {
pScan->m_pScanCallbacks->onResult(advertisedDevice);
advertisedDevice->m_callbackSent++;
pScan->m_pScanCallbacks->onResult(advertisedDevice);
} else if (isLegacyAdv && event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
advertisedDevice->m_callbackSent++;
// got the scan response report the full data.
pScan->m_pScanCallbacks->onResult(advertisedDevice);
advertisedDevice->m_callbackSent++;
}
// If not storing results and we have invoked the callback, delete the device.

View File

@@ -611,8 +611,9 @@ int NimBLEServer::handleGattEvent(uint16_t connHandle, uint16_t attrHandle, ble_
NIMBLE_LOGD(LOG_TAG,
"Gatt %s event",
(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR || ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) ? "Read" : "Write");
auto pAtt = static_cast<NimBLELocalValueAttribute*>(arg);
auto val = pAtt->getAttVal();
auto pAtt = static_cast<NimBLELocalValueAttribute*>(arg);
const NimBLEAttValue& val = pAtt->getAttVal();
NimBLEConnInfo peerInfo{};
ble_gap_conn_find(connHandle, &peerInfo.m_desc);
@@ -623,7 +624,7 @@ int NimBLEServer::handleGattEvent(uint16_t connHandle, uint16_t attrHandle, ble_
if (connHandle != BLE_HS_CONN_HANDLE_NONE) {
// If the packet header is only 8 bytes then this is a follow up of a long read
// so we don't want to call the onRead() callback again.
if (ctxt->om->om_pkthdr_len > 8 || pAtt->getAttVal().size() <= (ble_att_mtu(connHandle) - 3)) {
if (ctxt->om->om_pkthdr_len > 8 || val.size() <= (ble_att_mtu(connHandle) - 3)) {
pAtt->readEvent(peerInfo);
}
}

View File

@@ -37,6 +37,9 @@
# include <climits>
# if defined INC_FREERTOS_H
# ifndef CONFIG_NIMBLE_CPP_FREERTOS_TASK_BLOCK_BIT
# define CONFIG_NIMBLE_CPP_FREERTOS_TASK_BLOCK_BIT 31
# endif
constexpr uint32_t TASK_BLOCK_BIT = (1 << CONFIG_NIMBLE_CPP_FREERTOS_TASK_BLOCK_BIT);
# endif