Implement client long read / write

Client will now read/write long characteristics and descriptors.
This commit is contained in:
h2zero
2020-05-07 19:47:41 -06:00
parent 04b524d1f8
commit 59823b4bf0
4 changed files with 158 additions and 104 deletions

View File

@@ -15,6 +15,7 @@
#if defined(CONFIG_BT_ENABLED)
#include "NimBLERemoteDescriptor.h"
#include "NimBLEUtils.h"
#include "NimBLELog.h"
static const char* LOG_TAG = "NimBLERemoteDescriptor";
@@ -83,22 +84,26 @@ int NimBLERemoteDescriptor::onReadCB(uint16_t conn_handle,
struct ble_gatt_attr *attr, void *arg)
{
NimBLERemoteDescriptor* desc = (NimBLERemoteDescriptor*)arg;
uint16_t conn_id = desc->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId();
// Make sure the discovery is for this device
if(desc->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId() != conn_handle){
if(conn_id != conn_handle){
return 0;
}
NIMBLE_LOGD(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
if (error->status == 0) {
desc->m_value = std::string((char*) attr->om->om_data, attr->om->om_len);
desc->m_semaphoreReadDescrEvt.give(0);
} else {
desc->m_value = "";
desc->m_semaphoreReadDescrEvt.give(error->status);
if(error->status == 0){
if(attr){
NIMBLE_LOGD(LOG_TAG, "Got %d bytes", attr->om->om_len);
desc->m_value += std::string((char*) attr->om->om_data, attr->om->om_len);
return 0;
}
}
// Read complete release semaphore and let the app can continue.
desc->m_semaphoreReadDescrEvt.give(error->status);
return 0;
}
@@ -106,10 +111,12 @@ int NimBLERemoteDescriptor::onReadCB(uint16_t conn_handle,
std::string NimBLERemoteDescriptor::readValue() {
NIMBLE_LOGD(LOG_TAG, ">> Descriptor readValue: %s", toString().c_str());
NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
int rc = 0;
int retryCount = 1;
// Clear the value before reading.
m_value = "";
NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
// Check to see that we are connected.
if (!pClient->isConnected()) {
@@ -120,12 +127,13 @@ std::string NimBLERemoteDescriptor::readValue() {
do {
m_semaphoreReadDescrEvt.take("ReadDescriptor");
rc = ble_gattc_read(pClient->getConnId(), m_handle,
NimBLERemoteDescriptor::onReadCB, this);
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
NimBLERemoteDescriptor::onReadCB,
this);
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Descriptor read failed, code: %d", rc);
m_semaphoreReadDescrEvt.give();
NIMBLE_LOGE(LOG_TAG, "Error: Failed to read descriptor; rc=%d, %s",
rc, NimBLEUtils::returnCodeToString(rc));
m_semaphoreReadDescrEvt.give(0);
return "";
}
@@ -133,8 +141,14 @@ std::string NimBLERemoteDescriptor::readValue() {
switch(rc){
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;
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_ENC):
@@ -146,9 +160,8 @@ std::string NimBLERemoteDescriptor::readValue() {
}
} while(rc != 0 && retryCount--);
NIMBLE_LOGD(LOG_TAG, "<< Descriptor readValue(): length: %d, rc: %d", m_value.length(), rc);
return (rc == 0) ? m_value : "";
NIMBLE_LOGD(LOG_TAG, "<< Descriptor readValue(): length: %d", m_value.length());
return m_value;
} // readValue
@@ -204,19 +217,15 @@ int NimBLERemoteDescriptor::onWriteCB(uint16_t conn_handle,
{
NimBLERemoteDescriptor* descriptor = (NimBLERemoteDescriptor*)arg;
// Make sure the discovery is for this device
// Make sure the discovery is for this device
if(descriptor->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId() != conn_handle){
return 0;
}
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;
}
@@ -235,6 +244,7 @@ bool NimBLERemoteDescriptor::writeValue(uint8_t* data, size_t length, bool respo
int rc = 0;
int retryCount = 1;
uint16_t mtu;
// Check to see that we are connected.
if (!pClient->isConnected()) {
@@ -242,18 +252,31 @@ bool NimBLERemoteDescriptor::writeValue(uint8_t* data, size_t length, bool respo
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);
return (rc==0);
return (rc == 0);
}
do {
m_semaphoreDescWrite.take("WriteDescriptor");
rc = ble_gattc_write_flat(pClient->getConnId(), m_handle,
data, length,
NimBLERemoteDescriptor::onWriteCB,
this);
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,
data, length,
NimBLERemoteDescriptor::onWriteCB,
this);
}
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Error: Failed to write descriptor; rc=%d", rc);
m_semaphoreDescWrite.give();
@@ -264,6 +287,13 @@ bool NimBLERemoteDescriptor::writeValue(uint8_t* data, size_t length, bool respo
switch(rc){
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;
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--);
NIMBLE_LOGD(LOG_TAG, "<< Descriptor writeValue, rc: %d",rc);
return (rc == 0); //true;
return (rc == 0);
} // writeValue