mirror of
https://github.com/h2zero/esp-nimble-cpp.git
synced 2024-11-22 05:00:55 +01:00
Implement client long read / write
Client will now read/write long characteristics and descriptors.
This commit is contained in:
parent
04b524d1f8
commit
59823b4bf0
4 changed files with 158 additions and 104 deletions
13
README.md
13
README.md
|
@ -1,13 +1,10 @@
|
||||||
# *** UPDATE ***
|
# *** UPDATE ***
|
||||||
Server now handles long reads and writes, still work to do on client.
|
Client long read/write characteristics/descriptors now working.
|
||||||
|
We are now nearing 100% replacement of the original cpp_utils BLE library :smile:
|
||||||
NEW Client callback created - ```bool onConnParamsUpdateRequest(NimBLEClient* pClient, const ble_gap_upd_params* params)```
|
|
||||||
Called when the server wants to change the connection parameters, return true to accept them or false if not.
|
|
||||||
Check NimBLE_Client.ino example for a demonstration.
|
|
||||||
|
|
||||||
|
|
||||||
# esp-nimble-cpp
|
# esp-nimble-cpp
|
||||||
A fork of the NimBLE stack restructured for compilation in the Ardruino IDE with a CPP library for use with ESP32.
|
NimBLE CPP library for use with ESP32 that attempts to maintain compatibility with the @nkolban cpp_uitls API.
|
||||||
|
|
||||||
Why? Because the Bluedroid library is too bulky.
|
Why? Because the Bluedroid library is too bulky.
|
||||||
|
|
||||||
|
@ -18,6 +15,8 @@ Initial client code testing has resulted in code size reduction of ~115k and red
|
||||||
|
|
||||||
Download as .zip and extract to components folder in your esp-idf project.
|
Download as .zip and extract to components folder in your esp-idf project.
|
||||||
|
|
||||||
|
Run menuconfig, go to `Component config->Bluetooth->` enable Bluetooth and select NimBLE host.
|
||||||
|
|
||||||
`#include "NimBLEDevice.h"` in main.cpp.
|
`#include "NimBLEDevice.h"` in main.cpp.
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,6 +24,8 @@ Download as .zip and extract to components folder in your esp-idf project.
|
||||||
|
|
||||||
This library is intended to be compatible with the original ESP32 BLE functions and types with minor changes.
|
This library is intended to be compatible with the original ESP32 BLE functions and types with minor changes.
|
||||||
|
|
||||||
|
Check [API_DIFFERENCES](https://github.com/h2zero/esp-nimble-cpp/blob/master/API_DIFFERENCES.md) for details.
|
||||||
|
|
||||||
|
|
||||||
# Acknowledgments:
|
# Acknowledgments:
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,8 @@ static const char* LOG_TAG = "NimBLERemoteCharacteristic";
|
||||||
m_charProp = chr->properties;
|
m_charProp = chr->properties;
|
||||||
m_pRemoteService = pRemoteService;
|
m_pRemoteService = pRemoteService;
|
||||||
m_notifyCallback = nullptr;
|
m_notifyCallback = nullptr;
|
||||||
|
m_rawData = nullptr;
|
||||||
|
m_dataLen = 0;
|
||||||
} // NimBLERemoteCharacteristic
|
} // NimBLERemoteCharacteristic
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,7 +63,9 @@ static const char* LOG_TAG = "NimBLERemoteCharacteristic";
|
||||||
*/
|
*/
|
||||||
NimBLERemoteCharacteristic::~NimBLERemoteCharacteristic() {
|
NimBLERemoteCharacteristic::~NimBLERemoteCharacteristic() {
|
||||||
removeDescriptors(); // Release resources for any descriptor information we may have allocated.
|
removeDescriptors(); // Release resources for any descriptor information we may have allocated.
|
||||||
if(m_rawData != nullptr) free(m_rawData);
|
if(m_rawData != nullptr) {
|
||||||
|
free(m_rawData);
|
||||||
|
}
|
||||||
} // ~NimBLERemoteCharacteristic
|
} // ~NimBLERemoteCharacteristic
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -319,6 +323,8 @@ std::string NimBLERemoteCharacteristic::readValue() {
|
||||||
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int retryCount = 1;
|
int retryCount = 1;
|
||||||
|
// Clear the value before reading.
|
||||||
|
m_value = "";
|
||||||
|
|
||||||
NimBLEClient* pClient = getRemoteService()->getClient();
|
NimBLEClient* pClient = getRemoteService()->getClient();
|
||||||
|
|
||||||
|
@ -331,24 +337,27 @@ std::string NimBLERemoteCharacteristic::readValue() {
|
||||||
do {
|
do {
|
||||||
m_semaphoreReadCharEvt.take("readValue");
|
m_semaphoreReadCharEvt.take("readValue");
|
||||||
|
|
||||||
rc = ble_gattc_read(pClient->getConnId(), m_handle,
|
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
|
||||||
NimBLERemoteCharacteristic::onReadCB, this);
|
NimBLERemoteCharacteristic::onReadCB,
|
||||||
|
this);
|
||||||
// long read experiment
|
|
||||||
/* rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
|
|
||||||
NimBLERemoteCharacteristic::onReadCB, this);
|
|
||||||
*/
|
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Error: Failed to read characteristic; rc=%d", rc);
|
NIMBLE_LOGE(LOG_TAG, "Error: Failed to read characteristic; rc=%d, %s",
|
||||||
m_semaphoreReadCharEvt.give();
|
rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
|
m_semaphoreReadCharEvt.give(0);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = m_semaphoreReadCharEvt.wait("readValue");
|
rc = m_semaphoreReadCharEvt.wait("readValue");
|
||||||
switch(rc){
|
switch(rc){
|
||||||
case 0:
|
case 0:
|
||||||
|
case BLE_HS_EDONE:
|
||||||
|
rc = 0;
|
||||||
|
break;
|
||||||
|
// Characteristic is not long-readable, return with what we have.
|
||||||
|
case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
|
||||||
|
NIMBLE_LOGI(LOG_TAG, "Attribute not long");
|
||||||
|
rc = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
|
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
|
||||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR):
|
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR):
|
||||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC):
|
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC):
|
||||||
|
@ -361,7 +370,7 @@ std::string NimBLERemoteCharacteristic::readValue() {
|
||||||
} while(rc != 0 && retryCount--);
|
} while(rc != 0 && retryCount--);
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< readValue(): length: %d", m_value.length());
|
NIMBLE_LOGD(LOG_TAG, "<< readValue(): length: %d", m_value.length());
|
||||||
return (rc == 0) ? m_value : "";
|
return m_value;
|
||||||
} // readValue
|
} // readValue
|
||||||
|
|
||||||
|
|
||||||
|
@ -374,36 +383,25 @@ int NimBLERemoteCharacteristic::onReadCB(uint16_t conn_handle,
|
||||||
struct ble_gatt_attr *attr, void *arg)
|
struct ble_gatt_attr *attr, void *arg)
|
||||||
{
|
{
|
||||||
NimBLERemoteCharacteristic* characteristic = (NimBLERemoteCharacteristic*)arg;
|
NimBLERemoteCharacteristic* characteristic = (NimBLERemoteCharacteristic*)arg;
|
||||||
|
uint16_t conn_id = characteristic->getRemoteService()->getClient()->getConnId();
|
||||||
|
|
||||||
// Make sure the discovery is for this device
|
// Make sure the read is for this client
|
||||||
if(characteristic->getRemoteService()->getClient()->getConnId() != conn_handle){
|
if(conn_id != conn_handle) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
NIMBLE_LOGI(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
|
NIMBLE_LOGI(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
|
||||||
// long read experiment
|
|
||||||
/* if(attr && (attr->om->om_len >= (ble_att_mtu(characteristic->getRemoteService()->getClient()->getConnId()) - 1))){
|
|
||||||
|
|
||||||
|
if(error->status == 0) {
|
||||||
|
if(attr) {
|
||||||
|
NIMBLE_LOGD(LOG_TAG, "Got %d bytes", attr->om->om_len);
|
||||||
|
|
||||||
|
characteristic->m_value += std::string((char*) attr->om->om_data, attr->om->om_len);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
if(characteristic->m_rawData != nullptr) {
|
|
||||||
free(characteristic->m_rawData);
|
|
||||||
}
|
}
|
||||||
|
// Read complete release semaphore and let the app can continue.
|
||||||
if (error->status == 0) {
|
|
||||||
characteristic->m_value = std::string((char*) attr->om->om_data, attr->om->om_len);
|
|
||||||
characteristic->m_rawData = (uint8_t*) calloc(attr->om->om_len, sizeof(uint8_t));
|
|
||||||
memcpy(characteristic->m_rawData, attr->om->om_data, attr->om->om_len);
|
|
||||||
characteristic->m_semaphoreReadCharEvt.give(0);
|
|
||||||
} else {
|
|
||||||
characteristic->m_rawData = nullptr;
|
|
||||||
characteristic->m_value = "";
|
|
||||||
characteristic->m_semaphoreReadCharEvt.give(error->status);
|
characteristic->m_semaphoreReadCharEvt.give(error->status);
|
||||||
}
|
return 0;
|
||||||
|
|
||||||
// characteristic->m_semaphoreReadCharEvt.give(error->status);
|
|
||||||
return 0; //1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -523,7 +521,7 @@ bool NimBLERemoteCharacteristic::writeValue(uint8_t* data, size_t length, bool r
|
||||||
NimBLEClient* pClient = getRemoteService()->getClient();
|
NimBLEClient* pClient = getRemoteService()->getClient();
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int retryCount = 1;
|
int retryCount = 1;
|
||||||
// uint16_t mtu;
|
uint16_t mtu;
|
||||||
|
|
||||||
// Check to see that we are connected.
|
// Check to see that we are connected.
|
||||||
if (!pClient->isConnected()) {
|
if (!pClient->isConnected()) {
|
||||||
|
@ -531,29 +529,30 @@ bool NimBLERemoteCharacteristic::writeValue(uint8_t* data, size_t length, bool r
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// mtu = ble_att_mtu(pClient->getConnId()) - 3;
|
mtu = ble_att_mtu(pClient->getConnId()) - 3;
|
||||||
|
|
||||||
if(/*!length > mtu &&*/ !response) {
|
// Check if the data length is longer than we can write in 1 connection event.
|
||||||
|
// If so we must do a long write which requires a response.
|
||||||
|
if(length <= mtu && !response) {
|
||||||
rc = ble_gattc_write_no_rsp_flat(pClient->getConnId(), m_handle, data, length);
|
rc = ble_gattc_write_no_rsp_flat(pClient->getConnId(), m_handle, data, length);
|
||||||
return (rc==0);
|
return (rc==0);
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
m_semaphoreWriteCharEvt.take("writeValue");
|
m_semaphoreWriteCharEvt.take("writeValue");
|
||||||
// long write experiment
|
|
||||||
/* if(length > mtu) {
|
if(length > mtu) {
|
||||||
NIMBLE_LOGD(LOG_TAG,"long write");
|
NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length);
|
||||||
os_mbuf *om = ble_hs_mbuf_from_flat(data, length);
|
os_mbuf *om = ble_hs_mbuf_from_flat(data, length);
|
||||||
rc = ble_gattc_write_long(pClient->getConnId(), m_handle, 0, om,
|
rc = ble_gattc_write_long(pClient->getConnId(), m_handle, 0, om,
|
||||||
NimBLERemoteCharacteristic::onWriteCB,
|
NimBLERemoteCharacteristic::onWriteCB,
|
||||||
this);
|
this);
|
||||||
} else {
|
} else {
|
||||||
*/
|
|
||||||
rc = ble_gattc_write_flat(pClient->getConnId(), m_handle,
|
rc = ble_gattc_write_flat(pClient->getConnId(), m_handle,
|
||||||
data, length,
|
data, length,
|
||||||
NimBLERemoteCharacteristic::onWriteCB,
|
NimBLERemoteCharacteristic::onWriteCB,
|
||||||
this);
|
this);
|
||||||
// }
|
}
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Error: Failed to write characteristic; rc=%d", rc);
|
NIMBLE_LOGE(LOG_TAG, "Error: Failed to write characteristic; rc=%d", rc);
|
||||||
m_semaphoreWriteCharEvt.give();
|
m_semaphoreWriteCharEvt.give();
|
||||||
|
@ -564,6 +563,13 @@ bool NimBLERemoteCharacteristic::writeValue(uint8_t* data, size_t length, bool r
|
||||||
|
|
||||||
switch(rc){
|
switch(rc){
|
||||||
case 0:
|
case 0:
|
||||||
|
case BLE_HS_EDONE:
|
||||||
|
rc = 0;
|
||||||
|
break;
|
||||||
|
case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Long write not supported by peer; Truncating length to %d", mtu);
|
||||||
|
retryCount++;
|
||||||
|
length = mtu;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
|
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
|
||||||
|
@ -599,13 +605,7 @@ int NimBLERemoteCharacteristic::onWriteCB(uint16_t conn_handle,
|
||||||
|
|
||||||
NIMBLE_LOGI(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle);
|
NIMBLE_LOGI(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle);
|
||||||
|
|
||||||
if (error->status == 0) {
|
|
||||||
|
|
||||||
characteristic->m_semaphoreWriteCharEvt.give(0);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
characteristic->m_semaphoreWriteCharEvt.give(error->status);
|
characteristic->m_semaphoreWriteCharEvt.give(error->status);
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -613,13 +613,34 @@ int NimBLERemoteCharacteristic::onWriteCB(uint16_t conn_handle,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read raw data from remote characteristic as hex bytes
|
* @brief Read raw data from remote characteristic as hex bytes
|
||||||
* @return return pointer data read
|
* @return uint8_t pointer to the data read.
|
||||||
*/
|
*/
|
||||||
uint8_t* NimBLERemoteCharacteristic::readRawData() {
|
uint8_t* NimBLERemoteCharacteristic::readRawData() {
|
||||||
|
if(m_rawData != nullptr) {
|
||||||
|
free(m_rawData);
|
||||||
|
m_rawData = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dataLen = m_value.length();
|
||||||
|
// If we have data copy it to rawData
|
||||||
|
if(m_dataLen) {
|
||||||
|
m_rawData = (uint8_t*) calloc(m_dataLen, sizeof(uint8_t));
|
||||||
|
memcpy(m_rawData, m_value.data(), m_dataLen);
|
||||||
|
}
|
||||||
|
|
||||||
return m_rawData;
|
return m_rawData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the length of the data read from the remote characteristic.
|
||||||
|
* @return size_t length of the data in bytes.
|
||||||
|
*/
|
||||||
|
size_t NimBLERemoteCharacteristic::getDataLength() {
|
||||||
|
return m_value.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void NimBLERemoteCharacteristic::releaseSemaphores() {
|
void NimBLERemoteCharacteristic::releaseSemaphores() {
|
||||||
for (auto &dPair : m_descriptorMap) {
|
for (auto &dPair : m_descriptorMap) {
|
||||||
dPair.second->releaseSemaphores();
|
dPair.second->releaseSemaphores();
|
||||||
|
|
|
@ -60,6 +60,7 @@ public:
|
||||||
bool writeValue(uint8_t newValue, bool response = false);
|
bool writeValue(uint8_t newValue, bool response = false);
|
||||||
std::string toString();
|
std::string toString();
|
||||||
uint8_t* readRawData();
|
uint8_t* readRawData();
|
||||||
|
size_t getDataLength();
|
||||||
NimBLERemoteService* getRemoteService();
|
NimBLERemoteService* getRemoteService();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -90,7 +91,8 @@ private:
|
||||||
FreeRTOS::Semaphore m_semaphoreReadCharEvt = FreeRTOS::Semaphore("ReadCharEvt");
|
FreeRTOS::Semaphore m_semaphoreReadCharEvt = FreeRTOS::Semaphore("ReadCharEvt");
|
||||||
FreeRTOS::Semaphore m_semaphoreWriteCharEvt = FreeRTOS::Semaphore("WriteCharEvt");
|
FreeRTOS::Semaphore m_semaphoreWriteCharEvt = FreeRTOS::Semaphore("WriteCharEvt");
|
||||||
std::string m_value;
|
std::string m_value;
|
||||||
uint8_t* m_rawData = nullptr;
|
uint8_t* m_rawData;
|
||||||
|
size_t m_dataLen;
|
||||||
notify_callback m_notifyCallback;
|
notify_callback m_notifyCallback;
|
||||||
|
|
||||||
// We maintain a map of descriptors owned by this characteristic keyed by a string representation of the UUID.
|
// We maintain a map of descriptors owned by this characteristic keyed by a string representation of the UUID.
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
#if defined(CONFIG_BT_ENABLED)
|
||||||
|
|
||||||
#include "NimBLERemoteDescriptor.h"
|
#include "NimBLERemoteDescriptor.h"
|
||||||
|
#include "NimBLEUtils.h"
|
||||||
#include "NimBLELog.h"
|
#include "NimBLELog.h"
|
||||||
|
|
||||||
static const char* LOG_TAG = "NimBLERemoteDescriptor";
|
static const char* LOG_TAG = "NimBLERemoteDescriptor";
|
||||||
|
@ -83,22 +84,26 @@ int NimBLERemoteDescriptor::onReadCB(uint16_t conn_handle,
|
||||||
struct ble_gatt_attr *attr, void *arg)
|
struct ble_gatt_attr *attr, void *arg)
|
||||||
{
|
{
|
||||||
NimBLERemoteDescriptor* desc = (NimBLERemoteDescriptor*)arg;
|
NimBLERemoteDescriptor* desc = (NimBLERemoteDescriptor*)arg;
|
||||||
|
uint16_t conn_id = desc->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId();
|
||||||
|
|
||||||
// Make sure the discovery is for this device
|
// Make sure the discovery is for this device
|
||||||
if(desc->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId() != conn_handle){
|
if(conn_id != conn_handle){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
|
NIMBLE_LOGD(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
|
||||||
|
|
||||||
if (error->status == 0) {
|
if(error->status == 0){
|
||||||
desc->m_value = std::string((char*) attr->om->om_data, attr->om->om_len);
|
if(attr){
|
||||||
desc->m_semaphoreReadDescrEvt.give(0);
|
NIMBLE_LOGD(LOG_TAG, "Got %d bytes", attr->om->om_len);
|
||||||
} else {
|
|
||||||
desc->m_value = "";
|
desc->m_value += std::string((char*) attr->om->om_data, attr->om->om_len);
|
||||||
desc->m_semaphoreReadDescrEvt.give(error->status);
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read complete release semaphore and let the app can continue.
|
||||||
|
desc->m_semaphoreReadDescrEvt.give(error->status);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,10 +111,12 @@ int NimBLERemoteDescriptor::onReadCB(uint16_t conn_handle,
|
||||||
std::string NimBLERemoteDescriptor::readValue() {
|
std::string NimBLERemoteDescriptor::readValue() {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> Descriptor readValue: %s", toString().c_str());
|
NIMBLE_LOGD(LOG_TAG, ">> Descriptor readValue: %s", toString().c_str());
|
||||||
|
|
||||||
NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
|
|
||||||
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int retryCount = 1;
|
int retryCount = 1;
|
||||||
|
// Clear the value before reading.
|
||||||
|
m_value = "";
|
||||||
|
|
||||||
|
NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
|
||||||
|
|
||||||
// Check to see that we are connected.
|
// Check to see that we are connected.
|
||||||
if (!pClient->isConnected()) {
|
if (!pClient->isConnected()) {
|
||||||
|
@ -120,12 +127,13 @@ std::string NimBLERemoteDescriptor::readValue() {
|
||||||
do {
|
do {
|
||||||
m_semaphoreReadDescrEvt.take("ReadDescriptor");
|
m_semaphoreReadDescrEvt.take("ReadDescriptor");
|
||||||
|
|
||||||
rc = ble_gattc_read(pClient->getConnId(), m_handle,
|
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
|
||||||
NimBLERemoteDescriptor::onReadCB, this);
|
NimBLERemoteDescriptor::onReadCB,
|
||||||
|
this);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Descriptor read failed, code: %d", rc);
|
NIMBLE_LOGE(LOG_TAG, "Error: Failed to read descriptor; rc=%d, %s",
|
||||||
m_semaphoreReadDescrEvt.give();
|
rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
|
m_semaphoreReadDescrEvt.give(0);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,8 +141,14 @@ std::string NimBLERemoteDescriptor::readValue() {
|
||||||
|
|
||||||
switch(rc){
|
switch(rc){
|
||||||
case 0:
|
case 0:
|
||||||
|
case BLE_HS_EDONE:
|
||||||
|
rc = 0;
|
||||||
|
break;
|
||||||
|
// Descriptor is not long-readable, return with what we have.
|
||||||
|
case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
|
||||||
|
NIMBLE_LOGI(LOG_TAG, "Attribute not long");
|
||||||
|
rc = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
|
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
|
||||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR):
|
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR):
|
||||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC):
|
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC):
|
||||||
|
@ -146,9 +160,8 @@ std::string NimBLERemoteDescriptor::readValue() {
|
||||||
}
|
}
|
||||||
} while(rc != 0 && retryCount--);
|
} while(rc != 0 && retryCount--);
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< Descriptor readValue(): length: %d, rc: %d", m_value.length(), rc);
|
NIMBLE_LOGD(LOG_TAG, "<< Descriptor readValue(): length: %d", m_value.length());
|
||||||
|
return m_value;
|
||||||
return (rc == 0) ? m_value : "";
|
|
||||||
} // readValue
|
} // readValue
|
||||||
|
|
||||||
|
|
||||||
|
@ -211,11 +224,7 @@ int NimBLERemoteDescriptor::onWriteCB(uint16_t conn_handle,
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle);
|
NIMBLE_LOGD(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle);
|
||||||
|
|
||||||
if (error->status == 0) {
|
|
||||||
descriptor->m_semaphoreDescWrite.give(0);
|
|
||||||
} else {
|
|
||||||
descriptor->m_semaphoreDescWrite.give(error->status);
|
descriptor->m_semaphoreDescWrite.give(error->status);
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -235,6 +244,7 @@ bool NimBLERemoteDescriptor::writeValue(uint8_t* data, size_t length, bool respo
|
||||||
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int retryCount = 1;
|
int retryCount = 1;
|
||||||
|
uint16_t mtu;
|
||||||
|
|
||||||
// Check to see that we are connected.
|
// Check to see that we are connected.
|
||||||
if (!pClient->isConnected()) {
|
if (!pClient->isConnected()) {
|
||||||
|
@ -242,18 +252,31 @@ bool NimBLERemoteDescriptor::writeValue(uint8_t* data, size_t length, bool respo
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!response) {
|
mtu = ble_att_mtu(pClient->getConnId()) - 3;
|
||||||
|
|
||||||
|
// Check if the data length is longer than we can write in 1 connection event.
|
||||||
|
// If so we must do a long write which requires a response.
|
||||||
|
if(length <= mtu && !response) {
|
||||||
rc = ble_gattc_write_no_rsp_flat(pClient->getConnId(), m_handle, data, length);
|
rc = ble_gattc_write_no_rsp_flat(pClient->getConnId(), m_handle, data, length);
|
||||||
return (rc==0);
|
return (rc == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
m_semaphoreDescWrite.take("WriteDescriptor");
|
m_semaphoreDescWrite.take("WriteDescriptor");
|
||||||
|
|
||||||
|
if(length > mtu) {
|
||||||
|
NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length);
|
||||||
|
os_mbuf *om = ble_hs_mbuf_from_flat(data, length);
|
||||||
|
rc = ble_gattc_write_long(pClient->getConnId(), m_handle, 0, om,
|
||||||
|
NimBLERemoteDescriptor::onWriteCB,
|
||||||
|
this);
|
||||||
|
} else {
|
||||||
rc = ble_gattc_write_flat(pClient->getConnId(), m_handle,
|
rc = ble_gattc_write_flat(pClient->getConnId(), m_handle,
|
||||||
data, length,
|
data, length,
|
||||||
NimBLERemoteDescriptor::onWriteCB,
|
NimBLERemoteDescriptor::onWriteCB,
|
||||||
this);
|
this);
|
||||||
|
}
|
||||||
|
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Error: Failed to write descriptor; rc=%d", rc);
|
NIMBLE_LOGE(LOG_TAG, "Error: Failed to write descriptor; rc=%d", rc);
|
||||||
m_semaphoreDescWrite.give();
|
m_semaphoreDescWrite.give();
|
||||||
|
@ -264,6 +287,13 @@ bool NimBLERemoteDescriptor::writeValue(uint8_t* data, size_t length, bool respo
|
||||||
|
|
||||||
switch(rc){
|
switch(rc){
|
||||||
case 0:
|
case 0:
|
||||||
|
case BLE_HS_EDONE:
|
||||||
|
rc = 0;
|
||||||
|
break;
|
||||||
|
case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Long write not supported by peer; Truncating length to %d", mtu);
|
||||||
|
retryCount++;
|
||||||
|
length = mtu;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
|
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
|
||||||
|
@ -278,7 +308,7 @@ bool NimBLERemoteDescriptor::writeValue(uint8_t* data, size_t length, bool respo
|
||||||
} while(rc != 0 && retryCount--);
|
} while(rc != 0 && retryCount--);
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< Descriptor writeValue, rc: %d",rc);
|
NIMBLE_LOGD(LOG_TAG, "<< Descriptor writeValue, rc: %d",rc);
|
||||||
return (rc == 0); //true;
|
return (rc == 0);
|
||||||
} // writeValue
|
} // writeValue
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue