mirror of
https://github.com/h2zero/esp-nimble-cpp.git
synced 2024-11-24 22:20:55 +01:00
Refactor server code to use vectors instead of maps.
* Use critical sections to access characteristic/descriptor value data. * Remove unnecessary code * Create characteristic semaphore only if needed for indications. * Fix advertising when not broadcasting a service.
This commit is contained in:
parent
44f16e6ee2
commit
e987ad58b2
18 changed files with 471 additions and 1370 deletions
|
@ -12,10 +12,8 @@ idf_component_register(SRCS "src/FreeRTOS.cpp"
|
||||||
"src/NimBLEAdvertising.cpp"
|
"src/NimBLEAdvertising.cpp"
|
||||||
"src/NimBLEBeacon.cpp"
|
"src/NimBLEBeacon.cpp"
|
||||||
"src/NimBLECharacteristic.cpp"
|
"src/NimBLECharacteristic.cpp"
|
||||||
"src/NimBLECharacteristicMap.cpp"
|
|
||||||
"src/NimBLEClient.cpp"
|
"src/NimBLEClient.cpp"
|
||||||
"src/NimBLEDescriptor.cpp"
|
"src/NimBLEDescriptor.cpp"
|
||||||
"src/NimBLEDescriptorMap.cpp"
|
|
||||||
"src/NimBLEDevice.cpp"
|
"src/NimBLEDevice.cpp"
|
||||||
"src/NimBLEEddystoneTLM.cpp"
|
"src/NimBLEEddystoneTLM.cpp"
|
||||||
"src/NimBLEEddystoneURL.cpp"
|
"src/NimBLEEddystoneURL.cpp"
|
||||||
|
@ -26,9 +24,7 @@ idf_component_register(SRCS "src/FreeRTOS.cpp"
|
||||||
"src/NimBLESecurity.cpp"
|
"src/NimBLESecurity.cpp"
|
||||||
"src/NimBLEServer.cpp"
|
"src/NimBLEServer.cpp"
|
||||||
"src/NimBLEService.cpp"
|
"src/NimBLEService.cpp"
|
||||||
"src/NimBLEServiceMap.cpp"
|
|
||||||
"src/NimBLEUtils.cpp"
|
"src/NimBLEUtils.cpp"
|
||||||
"src/NimBLEUUID.cpp"
|
"src/NimBLEUUID.cpp"
|
||||||
"src/NimBLEValue.cpp"
|
|
||||||
INCLUDE_DIRS "src"
|
INCLUDE_DIRS "src"
|
||||||
REQUIRES bt)
|
REQUIRES bt)
|
||||||
|
|
|
@ -22,11 +22,16 @@
|
||||||
|
|
||||||
#include "NimBLEDescriptor.h"
|
#include "NimBLEDescriptor.h"
|
||||||
|
|
||||||
#include <map>
|
#include <vector>
|
||||||
|
|
||||||
#define NIMBLE_DESC_FLAG_NOTIFY 0x0001
|
#define NIMBLE_DESC_FLAG_NOTIFY 0x0001
|
||||||
#define NIMBLE_DESC_FLAG_INDICATE 0x0002
|
#define NIMBLE_DESC_FLAG_INDICATE 0x0002
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t conn_id;
|
||||||
|
uint16_t sub_val;
|
||||||
|
} chr_sub_status_t;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Descriptor for Client Characteristic Configuration.
|
* @brief Descriptor for Client Characteristic Configuration.
|
||||||
|
@ -45,7 +50,7 @@ public:
|
||||||
private:
|
private:
|
||||||
NimBLE2902(NimBLECharacteristic* pCharacterisitic);
|
NimBLE2902(NimBLECharacteristic* pCharacterisitic);
|
||||||
friend class NimBLECharacteristic;
|
friend class NimBLECharacteristic;
|
||||||
std::map<uint16_t, uint16_t> m_subscribedMap;
|
std::vector<chr_sub_status_t> m_subscribedVec;
|
||||||
|
|
||||||
}; // NimBLE2902
|
}; // NimBLE2902
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ struct BLE2904_Data {
|
||||||
|
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Descriptor for Characteristic Presentation Format.
|
* @brief Descriptor for Characteristic Presentation Format.
|
||||||
*
|
*
|
||||||
|
|
|
@ -100,7 +100,8 @@ void NimBLEAdvertising::setMaxInterval(uint16_t maxinterval) {
|
||||||
m_advParams.itvl_max = maxinterval;
|
m_advParams.itvl_max = maxinterval;
|
||||||
} // setMaxInterval
|
} // setMaxInterval
|
||||||
|
|
||||||
// These are dummy functions for now for compatibility
|
|
||||||
|
/* These are dummy functions for now for compatibility */
|
||||||
void NimBLEAdvertising::setMinPreferred(uint16_t mininterval) {
|
void NimBLEAdvertising::setMinPreferred(uint16_t mininterval) {
|
||||||
//m_advData.min_interval = mininterval;
|
//m_advData.min_interval = mininterval;
|
||||||
} //
|
} //
|
||||||
|
@ -108,7 +109,8 @@ void NimBLEAdvertising::setMinPreferred(uint16_t mininterval) {
|
||||||
void NimBLEAdvertising::setMaxPreferred(uint16_t maxinterval) {
|
void NimBLEAdvertising::setMaxPreferred(uint16_t maxinterval) {
|
||||||
//m_advData.max_interval = maxinterval;
|
//m_advData.max_interval = maxinterval;
|
||||||
} //
|
} //
|
||||||
//////////////////////////////////////////////////////////
|
/*******************************************************/
|
||||||
|
|
||||||
|
|
||||||
void NimBLEAdvertising::setScanResponse(bool set) {
|
void NimBLEAdvertising::setScanResponse(bool set) {
|
||||||
m_scanResp = set;
|
m_scanResp = set;
|
||||||
|
@ -204,19 +206,19 @@ void NimBLEAdvertising::start() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int numServices = m_serviceUUIDs.size();
|
|
||||||
int rc = 0;
|
|
||||||
uint8_t addressType;
|
|
||||||
uint8_t payloadLen = 3; //start with 3 bytes for the flags data
|
|
||||||
|
|
||||||
// If already advertising just return
|
// If already advertising just return
|
||||||
if(ble_gap_adv_active()) {
|
if(ble_gap_adv_active()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_customAdvData && !m_advSvcsSet && numServices > 0) {
|
int rc = 0;
|
||||||
for (int i = 0; i < numServices; i++) {
|
|
||||||
if(m_serviceUUIDs[i].getNative()->u.type == BLE_UUID_TYPE_16) {
|
if (!m_customAdvData && !m_advDataSet) {
|
||||||
|
//start with 3 bytes for the flags data
|
||||||
|
uint8_t payloadLen = 3;
|
||||||
|
|
||||||
|
for(auto &it : m_serviceUUIDs) {
|
||||||
|
if(it.getNative()->u.type == BLE_UUID_TYPE_16) {
|
||||||
int add = (m_advData.num_uuids16 > 0) ? 2 : 4;
|
int add = (m_advData.num_uuids16 > 0) ? 2 : 4;
|
||||||
if((payloadLen + add) > 31){
|
if((payloadLen + add) > 31){
|
||||||
m_advData.uuids16_is_complete = 0;
|
m_advData.uuids16_is_complete = 0;
|
||||||
|
@ -225,19 +227,19 @@ void NimBLEAdvertising::start() {
|
||||||
payloadLen += add;
|
payloadLen += add;
|
||||||
|
|
||||||
if(nullptr == (m_advData.uuids16 = (ble_uuid16_t*)realloc(m_advData.uuids16,
|
if(nullptr == (m_advData.uuids16 = (ble_uuid16_t*)realloc(m_advData.uuids16,
|
||||||
(m_advData.num_uuids16 + 1) * sizeof(ble_uuid16_t))))
|
(m_advData.num_uuids16 + 1) * sizeof(ble_uuid16_t))))
|
||||||
{
|
{
|
||||||
NIMBLE_LOGE(LOG_TAG, "Error, no mem");
|
NIMBLE_LOGE(LOG_TAG, "Error, no mem");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
memcpy(&m_advData.uuids16[m_advData.num_uuids16].value,
|
memcpy(&m_advData.uuids16[m_advData.num_uuids16].value,
|
||||||
&m_serviceUUIDs[i].getNative()->u16.value, sizeof(uint16_t));
|
&it.getNative()->u16.value, 2);
|
||||||
|
|
||||||
m_advData.uuids16[m_advData.num_uuids16].u.type = BLE_UUID_TYPE_16;
|
m_advData.uuids16[m_advData.num_uuids16].u.type = BLE_UUID_TYPE_16;
|
||||||
m_advData.uuids16_is_complete = 1;
|
m_advData.uuids16_is_complete = 1;
|
||||||
m_advData.num_uuids16++;
|
m_advData.num_uuids16++;
|
||||||
}
|
}
|
||||||
if(m_serviceUUIDs[i].getNative()->u.type == BLE_UUID_TYPE_32) {
|
if(it.getNative()->u.type == BLE_UUID_TYPE_32) {
|
||||||
int add = (m_advData.num_uuids32 > 0) ? 4 : 6;
|
int add = (m_advData.num_uuids32 > 0) ? 4 : 6;
|
||||||
if((payloadLen + add) > 31){
|
if((payloadLen + add) > 31){
|
||||||
m_advData.uuids32_is_complete = 0;
|
m_advData.uuids32_is_complete = 0;
|
||||||
|
@ -246,19 +248,19 @@ void NimBLEAdvertising::start() {
|
||||||
payloadLen += add;
|
payloadLen += add;
|
||||||
|
|
||||||
if(nullptr == (m_advData.uuids32 = (ble_uuid32_t*)realloc(m_advData.uuids32,
|
if(nullptr == (m_advData.uuids32 = (ble_uuid32_t*)realloc(m_advData.uuids32,
|
||||||
(m_advData.num_uuids32 + 1) * sizeof(ble_uuid32_t))))
|
(m_advData.num_uuids32 + 1) * sizeof(ble_uuid32_t))))
|
||||||
{
|
{
|
||||||
NIMBLE_LOGE(LOG_TAG, "Error, no mem");
|
NIMBLE_LOGE(LOG_TAG, "Error, no mem");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
memcpy(&m_advData.uuids32[m_advData.num_uuids32].value,
|
memcpy(&m_advData.uuids32[m_advData.num_uuids32].value,
|
||||||
&m_serviceUUIDs[i].getNative()->u32.value, sizeof(uint32_t));
|
&it.getNative()->u32.value, 4);
|
||||||
|
|
||||||
m_advData.uuids32[m_advData.num_uuids32].u.type = BLE_UUID_TYPE_32;
|
m_advData.uuids32[m_advData.num_uuids32].u.type = BLE_UUID_TYPE_32;
|
||||||
m_advData.uuids32_is_complete = 1;
|
m_advData.uuids32_is_complete = 1;
|
||||||
m_advData.num_uuids32++;
|
m_advData.num_uuids32++;
|
||||||
}
|
}
|
||||||
if(m_serviceUUIDs[i].getNative()->u.type == BLE_UUID_TYPE_128){
|
if(it.getNative()->u.type == BLE_UUID_TYPE_128){
|
||||||
int add = (m_advData.num_uuids128 > 0) ? 16 : 18;
|
int add = (m_advData.num_uuids128 > 0) ? 16 : 18;
|
||||||
if((payloadLen + add) > 31){
|
if((payloadLen + add) > 31){
|
||||||
m_advData.uuids128_is_complete = 0;
|
m_advData.uuids128_is_complete = 0;
|
||||||
|
@ -267,12 +269,13 @@ void NimBLEAdvertising::start() {
|
||||||
payloadLen += add;
|
payloadLen += add;
|
||||||
|
|
||||||
if(nullptr == (m_advData.uuids128 = (ble_uuid128_t*)realloc(m_advData.uuids128,
|
if(nullptr == (m_advData.uuids128 = (ble_uuid128_t*)realloc(m_advData.uuids128,
|
||||||
(m_advData.num_uuids128 + 1) * sizeof(ble_uuid128_t)))) {
|
(m_advData.num_uuids128 + 1) * sizeof(ble_uuid128_t))))
|
||||||
|
{
|
||||||
NIMBLE_LOGE(LOG_TAG, "Error, no mem");
|
NIMBLE_LOGE(LOG_TAG, "Error, no mem");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
memcpy(&m_advData.uuids128[m_advData.num_uuids128].value,
|
memcpy(&m_advData.uuids128[m_advData.num_uuids128].value,
|
||||||
&m_serviceUUIDs[i].getNative()->u128.value, 16);
|
&it.getNative()->u128.value, 16);
|
||||||
|
|
||||||
m_advData.uuids128[m_advData.num_uuids128].u.type = BLE_UUID_TYPE_128;
|
m_advData.uuids128[m_advData.num_uuids128].u.type = BLE_UUID_TYPE_128;
|
||||||
m_advData.uuids128_is_complete = 1;
|
m_advData.uuids128_is_complete = 1;
|
||||||
|
@ -315,11 +318,11 @@ void NimBLEAdvertising::start() {
|
||||||
|
|
||||||
rc = ble_gap_adv_rsp_set_fields(&m_scanData);
|
rc = ble_gap_adv_rsp_set_fields(&m_scanData);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "error setting scan response data; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
NIMBLE_LOGC(LOG_TAG, "error setting scan response data; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
// if not using scan response and there is room,
|
// if not using scan response and there is room,
|
||||||
// throw the tx power data into the advertisment
|
// put the tx power data into the advertisment
|
||||||
} else if (payloadLen < 29) {
|
} else if (payloadLen < 29) {
|
||||||
m_advData.tx_pwr_lvl_is_present = 1;
|
m_advData.tx_pwr_lvl_is_present = 1;
|
||||||
m_advData.tx_pwr_lvl = NimBLEDevice::getPower();
|
m_advData.tx_pwr_lvl = NimBLEDevice::getPower();
|
||||||
|
@ -327,7 +330,7 @@ void NimBLEAdvertising::start() {
|
||||||
|
|
||||||
rc = ble_gap_adv_set_fields(&m_advData);
|
rc = ble_gap_adv_set_fields(&m_advData);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "error setting advertisement data; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
NIMBLE_LOGC(LOG_TAG, "error setting advertisement data; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,22 +352,16 @@ void NimBLEAdvertising::start() {
|
||||||
m_advData.num_uuids16 = 0;
|
m_advData.num_uuids16 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_advSvcsSet = true;
|
m_advDataSet = true;
|
||||||
}
|
|
||||||
|
|
||||||
rc = ble_hs_id_infer_auto(0, &addressType);
|
|
||||||
if (rc != 0) {
|
|
||||||
NIMBLE_LOGC(LOG_TAG, "Error determining address type; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
||||||
abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
rc = ble_gap_adv_start(addressType, NULL, BLE_HS_FOREVER,
|
rc = ble_gap_adv_start(0, NULL, BLE_HS_FOREVER,
|
||||||
&m_advParams,
|
&m_advParams,
|
||||||
(pServer != nullptr) ? NimBLEServer::handleGapEvent : NULL,
|
(pServer != nullptr) ? NimBLEServer::handleGapEvent : NULL,
|
||||||
pServer);
|
pServer);
|
||||||
#else
|
#else
|
||||||
rc = ble_gap_adv_start(addressType, NULL, BLE_HS_FOREVER,
|
rc = ble_gap_adv_start(0, NULL, BLE_HS_FOREVER,
|
||||||
&m_advParams, NULL,NULL);
|
&m_advParams, NULL,NULL);
|
||||||
#endif
|
#endif
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
|
@ -398,7 +395,7 @@ void NimBLEAdvertising::stop() {
|
||||||
* we need clear the flag so it reloads it.
|
* we need clear the flag so it reloads it.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertising::onHostReset() {
|
void NimBLEAdvertising::onHostReset() {
|
||||||
m_advSvcsSet = false;
|
m_advDataSet = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ private:
|
||||||
bool m_customAdvData = false; // Are we using custom advertising data?
|
bool m_customAdvData = false; // Are we using custom advertising data?
|
||||||
bool m_customScanResponseData = false; // Are we using custom scan response data?
|
bool m_customScanResponseData = false; // Are we using custom scan response data?
|
||||||
bool m_scanResp = true;
|
bool m_scanResp = true;
|
||||||
bool m_advSvcsSet = false;
|
bool m_advDataSet = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,18 +22,16 @@
|
||||||
#include "NimBLEUtils.h"
|
#include "NimBLEUtils.h"
|
||||||
#include "NimBLELog.h"
|
#include "NimBLELog.h"
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#define NULL_HANDLE (0xffff)
|
#define NULL_HANDLE (0xffff)
|
||||||
|
|
||||||
static NimBLECharacteristicCallbacks defaultCallback;
|
static NimBLECharacteristicCallbacks defaultCallback;
|
||||||
|
|
||||||
static const char* LOG_TAG = "NimBLECharacteristic";
|
static const char* LOG_TAG = "NimBLECharacteristic";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Construct a characteristic
|
* @brief Construct a characteristic
|
||||||
* @param [in] uuid - UUID (const char*) for the characteristic.
|
* @param [in] uuid - UUID (const char*) for the characteristic.
|
||||||
* @param [in] properties - Properties for the characteristic.
|
* @param [in] properties - Properties for the characteristic.
|
||||||
|
* @param [in] pService - pointer to the service instance this characteristic belongs to.
|
||||||
*/
|
*/
|
||||||
NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties, NimBLEService* pService)
|
NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties, NimBLEService* pService)
|
||||||
: NimBLECharacteristic(NimBLEUUID(uuid), properties, pService) {
|
: NimBLECharacteristic(NimBLEUUID(uuid), properties, pService) {
|
||||||
|
@ -43,6 +41,7 @@ NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties
|
||||||
* @brief Construct a characteristic
|
* @brief Construct a characteristic
|
||||||
* @param [in] uuid - UUID for the characteristic.
|
* @param [in] uuid - UUID for the characteristic.
|
||||||
* @param [in] properties - Properties for the characteristic.
|
* @param [in] properties - Properties for the characteristic.
|
||||||
|
* @param [in] pService - pointer to the service instance this characteristic belongs to.
|
||||||
*/
|
*/
|
||||||
NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t properties, NimBLEService* pService) {
|
NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t properties, NimBLEService* pService) {
|
||||||
m_uuid = uuid;
|
m_uuid = uuid;
|
||||||
|
@ -50,39 +49,24 @@ NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t prop
|
||||||
m_properties = properties;
|
m_properties = properties;
|
||||||
m_pCallbacks = &defaultCallback;
|
m_pCallbacks = &defaultCallback;
|
||||||
m_pService = pService;
|
m_pService = pService;
|
||||||
// Backward Compatibility - to be removed
|
m_value = "";
|
||||||
/* setBroadcastProperty((properties & PROPERTY_BROADCAST) != 0);
|
m_valMux = portMUX_INITIALIZER_UNLOCKED;
|
||||||
setReadProperty((properties & PROPERTY_READ) != 0);
|
|
||||||
setWriteProperty((properties & PROPERTY_WRITE) != 0);
|
if(properties & NIMBLE_PROPERTY::INDICATE){
|
||||||
setNotifyProperty((properties & PROPERTY_NOTIFY) != 0);
|
m_pIndSemaphore = new FreeRTOS::Semaphore("ConfEvt");
|
||||||
setIndicateProperty((properties & PROPERTY_INDICATE) != 0);
|
} else {
|
||||||
setWriteNoResponseProperty((properties & PROPERTY_WRITE_NR) != 0);
|
m_pIndSemaphore = nullptr;
|
||||||
*/
|
}
|
||||||
///////////////////////////////////////////
|
|
||||||
} // NimBLECharacteristic
|
} // NimBLECharacteristic
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Destructor.
|
* @brief Destructor.
|
||||||
*/
|
*/
|
||||||
NimBLECharacteristic::~NimBLECharacteristic() {
|
NimBLECharacteristic::~NimBLECharacteristic() {
|
||||||
} // ~NimBLECharacteristic
|
if(m_pIndSemaphore != nullptr) {
|
||||||
|
delete(m_pIndSemaphore);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Associate a descriptor with this characteristic.
|
|
||||||
* @param [in] pDescriptor
|
|
||||||
* @return N/A.
|
|
||||||
*/
|
|
||||||
void NimBLECharacteristic::addDescriptor(NimBLEDescriptor* pDescriptor) {
|
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> addDescriptor(): Adding %s to %s", pDescriptor->toString().c_str(), toString().c_str());
|
|
||||||
// Check that we don't add the same descriptor twice.
|
|
||||||
if (m_descriptorMap.getByUUID(pDescriptor->getUUID()) != nullptr) {
|
|
||||||
NIMBLE_LOGW(LOG_TAG, "<< Adding a new descriptor with the same UUID as a previous one");
|
|
||||||
//return;
|
|
||||||
}
|
}
|
||||||
m_descriptorMap.setByUUID(pDescriptor->getUUID(), pDescriptor);
|
} // ~NimBLECharacteristic
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< addDescriptor()");
|
|
||||||
} // addDescriptor
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -104,25 +88,26 @@ NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const char* uuid, uint3
|
||||||
*/
|
*/
|
||||||
NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID &uuid, uint32_t properties, uint16_t max_len) {
|
NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID &uuid, uint32_t properties, uint16_t max_len) {
|
||||||
NimBLEDescriptor* pDescriptor = nullptr;
|
NimBLEDescriptor* pDescriptor = nullptr;
|
||||||
if(uuid.equals(NimBLEUUID((uint16_t)0x2902))) {
|
if(uuid == NimBLEUUID(uint16_t(0x2902))) {
|
||||||
if(!(m_properties & BLE_GATT_CHR_F_NOTIFY) && !(m_properties & BLE_GATT_CHR_F_INDICATE)) {
|
if(!(m_properties & BLE_GATT_CHR_F_NOTIFY) && !(m_properties & BLE_GATT_CHR_F_INDICATE)) {
|
||||||
assert(0 && "Cannot create 2902 descriptior without characteristic notification or indication property set");
|
assert(0 && "Cannot create 2902 descriptior without characteristic notification or indication property set");
|
||||||
}
|
}
|
||||||
// We cannot have more than one 2902 descriptor, if it's already been created just return a pointer to it.
|
// We cannot have more than one 2902 descriptor, if it's already been created just return a pointer to it.
|
||||||
pDescriptor = m_descriptorMap.getByUUID(uuid);
|
pDescriptor = getDescriptorByUUID(uuid);
|
||||||
if(pDescriptor == nullptr) {
|
if(pDescriptor == nullptr) {
|
||||||
pDescriptor = new NimBLE2902(this);
|
pDescriptor = new NimBLE2902(this);
|
||||||
} else {
|
} else {
|
||||||
return pDescriptor;
|
return pDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (uuid.equals(NimBLEUUID((uint16_t)0x2904))) {
|
} else if (uuid == NimBLEUUID(uint16_t(0x2904))) {
|
||||||
pDescriptor = new NimBLE2904(this);
|
pDescriptor = new NimBLE2904(this);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
pDescriptor = new NimBLEDescriptor(uuid, properties, max_len, this);
|
pDescriptor = new NimBLEDescriptor(uuid, properties, max_len, this);
|
||||||
}
|
}
|
||||||
addDescriptor(pDescriptor);
|
|
||||||
|
m_dscVec.push_back(pDescriptor);
|
||||||
return pDescriptor;
|
return pDescriptor;
|
||||||
} // createCharacteristic
|
} // createCharacteristic
|
||||||
|
|
||||||
|
@ -132,8 +117,8 @@ NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID &uuid,
|
||||||
* @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve.
|
* @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve.
|
||||||
* @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned.
|
* @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned.
|
||||||
*/
|
*/
|
||||||
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* descriptorUUID) {
|
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* uuid) {
|
||||||
return m_descriptorMap.getByUUID(NimBLEUUID(descriptorUUID));
|
return getDescriptorByUUID(NimBLEUUID(uuid));
|
||||||
} // getDescriptorByUUID
|
} // getDescriptorByUUID
|
||||||
|
|
||||||
|
|
||||||
|
@ -142,8 +127,13 @@ NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* descript
|
||||||
* @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve.
|
* @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve.
|
||||||
* @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned.
|
* @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned.
|
||||||
*/
|
*/
|
||||||
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &descriptorUUID) {
|
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &uuid) {
|
||||||
return m_descriptorMap.getByUUID(descriptorUUID);
|
for (auto &it : m_dscVec) {
|
||||||
|
if (it->getUUID() == uuid) {
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
} // getDescriptorByUUID
|
} // getDescriptorByUUID
|
||||||
|
|
||||||
|
|
||||||
|
@ -155,11 +145,6 @@ uint16_t NimBLECharacteristic::getHandle() {
|
||||||
return m_handle;
|
return m_handle;
|
||||||
} // getHandle
|
} // getHandle
|
||||||
|
|
||||||
/*
|
|
||||||
void NimBLECharacteristic::setAccessPermissions(uint16_t perm) {
|
|
||||||
m_permissions = perm;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
uint8_t NimBLECharacteristic::getProperties() {
|
uint8_t NimBLECharacteristic::getProperties() {
|
||||||
return m_properties;
|
return m_properties;
|
||||||
|
@ -188,25 +173,24 @@ NimBLEUUID NimBLECharacteristic::getUUID() {
|
||||||
* @return A pointer to storage containing the current characteristic value.
|
* @return A pointer to storage containing the current characteristic value.
|
||||||
*/
|
*/
|
||||||
std::string NimBLECharacteristic::getValue() {
|
std::string NimBLECharacteristic::getValue() {
|
||||||
return m_value.getValue();
|
portENTER_CRITICAL(&m_valMux);
|
||||||
|
std::string retVal = m_value;
|
||||||
|
portEXIT_CRITICAL(&m_valMux);
|
||||||
|
|
||||||
|
return retVal;
|
||||||
} // getValue
|
} // getValue
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Retrieve the current raw data of the characteristic.
|
|
||||||
* @return A pointer to storage containing the current characteristic data.
|
|
||||||
*/
|
|
||||||
uint8_t* NimBLECharacteristic::getData() {
|
|
||||||
return m_value.getData();
|
|
||||||
} // getData
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieve the the current data length of the characteristic.
|
* @brief Retrieve the the current data length of the characteristic.
|
||||||
* @return The length of the current characteristic data.
|
* @return The length of the current characteristic data.
|
||||||
*/
|
*/
|
||||||
size_t NimBLECharacteristic:: getDataLength() {
|
size_t NimBLECharacteristic::getDataLength() {
|
||||||
return m_value.getLength();
|
portENTER_CRITICAL(&m_valMux);
|
||||||
|
size_t len = m_value.length();
|
||||||
|
portEXIT_CRITICAL(&m_valMux);
|
||||||
|
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -225,32 +209,41 @@ int NimBLECharacteristic::handleGapEvent(uint16_t conn_handle, uint16_t attr_han
|
||||||
if(ble_uuid_cmp(uuid, &pCharacteristic->getUUID().getNative()->u) == 0){
|
if(ble_uuid_cmp(uuid, &pCharacteristic->getUUID().getNative()->u) == 0){
|
||||||
switch(ctxt->op) {
|
switch(ctxt->op) {
|
||||||
case BLE_GATT_ACCESS_OP_READ_CHR: {
|
case BLE_GATT_ACCESS_OP_READ_CHR: {
|
||||||
//NIMBLE_LOGD(LOG_TAG, "read char pkthdr len:%d flags:%d", ctxt->om->om_pkthdr_len, ctxt->om->om_flags);
|
|
||||||
// If the packet header is only 8 bytes this is a follow up of a long read
|
// If the packet header is only 8 bytes this is a follow up of a long read
|
||||||
// so we don't want to call the onRead() callback again.
|
// so we don't want to call the onRead() callback again.
|
||||||
if(ctxt->om->om_pkthdr_len > 8) {
|
if(ctxt->om->om_pkthdr_len > 8) {
|
||||||
pCharacteristic->m_pCallbacks->onRead(pCharacteristic);
|
pCharacteristic->m_pCallbacks->onRead(pCharacteristic);
|
||||||
}
|
}
|
||||||
rc = os_mbuf_append(ctxt->om, pCharacteristic->getData(), pCharacteristic->m_value.getLength());
|
|
||||||
|
portENTER_CRITICAL(&pCharacteristic->m_valMux);
|
||||||
|
rc = os_mbuf_append(ctxt->om, (uint8_t*)pCharacteristic->m_value.data(),
|
||||||
|
pCharacteristic->m_value.length());
|
||||||
|
portEXIT_CRITICAL(&pCharacteristic->m_valMux);
|
||||||
|
|
||||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||||
}
|
}
|
||||||
|
|
||||||
case BLE_GATT_ACCESS_OP_WRITE_CHR: {
|
case BLE_GATT_ACCESS_OP_WRITE_CHR: {
|
||||||
//NIMBLE_LOGD(LOG_TAG, "write char pkthdr len:%d datalen:%d", ctxt->om->om_pkthdr_len, ctxt->om->om_len);
|
|
||||||
if (ctxt->om->om_len > BLE_ATT_ATTR_MAX_LEN) {
|
if (ctxt->om->om_len > BLE_ATT_ATTR_MAX_LEN) {
|
||||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
//pCharacteristic->setValue(ctxt->om->om_data, ctxt->om->om_len);
|
uint8_t buf[BLE_ATT_ATTR_MAX_LEN];
|
||||||
pCharacteristic->m_value.addPart(ctxt->om->om_data, ctxt->om->om_len);
|
size_t len = ctxt->om->om_len;
|
||||||
|
memcpy(buf, ctxt->om->om_data,len);
|
||||||
|
|
||||||
os_mbuf *next;
|
os_mbuf *next;
|
||||||
next = SLIST_NEXT(ctxt->om, om_next);
|
next = SLIST_NEXT(ctxt->om, om_next);
|
||||||
while(next != NULL){
|
while(next != NULL){
|
||||||
//NIMBLE_LOGD(LOG_TAG, "Found long write data, len:%d", next->om_len);
|
if((len + next->om_len) > BLE_ATT_ATTR_MAX_LEN) {
|
||||||
pCharacteristic->m_value.addPart(next->om_data, next->om_len);
|
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||||
|
}
|
||||||
|
memcpy(&buf[len-1], next->om_data, next->om_len);
|
||||||
|
len += next->om_len;
|
||||||
next = SLIST_NEXT(next, om_next);
|
next = SLIST_NEXT(next, om_next);
|
||||||
}
|
}
|
||||||
pCharacteristic->m_value.commit();
|
|
||||||
|
pCharacteristic->setValue(buf, len);
|
||||||
pCharacteristic->m_pCallbacks->onWrite(pCharacteristic);
|
pCharacteristic->m_pCallbacks->onWrite(pCharacteristic);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -278,14 +271,18 @@ void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) {
|
||||||
subVal |= NIMBLE_DESC_FLAG_INDICATE;
|
subVal |= NIMBLE_DESC_FLAG_INDICATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_semaphoreConfEvt.give((subVal | NIMBLE_DESC_FLAG_INDICATE) ? 0 :
|
if(m_pIndSemaphore != nullptr) {
|
||||||
NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_DISABLED);
|
m_pIndSemaphore->give((subVal & NIMBLE_DESC_FLAG_INDICATE) ? 0 :
|
||||||
|
NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_DISABLED);
|
||||||
|
}
|
||||||
|
|
||||||
NIMBLE_LOGI(LOG_TAG, "New subscribe value for conn: %d val: %d", event->subscribe.conn_handle, subVal);
|
NIMBLE_LOGI(LOG_TAG, "New subscribe value for conn: %d val: %d",
|
||||||
|
event->subscribe.conn_handle, subVal);
|
||||||
|
|
||||||
NimBLE2902* p2902 = (NimBLE2902*)getDescriptorByUUID((uint16_t)0x2902);
|
NimBLE2902* p2902 = (NimBLE2902*)getDescriptorByUUID(uint16_t(0x2902));
|
||||||
if(p2902 == nullptr){
|
if(p2902 == nullptr){
|
||||||
ESP_LOGE(LOG_TAG, "No 2902 descriptor found for %s", getUUID().toString().c_str());
|
ESP_LOGE(LOG_TAG, "No 2902 descriptor found for %s",
|
||||||
|
std::string(getUUID()).c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,21 +291,28 @@ void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) {
|
||||||
p2902->m_pCallbacks->onWrite(p2902);
|
p2902->m_pCallbacks->onWrite(p2902);
|
||||||
|
|
||||||
|
|
||||||
auto it = p2902->m_subscribedMap.find(event->subscribe.conn_handle);
|
auto it = p2902->m_subscribedVec.begin();
|
||||||
if(subVal > 0 && it == p2902->m_subscribedMap.cend()) {
|
for(;it != p2902->m_subscribedVec.end(); ++it) {
|
||||||
p2902->m_subscribedMap.insert(std::pair<uint16_t, uint16_t>(event->subscribe.conn_handle, subVal));
|
if((*it).conn_id == event->subscribe.conn_handle) {
|
||||||
return;
|
break;
|
||||||
} else if(it != p2902->m_subscribedMap.cend()) {
|
}
|
||||||
p2902->m_subscribedMap.erase(event->subscribe.conn_handle);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
if(event->subscribe.reason == BLE_GAP_SUBSCRIBE_REASON_TERM) {
|
if(subVal > 0) {
|
||||||
p2902->m_subscribedMap.erase(event->subscribe.conn_handle);
|
if(it == p2902->m_subscribedVec.end()) {
|
||||||
return;
|
chr_sub_status_t client_sub;
|
||||||
|
client_sub.conn_id = event->subscribe.conn_handle;
|
||||||
|
client_sub.sub_val = subVal;
|
||||||
|
p2902->m_subscribedVec.push_back(client_sub);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*it).sub_val = subVal;
|
||||||
|
|
||||||
|
} else if(it != p2902->m_subscribedVec.end()) {
|
||||||
|
p2902->m_subscribedVec.erase(it);
|
||||||
|
p2902->m_subscribedVec.shrink_to_fit();
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
(*it).second = subVal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -319,7 +323,7 @@ void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) {
|
||||||
* @return N/A
|
* @return N/A
|
||||||
*/
|
*/
|
||||||
void NimBLECharacteristic::indicate() {
|
void NimBLECharacteristic::indicate() {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> indicate: length: %d", m_value.getValue().length());
|
NIMBLE_LOGD(LOG_TAG, ">> indicate: length: %d", getDataLength());
|
||||||
notify(false);
|
notify(false);
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< indicate");
|
NIMBLE_LOGD(LOG_TAG, "<< indicate");
|
||||||
} // indicate
|
} // indicate
|
||||||
|
@ -331,36 +335,38 @@ void NimBLECharacteristic::indicate() {
|
||||||
* @return N/A.
|
* @return N/A.
|
||||||
*/
|
*/
|
||||||
void NimBLECharacteristic::notify(bool is_notification) {
|
void NimBLECharacteristic::notify(bool is_notification) {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> notify: length: %d", m_value.getValue().length());
|
NIMBLE_LOGD(LOG_TAG, ">> notify: length: %d", getDataLength());
|
||||||
|
|
||||||
assert(getService() != nullptr);
|
NimBLE2902* p2902 = (NimBLE2902*)getDescriptorByUUID(uint16_t(0x2902));
|
||||||
assert(getService()->getServer() != nullptr);
|
|
||||||
|
|
||||||
|
if(p2902 == nullptr) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG,
|
||||||
|
"<< notify-Error; Notify/indicate not enabled for characterisitc: %s",
|
||||||
|
std::string(getUUID()).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
if (getService()->getServer()->getConnectedCount() == 0) {
|
if (p2902->m_subscribedVec.size() == 0) {
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< notify: No connected clients.");
|
NIMBLE_LOGD(LOG_TAG, "<< notify: No clients subscribed.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pCallbacks->onNotify(this);
|
m_pCallbacks->onNotify(this);
|
||||||
|
|
||||||
|
std::string value = getValue();
|
||||||
|
size_t length = value.length();
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
NimBLE2902* p2902 = (NimBLE2902*)getDescriptorByUUID((uint16_t)0x2902);
|
|
||||||
|
|
||||||
for (auto it = p2902->m_subscribedMap.cbegin(); it != p2902->m_subscribedMap.cend(); ++it) {
|
for (auto &it : p2902->m_subscribedVec) {
|
||||||
uint16_t _mtu = getService()->getServer()->getPeerMTU((*it).first);
|
uint16_t _mtu = getService()->getServer()->getPeerMTU(it.conn_id);
|
||||||
// Must rebuild the data on each loop iteration as NimBLE will release it.
|
|
||||||
size_t length = m_value.getValue().length();
|
|
||||||
uint8_t* data = (uint8_t*)m_value.getValue().data();
|
|
||||||
os_mbuf *om;
|
os_mbuf *om;
|
||||||
|
|
||||||
if(_mtu == 0) {
|
if(_mtu == 0) {
|
||||||
//NIMBLE_LOGD(LOG_TAG, "peer not connected, removing from map");
|
//NIMBLE_LOGD(LOG_TAG, "peer not connected");
|
||||||
p2902->m_subscribedMap.erase((*it).first);
|
continue;
|
||||||
it = p2902->m_subscribedMap.cbegin();
|
}
|
||||||
if(it == p2902->m_subscribedMap.cend()) {
|
|
||||||
return;
|
if(it.sub_val == 0) {
|
||||||
}
|
//NIMBLE_LOGD(LOG_TAG, "Skipping unsubscribed client");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,54 +374,52 @@ void NimBLECharacteristic::notify(bool is_notification) {
|
||||||
NIMBLE_LOGW(LOG_TAG, "- Truncating to %d bytes (maximum notify size)", _mtu - 3);
|
NIMBLE_LOGW(LOG_TAG, "- Truncating to %d bytes (maximum notify size)", _mtu - 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((*it).second == 0) {
|
if(is_notification && (!(it.sub_val & NIMBLE_DESC_FLAG_NOTIFY))) {
|
||||||
//NIMBLE_LOGI(LOG_TAG, "Skipping unsubscribed client");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_notification && (!((*it).second & NIMBLE_DESC_FLAG_NOTIFY))) {
|
|
||||||
NIMBLE_LOGW(LOG_TAG,
|
NIMBLE_LOGW(LOG_TAG,
|
||||||
"Sending notification to client subscribed to indications, sending indication instead");
|
"Sending notification to client subscribed to indications, sending indication instead");
|
||||||
is_notification = false;
|
is_notification = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!is_notification && (!((*it).second & NIMBLE_DESC_FLAG_INDICATE))) {
|
if(!is_notification && (!(it.sub_val & NIMBLE_DESC_FLAG_INDICATE))) {
|
||||||
NIMBLE_LOGW(LOG_TAG,
|
NIMBLE_LOGW(LOG_TAG,
|
||||||
"Sending indication to client subscribed to notifications, sending notifications instead");
|
"Sending indication to client subscribed to notification, sending notification instead");
|
||||||
is_notification = true;
|
is_notification = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't create the m_buf until we are sure to send the data or else
|
// don't create the m_buf until we are sure to send the data or else
|
||||||
// we could be allocating a buffer that doesn't get released.
|
// we could be allocating a buffer that doesn't get released.
|
||||||
// We also must create it in each loop iteration because it is consumed with each host call.
|
// We also must create it in each loop iteration because it is consumed with each host call.
|
||||||
om = ble_hs_mbuf_from_flat(data, length);
|
om = ble_hs_mbuf_from_flat((uint8_t*)value.data(), length);
|
||||||
|
|
||||||
if(!is_notification) {
|
NimBLECharacteristicCallbacks::Status statusRC;
|
||||||
m_semaphoreConfEvt.take("indicate");
|
if(m_pIndSemaphore != nullptr && !is_notification) {
|
||||||
rc = ble_gattc_indicate_custom((*it).first, m_handle, om);
|
m_pIndSemaphore->take("indicate");
|
||||||
|
rc = ble_gattc_indicate_custom(it.conn_id, m_handle, om);
|
||||||
if(rc != 0){
|
if(rc != 0){
|
||||||
m_semaphoreConfEvt.give();
|
m_pIndSemaphore->give();
|
||||||
m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::ERROR_GATT, rc);
|
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_GATT;
|
||||||
return;
|
} else {
|
||||||
|
rc = m_pIndSemaphore->wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = m_semaphoreConfEvt.wait();
|
if(rc == 0 || rc == BLE_HS_EDONE) {
|
||||||
|
rc = 0;
|
||||||
if(rc == BLE_HS_ETIMEOUT) {
|
statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_INDICATE;
|
||||||
m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_TIMEOUT, rc);
|
} else if(rc == BLE_HS_ETIMEOUT) {
|
||||||
} else if(rc == BLE_HS_EDONE) {
|
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_TIMEOUT;
|
||||||
m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::SUCCESS_INDICATE, rc);
|
|
||||||
} else {
|
} else {
|
||||||
m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_FAILURE, rc);
|
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_FAILURE;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rc = ble_gattc_notify_custom((*it).first, m_handle, om);
|
rc = ble_gattc_notify_custom(it.conn_id, m_handle, om);
|
||||||
if(rc == 0) {
|
if(rc == 0) {
|
||||||
m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::SUCCESS_NOTIFY, 0);
|
statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_NOTIFY;
|
||||||
} else {
|
} else {
|
||||||
m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::ERROR_GATT, rc);
|
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_GATT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_pCallbacks->onStatus(this, statusRC, rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< notify");
|
NIMBLE_LOGD(LOG_TAG, "<< notify");
|
||||||
|
@ -434,87 +438,6 @@ void NimBLECharacteristic::setCallbacks(NimBLECharacteristicCallbacks* pCallback
|
||||||
}
|
}
|
||||||
} // setCallbacks
|
} // setCallbacks
|
||||||
|
|
||||||
// Backward compatibility - to be removed ////////////////////////////////
|
|
||||||
/**
|
|
||||||
* @brief Set the permission to broadcast.
|
|
||||||
* A characteristics has properties associated with it which define what it is capable of doing.
|
|
||||||
* One of these is the broadcast flag.
|
|
||||||
* @param [in] value The flag value of the property.
|
|
||||||
* @return N/A
|
|
||||||
*/
|
|
||||||
void NimBLECharacteristic::setBroadcastProperty(bool value) {
|
|
||||||
if (value) {
|
|
||||||
m_properties = (m_properties | BLE_GATT_CHR_F_BROADCAST);
|
|
||||||
} else {
|
|
||||||
m_properties = (m_properties & ~BLE_GATT_CHR_F_BROADCAST);
|
|
||||||
}
|
|
||||||
} // setBroadcastProperty
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the Indicate property value.
|
|
||||||
* @param [in] value Set to true if we are to allow indicate messages.
|
|
||||||
*/
|
|
||||||
void NimBLECharacteristic::setIndicateProperty(bool value) {
|
|
||||||
if (value) {
|
|
||||||
m_properties = (m_properties | BLE_GATT_CHR_F_INDICATE);
|
|
||||||
} else {
|
|
||||||
m_properties = (m_properties & ~BLE_GATT_CHR_F_INDICATE);
|
|
||||||
}
|
|
||||||
} // setIndicateProperty
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the Notify property value.
|
|
||||||
* @param [in] value Set to true if we are to allow notification messages.
|
|
||||||
*/
|
|
||||||
void NimBLECharacteristic::setNotifyProperty(bool value) {
|
|
||||||
if (value) {
|
|
||||||
m_properties = (m_properties | BLE_GATT_CHR_F_NOTIFY);
|
|
||||||
} else {
|
|
||||||
m_properties = (m_properties & ~BLE_GATT_CHR_F_NOTIFY);
|
|
||||||
}
|
|
||||||
} // setNotifyProperty
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the Read property value.
|
|
||||||
* @param [in] value Set to true if we are to allow reads.
|
|
||||||
*/
|
|
||||||
void NimBLECharacteristic::setReadProperty(bool value) {
|
|
||||||
if (value) {
|
|
||||||
m_properties = (m_properties | BLE_GATT_CHR_F_READ);
|
|
||||||
} else {
|
|
||||||
m_properties = (m_properties & ~BLE_GATT_CHR_F_READ);
|
|
||||||
}
|
|
||||||
} // setReadProperty
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the Write No Response property value.
|
|
||||||
* @param [in] value Set to true if we are to allow writes with no response.
|
|
||||||
*/
|
|
||||||
void NimBLECharacteristic::setWriteNoResponseProperty(bool value) {
|
|
||||||
if (value) {
|
|
||||||
m_properties = (m_properties | BLE_GATT_CHR_F_WRITE_NO_RSP);
|
|
||||||
} else {
|
|
||||||
m_properties = (m_properties & ~BLE_GATT_CHR_F_WRITE_NO_RSP);
|
|
||||||
}
|
|
||||||
} // setWriteNoResponseProperty
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the Write property value.
|
|
||||||
* @param [in] value Set to true if we are to allow writes.
|
|
||||||
*/
|
|
||||||
void NimBLECharacteristic::setWriteProperty(bool value) {
|
|
||||||
if (value) {
|
|
||||||
m_properties = (m_properties | BLE_GATT_CHR_F_WRITE );
|
|
||||||
} else {
|
|
||||||
m_properties = (m_properties & ~BLE_GATT_CHR_F_WRITE );
|
|
||||||
}
|
|
||||||
} // setWriteProperty
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the value of the characteristic.
|
* @brief Set the value of the characteristic.
|
||||||
|
@ -522,21 +445,20 @@ void NimBLECharacteristic::setWriteProperty(bool value) {
|
||||||
* @param [in] length The length of the data in bytes.
|
* @param [in] length The length of the data in bytes.
|
||||||
*/
|
*/
|
||||||
void NimBLECharacteristic::setValue(const uint8_t* data, size_t length) {
|
void NimBLECharacteristic::setValue(const uint8_t* data, size_t length) {
|
||||||
|
#if CONFIG_LOG_DEFAULT_LEVEL > 3 || (ARDUINO_ARCH_ESP32 && CORE_DEBUG_LEVEL >= 4)
|
||||||
char* pHex = NimBLEUtils::buildHexData(nullptr, data, length);
|
char* pHex = NimBLEUtils::buildHexData(nullptr, data, length);
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> setValue: length=%d, data=%s, characteristic UUID=%s", length, pHex, getUUID().toString().c_str());
|
NIMBLE_LOGD(LOG_TAG, ">> setValue: length=%d, data=%s, characteristic UUID=%s", length, pHex, getUUID().toString().c_str());
|
||||||
free(pHex);
|
free(pHex);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (length > BLE_ATT_ATTR_MAX_LEN) {
|
if (length > BLE_ATT_ATTR_MAX_LEN) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, BLE_ATT_ATTR_MAX_LEN);
|
NIMBLE_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, BLE_ATT_ATTR_MAX_LEN);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_value.setValue(data, length);
|
portENTER_CRITICAL(&m_valMux);
|
||||||
|
m_value = std::string((char*)data, length);
|
||||||
// if(m_handle != NULL_HANDLE) {
|
portEXIT_CRITICAL(&m_valMux);
|
||||||
//ble_gatts_chr_updated(m_handle);
|
|
||||||
// ble_gattc_notify(getService()->getServer()->m_connId, m_handle);
|
|
||||||
// }
|
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< setValue");
|
NIMBLE_LOGD(LOG_TAG, "<< setValue");
|
||||||
} // setValue
|
} // setValue
|
||||||
|
|
|
@ -42,42 +42,16 @@ typedef enum {
|
||||||
|
|
||||||
#include "NimBLEService.h"
|
#include "NimBLEService.h"
|
||||||
#include "NimBLEDescriptor.h"
|
#include "NimBLEDescriptor.h"
|
||||||
#include "NimBLEUUID.h"
|
|
||||||
#include "NimBLEValue.h"
|
|
||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
class NimBLEService;
|
class NimBLEService;
|
||||||
class NimBLEDescriptor;
|
class NimBLEDescriptor;
|
||||||
class NimBLECharacteristicCallbacks;
|
class NimBLECharacteristicCallbacks;
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A management structure for %BLE descriptors.
|
|
||||||
*/
|
|
||||||
class NimBLEDescriptorMap {
|
|
||||||
public:
|
|
||||||
void setByUUID(const char* uuid, NimBLEDescriptor* pDescriptor);
|
|
||||||
void setByUUID(const NimBLEUUID &uuid, NimBLEDescriptor* pDescriptor);
|
|
||||||
// void setByHandle(uint16_t handle, NimBLEDescriptor* pDescriptor);
|
|
||||||
NimBLEDescriptor* getByUUID(const char* uuid);
|
|
||||||
NimBLEDescriptor* getByUUID(const NimBLEUUID &uuid);
|
|
||||||
// NimBLEDescriptor* getByHandle(uint16_t handle);
|
|
||||||
std::string toString();
|
|
||||||
NimBLEDescriptor* getFirst();
|
|
||||||
NimBLEDescriptor* getNext();
|
|
||||||
uint8_t getSize();
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::map<NimBLEDescriptor*, std::string> m_uuidMap;
|
|
||||||
// std::map<uint16_t, BLEDescriptor*> m_handleMap;
|
|
||||||
std::map<NimBLEDescriptor*, std::string>::iterator m_iterator;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The model of a %BLE Characteristic.
|
* @brief The model of a %BLE Characteristic.
|
||||||
*
|
*
|
||||||
|
@ -87,84 +61,67 @@ private:
|
||||||
class NimBLECharacteristic {
|
class NimBLECharacteristic {
|
||||||
public:
|
public:
|
||||||
NimBLEDescriptor* createDescriptor(const char* uuid,
|
NimBLEDescriptor* createDescriptor(const char* uuid,
|
||||||
uint32_t properties = NIMBLE_PROPERTY::READ |
|
uint32_t properties =
|
||||||
NIMBLE_PROPERTY::WRITE,
|
NIMBLE_PROPERTY::READ |
|
||||||
uint16_t max_len = 100);
|
NIMBLE_PROPERTY::WRITE,
|
||||||
|
uint16_t max_len = 100);
|
||||||
NimBLEDescriptor* createDescriptor(const NimBLEUUID &uuid,
|
NimBLEDescriptor* createDescriptor(const NimBLEUUID &uuid,
|
||||||
uint32_t properties = NIMBLE_PROPERTY::READ |
|
uint32_t properties =
|
||||||
NIMBLE_PROPERTY::WRITE,
|
NIMBLE_PROPERTY::READ |
|
||||||
uint16_t max_len = 100);
|
NIMBLE_PROPERTY::WRITE,
|
||||||
|
uint16_t max_len = 100);
|
||||||
|
|
||||||
NimBLEDescriptor* getDescriptorByUUID(const char* descriptorUUID);
|
NimBLEDescriptor* getDescriptorByUUID(const char* uuid);
|
||||||
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &descriptorUUID);
|
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &uuid);
|
||||||
NimBLEUUID getUUID();
|
NimBLEUUID getUUID();
|
||||||
std::string getValue();
|
std::string getValue();
|
||||||
uint8_t* getData();
|
|
||||||
size_t getDataLength();
|
size_t getDataLength();
|
||||||
|
void indicate();
|
||||||
void indicate();
|
void notify(bool is_notification = true);
|
||||||
void notify(bool is_notification = true);
|
void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
|
||||||
void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
|
void setValue(const uint8_t* data, size_t size);
|
||||||
// Backward Compatibility - to be removed
|
void setValue(const std::string &value);
|
||||||
void setBroadcastProperty(bool value);
|
void setValue(uint16_t& data16);
|
||||||
void setIndicateProperty(bool value);
|
void setValue(uint32_t& data32);
|
||||||
void setNotifyProperty(bool value);
|
void setValue(int& data32);
|
||||||
void setReadProperty(bool value);
|
void setValue(float& data32);
|
||||||
void setWriteProperty(bool value);
|
void setValue(double& data64);
|
||||||
void setWriteNoResponseProperty(bool value);
|
std::string toString();
|
||||||
//////////////////////////////////////////////////////
|
uint16_t getHandle();
|
||||||
void setValue(const uint8_t* data, size_t size);
|
|
||||||
void setValue(const std::string &value);
|
|
||||||
void setValue(uint16_t& data16);
|
|
||||||
void setValue(uint32_t& data32);
|
|
||||||
void setValue(int& data32);
|
|
||||||
void setValue(float& data32);
|
|
||||||
void setValue(double& data64);
|
|
||||||
|
|
||||||
std::string toString();
|
|
||||||
uint16_t getHandle();
|
|
||||||
// void setAccessPermissions(uint16_t perm);
|
|
||||||
|
|
||||||
// Backward Compatibility - to be removed
|
|
||||||
/* static const uint32_t PROPERTY_READ = 1<<0;
|
|
||||||
static const uint32_t PROPERTY_WRITE = 1<<1;
|
|
||||||
static const uint32_t PROPERTY_NOTIFY = 1<<2;
|
|
||||||
static const uint32_t PROPERTY_BROADCAST = 1<<3;
|
|
||||||
static const uint32_t PROPERTY_INDICATE = 1<<4;
|
|
||||||
static const uint32_t PROPERTY_WRITE_NR = 1<<5;
|
|
||||||
*/
|
|
||||||
//////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
friend class NimBLEServer;
|
friend class NimBLEServer;
|
||||||
friend class NimBLEService;
|
friend class NimBLEService;
|
||||||
// friend class NimBLEDescriptor;
|
|
||||||
// friend class NimBLECharacteristicMap;
|
|
||||||
|
|
||||||
NimBLECharacteristic(const char* uuid, uint16_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
|
NimBLECharacteristic(const char* uuid,
|
||||||
NimBLEService* pService = nullptr);
|
uint16_t properties =
|
||||||
NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
|
NIMBLE_PROPERTY::READ |
|
||||||
NimBLEService* pService = nullptr);
|
NIMBLE_PROPERTY::WRITE,
|
||||||
virtual ~NimBLECharacteristic();
|
NimBLEService* pService = nullptr);
|
||||||
|
NimBLECharacteristic(const NimBLEUUID &uuid,
|
||||||
|
uint16_t properties =
|
||||||
|
NIMBLE_PROPERTY::READ |
|
||||||
|
NIMBLE_PROPERTY::WRITE,
|
||||||
|
NimBLEService* pService = nullptr);
|
||||||
|
|
||||||
NimBLEUUID m_uuid;
|
~NimBLECharacteristic();
|
||||||
NimBLEDescriptorMap m_descriptorMap;
|
|
||||||
uint16_t m_handle;
|
|
||||||
uint16_t m_properties;
|
|
||||||
NimBLECharacteristicCallbacks* m_pCallbacks;
|
|
||||||
NimBLEService* m_pService;
|
|
||||||
NimBLEValue m_value;
|
|
||||||
// uint16_t m_permissions;
|
|
||||||
|
|
||||||
void addDescriptor(NimBLEDescriptor* pDescriptor);
|
|
||||||
NimBLEService* getService();
|
NimBLEService* getService();
|
||||||
uint8_t getProperties();
|
uint8_t getProperties();
|
||||||
void setSubscribe(struct ble_gap_event *event);
|
void setSubscribe(struct ble_gap_event *event);
|
||||||
static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||||
|
|
||||||
FreeRTOS::Semaphore m_semaphoreConfEvt = FreeRTOS::Semaphore("ConfEvt");
|
NimBLEUUID m_uuid;
|
||||||
|
uint16_t m_handle;
|
||||||
|
uint16_t m_properties;
|
||||||
|
NimBLECharacteristicCallbacks* m_pCallbacks;
|
||||||
|
NimBLEService* m_pService;
|
||||||
|
std::string m_value;
|
||||||
|
std::vector<NimBLEDescriptor*> m_dscVec;
|
||||||
|
FreeRTOS::Semaphore *m_pIndSemaphore;
|
||||||
|
portMUX_TYPE m_valMux;
|
||||||
}; // NimBLECharacteristic
|
}; // NimBLECharacteristic
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,132 +0,0 @@
|
||||||
/*
|
|
||||||
* NimBLECharacteristicMap.cpp
|
|
||||||
*
|
|
||||||
* Created: on March 3, 2020
|
|
||||||
* Author H2zero
|
|
||||||
*
|
|
||||||
* BLECharacteristicMap.cpp
|
|
||||||
*
|
|
||||||
* Created on: Jun 22, 2017
|
|
||||||
* Author: kolban
|
|
||||||
*/
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
|
|
||||||
#include "NimBLEService.h"
|
|
||||||
#include "NimBLELog.h"
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the characteristic by handle.
|
|
||||||
* @param [in] handle The handle to look up the characteristic.
|
|
||||||
* @return The characteristic.
|
|
||||||
*/
|
|
||||||
NimBLECharacteristic* NimBLECharacteristicMap::getByHandle(uint16_t handle) {
|
|
||||||
return m_handleMap.at(handle);
|
|
||||||
} // getByHandle
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the characteristic by UUID.
|
|
||||||
* @param [in] UUID The UUID to look up the characteristic.
|
|
||||||
* @return The characteristic.
|
|
||||||
*/
|
|
||||||
NimBLECharacteristic* NimBLECharacteristicMap::getByUUID(const char* uuid) {
|
|
||||||
return getByUUID(NimBLEUUID(uuid));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the characteristic by UUID.
|
|
||||||
* @param [in] UUID The UUID to look up the characteristic.
|
|
||||||
* @return The characteristic.
|
|
||||||
*/
|
|
||||||
NimBLECharacteristic* NimBLECharacteristicMap::getByUUID(const NimBLEUUID &uuid) {
|
|
||||||
for (auto &myPair : m_uuidMap) {
|
|
||||||
if (myPair.first->getUUID().equals(uuid)) {
|
|
||||||
return myPair.first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
} // getByUUID
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the number of characteristics in the map.
|
|
||||||
*/
|
|
||||||
uint8_t NimBLECharacteristicMap::getSize() {
|
|
||||||
return (uint8_t)m_uuidMap.size();
|
|
||||||
} // getSize
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the first characteristic in the map.
|
|
||||||
* @return The first characteristic in the map.
|
|
||||||
*/
|
|
||||||
NimBLECharacteristic* NimBLECharacteristicMap::getFirst() {
|
|
||||||
m_iterator = m_uuidMap.begin();
|
|
||||||
if (m_iterator == m_uuidMap.end()) return nullptr;
|
|
||||||
NimBLECharacteristic* pRet = m_iterator->first;
|
|
||||||
m_iterator++;
|
|
||||||
return pRet;
|
|
||||||
} // getFirst
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the next characteristic in the map.
|
|
||||||
* @return The next characteristic in the map.
|
|
||||||
*/
|
|
||||||
NimBLECharacteristic* NimBLECharacteristicMap::getNext() {
|
|
||||||
if (m_iterator == m_uuidMap.end()) return nullptr;
|
|
||||||
NimBLECharacteristic* pRet = m_iterator->first;
|
|
||||||
m_iterator++;
|
|
||||||
return pRet;
|
|
||||||
} // getNext
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the characteristic by handle.
|
|
||||||
* @param [in] handle The handle of the characteristic.
|
|
||||||
* @param [in] characteristic The characteristic to cache.
|
|
||||||
* @return N/A.
|
|
||||||
*/
|
|
||||||
void NimBLECharacteristicMap::setByHandle(uint16_t handle, NimBLECharacteristic* characteristic) {
|
|
||||||
m_handleMap.insert(std::pair<uint16_t, NimBLECharacteristic*>(handle, characteristic));
|
|
||||||
} // setByHandle
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the characteristic by UUID.
|
|
||||||
* @param [in] uuid The uuid of the characteristic.
|
|
||||||
* @param [in] characteristic The characteristic to cache.
|
|
||||||
* @return N/A.
|
|
||||||
*/
|
|
||||||
void NimBLECharacteristicMap::setByUUID(NimBLECharacteristic* pCharacteristic, const NimBLEUUID &uuid) {
|
|
||||||
m_uuidMap.insert(std::pair<NimBLECharacteristic*, std::string>(pCharacteristic, uuid.toString()));
|
|
||||||
} // setByUUID
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return a string representation of the characteristic map.
|
|
||||||
* @return A string representation of the characteristic map.
|
|
||||||
*/
|
|
||||||
std::string NimBLECharacteristicMap::toString() {
|
|
||||||
std::string res;
|
|
||||||
int count = 0;
|
|
||||||
char hex[5];
|
|
||||||
for (auto &myPair: m_uuidMap) {
|
|
||||||
if (count > 0) {res += "\n";}
|
|
||||||
snprintf(hex, sizeof(hex), "%04x", myPair.first->getHandle());
|
|
||||||
count++;
|
|
||||||
res += "handle: 0x";
|
|
||||||
res += hex;
|
|
||||||
res += ", uuid: " + myPair.first->getUUID().toString();
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
} // toString
|
|
||||||
|
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
|
@ -50,6 +50,7 @@ NimBLEDescriptor::NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties, uint16_
|
||||||
m_pCharacteristic = nullptr; // No initial characteristic.
|
m_pCharacteristic = nullptr; // No initial characteristic.
|
||||||
m_pCallbacks = &defaultCallbacks; // No initial callback.
|
m_pCallbacks = &defaultCallbacks; // No initial callback.
|
||||||
m_value.attr_value = (uint8_t*) calloc(max_len,1); // Allocate storage for the value.
|
m_value.attr_value = (uint8_t*) calloc(max_len,1); // Allocate storage for the value.
|
||||||
|
m_valMux = portMUX_INITIALIZER_UNLOCKED;
|
||||||
m_properties = 0;
|
m_properties = 0;
|
||||||
|
|
||||||
if (properties & BLE_GATT_CHR_F_READ) { // convert uint16_t properties to uint8_t
|
if (properties & BLE_GATT_CHR_F_READ) { // convert uint16_t properties to uint8_t
|
||||||
|
@ -137,17 +138,37 @@ int NimBLEDescriptor::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||||
if(ble_uuid_cmp(uuid, &pDescriptor->getUUID().getNative()->u) == 0){
|
if(ble_uuid_cmp(uuid, &pDescriptor->getUUID().getNative()->u) == 0){
|
||||||
switch(ctxt->op) {
|
switch(ctxt->op) {
|
||||||
case BLE_GATT_ACCESS_OP_READ_DSC: {
|
case BLE_GATT_ACCESS_OP_READ_DSC: {
|
||||||
pDescriptor->m_pCallbacks->onRead(pDescriptor);
|
// If the packet header is only 8 bytes 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) {
|
||||||
|
pDescriptor->m_pCallbacks->onRead(pDescriptor);
|
||||||
|
}
|
||||||
|
portENTER_CRITICAL(&pDescriptor->m_valMux);
|
||||||
rc = os_mbuf_append(ctxt->om, pDescriptor->getValue(), pDescriptor->getLength());
|
rc = os_mbuf_append(ctxt->om, pDescriptor->getValue(), pDescriptor->getLength());
|
||||||
|
portEXIT_CRITICAL(&pDescriptor->m_valMux);
|
||||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||||
}
|
}
|
||||||
|
|
||||||
case BLE_GATT_ACCESS_OP_WRITE_DSC: {
|
case BLE_GATT_ACCESS_OP_WRITE_DSC: {
|
||||||
if (ctxt->om->om_len > BLE_ATT_ATTR_MAX_LEN) {
|
if (ctxt->om->om_len > pDescriptor->m_value.attr_max_len) {
|
||||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
pDescriptor->setValue(ctxt->om->om_data, ctxt->om->om_len);
|
uint8_t buf[pDescriptor->m_value.attr_max_len];
|
||||||
|
size_t len = ctxt->om->om_len;
|
||||||
|
memcpy(buf, ctxt->om->om_data,len);
|
||||||
|
os_mbuf *next;
|
||||||
|
next = SLIST_NEXT(ctxt->om, om_next);
|
||||||
|
while(next != NULL){
|
||||||
|
if((len + next->om_len) > pDescriptor->m_value.attr_max_len) {
|
||||||
|
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||||
|
}
|
||||||
|
memcpy(&buf[len-1], next->om_data, next->om_len);
|
||||||
|
len += next->om_len;
|
||||||
|
next = SLIST_NEXT(next, om_next);
|
||||||
|
}
|
||||||
|
|
||||||
|
pDescriptor->setValue(buf, len);
|
||||||
pDescriptor->m_pCallbacks->onWrite(pDescriptor);
|
pDescriptor->m_pCallbacks->onWrite(pDescriptor);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -191,12 +212,14 @@ void NimBLEDescriptor::setHandle(uint16_t handle) {
|
||||||
* @param [in] length The length of the data in bytes.
|
* @param [in] length The length of the data in bytes.
|
||||||
*/
|
*/
|
||||||
void NimBLEDescriptor::setValue(const uint8_t* data, size_t length) {
|
void NimBLEDescriptor::setValue(const uint8_t* data, size_t length) {
|
||||||
if (length > BLE_ATT_ATTR_MAX_LEN) {
|
if (length > m_value.attr_max_len) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, BLE_ATT_ATTR_MAX_LEN);
|
NIMBLE_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, m_value.attr_max_len);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
portENTER_CRITICAL(&m_valMux);
|
||||||
m_value.attr_len = length;
|
m_value.attr_len = length;
|
||||||
memcpy(m_value.attr_value, data, length);
|
memcpy(m_value.attr_value, data, length);
|
||||||
|
portEXIT_CRITICAL(&m_valMux);
|
||||||
} // setValue
|
} // setValue
|
||||||
|
|
||||||
|
|
||||||
|
@ -209,13 +232,6 @@ void NimBLEDescriptor::setValue(const std::string &value) {
|
||||||
} // setValue
|
} // setValue
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
void NimBLEDescriptor::setAccessPermissions(uint8_t perm) {
|
|
||||||
m_permissions = perm;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return a string representation of the descriptor.
|
* @brief Return a string representation of the descriptor.
|
||||||
* @return A string representation of the descriptor.
|
* @return A string representation of the descriptor.
|
||||||
|
|
|
@ -29,13 +29,11 @@
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint16_t attr_max_len; /*!< attribute max value length */
|
uint16_t attr_max_len; /*!< attribute max value length */
|
||||||
uint16_t attr_len; /*!< attribute current value length */
|
uint16_t attr_len; /*!< attribute current value length */
|
||||||
uint8_t *attr_value; /*!< the pointer to attribute value */
|
uint8_t *attr_value; /*!< the pointer to attribute value */
|
||||||
} attr_value_t;
|
} attr_value_t;
|
||||||
|
|
||||||
typedef attr_value_t esp_attr_value_t; /*!< compatibility for esp32 */
|
|
||||||
|
|
||||||
class NimBLEService;
|
class NimBLEService;
|
||||||
class NimBLECharacteristic;
|
class NimBLECharacteristic;
|
||||||
class NimBLEDescriptorCallbacks;
|
class NimBLEDescriptorCallbacks;
|
||||||
|
@ -46,32 +44,34 @@ class NimBLEDescriptorCallbacks;
|
||||||
*/
|
*/
|
||||||
class NimBLEDescriptor {
|
class NimBLEDescriptor {
|
||||||
public:
|
public:
|
||||||
virtual ~NimBLEDescriptor();
|
uint16_t getHandle();
|
||||||
uint16_t getHandle(); // Get the handle of the descriptor.
|
size_t getLength();
|
||||||
size_t getLength(); // Get the length of the value of the descriptor.
|
NimBLEUUID getUUID();
|
||||||
NimBLEUUID getUUID(); // Get the UUID of the descriptor.
|
uint8_t* getValue();
|
||||||
uint8_t* getValue(); // Get a pointer to the value of the descriptor.
|
void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks);
|
||||||
// void setAccessPermissions(uint8_t perm); // Set the permissions of the descriptor.
|
void setValue(const uint8_t* data, size_t size);
|
||||||
void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks); // Set callbacks to be invoked for the descriptor.
|
void setValue(const std::string &value);
|
||||||
void setValue(const uint8_t* data, size_t size); // Set the value of the descriptor as a pointer to data.
|
std::string toString();
|
||||||
void setValue(const std::string &value); // Set the value of the descriptor as a data buffer.
|
|
||||||
|
|
||||||
std::string toString(); // Convert the descriptor to a string representation.
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class NimBLEDescriptorMap;
|
|
||||||
friend class NimBLECharacteristic;
|
friend class NimBLECharacteristic;
|
||||||
friend class NimBLEService;
|
friend class NimBLEService;
|
||||||
friend class NimBLE2902;
|
friend class NimBLE2902;
|
||||||
friend class NimBLE2904;
|
friend class NimBLE2904;
|
||||||
|
|
||||||
NimBLEDescriptor(const char* uuid, uint16_t properties,
|
NimBLEDescriptor(const char* uuid, uint16_t properties,
|
||||||
uint16_t max_len,
|
uint16_t max_len,
|
||||||
NimBLECharacteristic* pCharacteristic);
|
NimBLECharacteristic* pCharacteristic);
|
||||||
|
|
||||||
NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties,
|
NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties,
|
||||||
uint16_t max_len,
|
uint16_t max_len,
|
||||||
NimBLECharacteristic* pCharacteristic);
|
NimBLECharacteristic* pCharacteristic);
|
||||||
|
|
||||||
|
~NimBLEDescriptor();
|
||||||
|
|
||||||
|
static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||||
|
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||||
|
void setHandle(uint16_t handle);
|
||||||
|
|
||||||
NimBLEUUID m_uuid;
|
NimBLEUUID m_uuid;
|
||||||
uint16_t m_handle;
|
uint16_t m_handle;
|
||||||
|
@ -79,12 +79,8 @@ private:
|
||||||
NimBLECharacteristic* m_pCharacteristic;
|
NimBLECharacteristic* m_pCharacteristic;
|
||||||
uint8_t m_properties;
|
uint8_t m_properties;
|
||||||
attr_value_t m_value;
|
attr_value_t m_value;
|
||||||
|
portMUX_TYPE m_valMux;
|
||||||
static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
}; // NimBLEDescriptor
|
||||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
|
||||||
|
|
||||||
void setHandle(uint16_t handle);
|
|
||||||
}; // BLEDescriptor
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,149 +0,0 @@
|
||||||
/*
|
|
||||||
* NimBLEDescriptorMap.cpp
|
|
||||||
*
|
|
||||||
* Created: on March 10, 2020
|
|
||||||
* Author H2zero
|
|
||||||
*
|
|
||||||
* Originally:
|
|
||||||
*
|
|
||||||
* BLEDescriptorMap.cpp
|
|
||||||
*
|
|
||||||
* Created on: Jun 22, 2017
|
|
||||||
* Author: kolban
|
|
||||||
*/
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
|
|
||||||
#include "NimBLECharacteristic.h"
|
|
||||||
#include "NimBLEDescriptor.h"
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the descriptor by UUID.
|
|
||||||
* @param [in] UUID The UUID to look up the descriptor.
|
|
||||||
* @return The descriptor. If not present, then nullptr is returned.
|
|
||||||
*/
|
|
||||||
NimBLEDescriptor* NimBLEDescriptorMap::getByUUID(const char* uuid) {
|
|
||||||
return getByUUID(NimBLEUUID(uuid));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the descriptor by UUID.
|
|
||||||
* @param [in] UUID The UUID to look up the descriptor.
|
|
||||||
* @return The descriptor. If not present, then nullptr is returned.
|
|
||||||
*/
|
|
||||||
NimBLEDescriptor* NimBLEDescriptorMap::getByUUID(const NimBLEUUID &uuid) {
|
|
||||||
for (auto &myPair : m_uuidMap) {
|
|
||||||
if (myPair.first->getUUID().equals(uuid)) {
|
|
||||||
return myPair.first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
} // getByUUID
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the descriptor by handle.
|
|
||||||
* @param [in] handle The handle to look up the descriptor.
|
|
||||||
* @return The descriptor.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
NimBLEDescriptor* NimBLEDescriptorMap::getByHandle(uint16_t handle) {
|
|
||||||
return m_handleMap.at(handle);
|
|
||||||
} // getByHandle
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the descriptor by UUID.
|
|
||||||
* @param [in] uuid The uuid of the descriptor.
|
|
||||||
* @param [in] characteristic The descriptor to cache.
|
|
||||||
* @return N/A.
|
|
||||||
*/
|
|
||||||
void NimBLEDescriptorMap::setByUUID(const char* uuid, NimBLEDescriptor* pDescriptor){
|
|
||||||
m_uuidMap.insert(std::pair<NimBLEDescriptor*, std::string>(pDescriptor, uuid));
|
|
||||||
} // setByUUID
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the descriptor by UUID.
|
|
||||||
* @param [in] uuid The uuid of the descriptor.
|
|
||||||
* @param [in] characteristic The descriptor to cache.
|
|
||||||
* @return N/A.
|
|
||||||
*/
|
|
||||||
void NimBLEDescriptorMap::setByUUID(const NimBLEUUID &uuid, NimBLEDescriptor* pDescriptor) {
|
|
||||||
m_uuidMap.insert(std::pair<NimBLEDescriptor*, std::string>(pDescriptor, uuid.toString()));
|
|
||||||
} // setByUUID
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the descriptor by handle.
|
|
||||||
* @param [in] handle The handle of the descriptor.
|
|
||||||
* @param [in] descriptor The descriptor to cache.
|
|
||||||
* @return N/A.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
void NimBLEDescriptorMap::setByHandle(uint16_t handle, NimBLEDescriptor* pDescriptor) {
|
|
||||||
m_handleMap.insert(std::pair<uint16_t, NimBLEDescriptor*>(handle, pDescriptor));
|
|
||||||
} // setByHandle
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the number of descriptors in the map.
|
|
||||||
*/
|
|
||||||
uint8_t NimBLEDescriptorMap::getSize() {
|
|
||||||
return (uint8_t)m_uuidMap.size();
|
|
||||||
} // getSize
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return a string representation of the descriptor map.
|
|
||||||
* @return A string representation of the descriptor map.
|
|
||||||
*/
|
|
||||||
std::string NimBLEDescriptorMap::toString() {
|
|
||||||
std::string res;
|
|
||||||
char hex[5];
|
|
||||||
int count = 0;
|
|
||||||
for (auto &myPair : m_uuidMap) {
|
|
||||||
if (count > 0) {res += "\n";}
|
|
||||||
snprintf(hex, sizeof(hex), "%04x", myPair.first->getHandle());
|
|
||||||
count++;
|
|
||||||
res += "handle: 0x";
|
|
||||||
res += hex;
|
|
||||||
res += ", uuid: " + myPair.first->getUUID().toString();
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
} // toString
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the first descriptor in the map.
|
|
||||||
* @return The first descriptor in the map.
|
|
||||||
*/
|
|
||||||
NimBLEDescriptor* NimBLEDescriptorMap::getFirst() {
|
|
||||||
m_iterator = m_uuidMap.begin();
|
|
||||||
if (m_iterator == m_uuidMap.end()) return nullptr;
|
|
||||||
NimBLEDescriptor* pRet = m_iterator->first;
|
|
||||||
m_iterator++;
|
|
||||||
return pRet;
|
|
||||||
} // getFirst
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the next descriptor in the map.
|
|
||||||
* @return The next descriptor in the map.
|
|
||||||
*/
|
|
||||||
NimBLEDescriptor* NimBLEDescriptorMap::getNext() {
|
|
||||||
if (m_iterator == m_uuidMap.end()) return nullptr;
|
|
||||||
NimBLEDescriptor* pRet = m_iterator->first;
|
|
||||||
m_iterator++;
|
|
||||||
return pRet;
|
|
||||||
} // getNext
|
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
|
@ -19,7 +19,6 @@
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
|
||||||
#include "NimBLEServer.h"
|
#include "NimBLEServer.h"
|
||||||
#include "NimBLE2902.h"
|
|
||||||
#include "NimBLEUtils.h"
|
#include "NimBLEUtils.h"
|
||||||
#include "NimBLEDevice.h"
|
#include "NimBLEDevice.h"
|
||||||
#include "NimBLELog.h"
|
#include "NimBLELog.h"
|
||||||
|
@ -32,51 +31,46 @@ static NimBLEServerCallbacks defaultCallbacks;
|
||||||
* @brief Construct a %BLE Server
|
* @brief Construct a %BLE Server
|
||||||
*
|
*
|
||||||
* This class is not designed to be individually instantiated. Instead one should create a server by asking
|
* This class is not designed to be individually instantiated. Instead one should create a server by asking
|
||||||
* the BLEDevice class.
|
* the NimBLEDevice class.
|
||||||
*/
|
*/
|
||||||
NimBLEServer::NimBLEServer() {
|
NimBLEServer::NimBLEServer() {
|
||||||
m_connId = BLE_HS_CONN_HANDLE_NONE;
|
// m_svcChgChrHdl = 0xffff; // Future Use
|
||||||
m_svcChgChrHdl = 0xffff;
|
m_pServerCallbacks = &defaultCallbacks;
|
||||||
m_pServerCallbacks = &defaultCallbacks;
|
m_gattsStarted = false;
|
||||||
m_gattsStarted = false;
|
m_advertiseOnDisconnect = true;
|
||||||
} // BLEServer
|
} // NimBLEServer
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a %BLE Service.
|
* @brief Create a %BLE Service.
|
||||||
*
|
|
||||||
* With a %BLE server, we can host one or more services. Invoking this function causes the creation of a definition
|
|
||||||
* of a new service. Every service must have a unique UUID.
|
|
||||||
* @param [in] uuid The UUID of the new service.
|
* @param [in] uuid The UUID of the new service.
|
||||||
* @return A reference to the new service object.
|
* @return A reference to the new service object.
|
||||||
*/
|
*/
|
||||||
NimBLEService* NimBLEServer::createService(const char* uuid) {
|
NimBLEService* NimBLEServer::createService(const char* uuid) {
|
||||||
return createService(NimBLEUUID(uuid));
|
return createService(NimBLEUUID(uuid));
|
||||||
}
|
} // createService
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a %BLE Service.
|
* @brief Create a %BLE Service.
|
||||||
*
|
|
||||||
* With a %BLE server, we can host one or more services. Invoking this function causes the creation of a definition
|
|
||||||
* of a new service. Every service must have a unique UUID.
|
|
||||||
* @param [in] uuid The UUID of the new service.
|
* @param [in] uuid The UUID of the new service.
|
||||||
* @param [in] numHandles The maximum number of handles associated with this service.
|
* @param [in] numHandles The maximum number of handles associated with this service.
|
||||||
* @param [in] inst_id With multiple services with the same UUID we need to provide inst_id value different for each service.
|
* @param [in] inst_id if we have multiple services with the same UUID we need
|
||||||
|
* to provide inst_id value different for each service.
|
||||||
* @return A reference to the new service object.
|
* @return A reference to the new service object.
|
||||||
*/
|
*/
|
||||||
NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid, uint32_t numHandles, uint8_t inst_id) {
|
NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid, uint32_t numHandles, uint8_t inst_id) {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> createService - %s", uuid.toString().c_str());
|
NIMBLE_LOGD(LOG_TAG, ">> createService - %s", uuid.toString().c_str());
|
||||||
|
// TODO: add functionality to use inst_id for multiple services with same uuid
|
||||||
|
(void)inst_id;
|
||||||
// Check that a service with the supplied UUID does not already exist.
|
// Check that a service with the supplied UUID does not already exist.
|
||||||
if (m_serviceMap.getByUUID(uuid) != nullptr) {
|
if(getServiceByUUID(uuid) != nullptr) {
|
||||||
NIMBLE_LOGW(LOG_TAG, "<< Attempt to create a new service with uuid %s but a service with that UUID already exists.",
|
NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s",
|
||||||
uuid.toString().c_str());
|
std::string(uuid).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
NimBLEService* pService = new NimBLEService(uuid, numHandles, this);
|
NimBLEService* pService = new NimBLEService(uuid, numHandles, this);
|
||||||
pService->m_instId = inst_id;
|
m_svcVec.push_back(pService); // Save a reference to this service being on this server.
|
||||||
m_serviceMap.setByUUID(uuid, pService); // Save a reference to this service being on this server.
|
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< createService");
|
NIMBLE_LOGD(LOG_TAG, "<< createService");
|
||||||
return pService;
|
return pService;
|
||||||
|
@ -89,8 +83,8 @@ NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid, uint32_t numH
|
||||||
* @return A reference to the service object.
|
* @return A reference to the service object.
|
||||||
*/
|
*/
|
||||||
NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid) {
|
NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid) {
|
||||||
return m_serviceMap.getByUUID(uuid);
|
return getServiceByUUID(NimBLEUUID(uuid));
|
||||||
}
|
} // getServiceByUUID
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,8 +93,13 @@ NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid) {
|
||||||
* @return A reference to the service object.
|
* @return A reference to the service object.
|
||||||
*/
|
*/
|
||||||
NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID &uuid) {
|
NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID &uuid) {
|
||||||
return m_serviceMap.getByUUID(uuid);
|
for (auto &it : m_svcVec) {
|
||||||
}
|
if (it->getUUID() == uuid) {
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
} // getServiceByUUID
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -109,18 +108,8 @@ NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID &uuid) {
|
||||||
* @return An advertising object.
|
* @return An advertising object.
|
||||||
*/
|
*/
|
||||||
NimBLEAdvertising* NimBLEServer::getAdvertising() {
|
NimBLEAdvertising* NimBLEServer::getAdvertising() {
|
||||||
return BLEDevice::getAdvertising();
|
return NimBLEDevice::getAdvertising();
|
||||||
}
|
} // getAdvertising
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Retrieve the connection id of the last connected client.
|
|
||||||
* @todo Not very useful, should refactor or remove.
|
|
||||||
* @return Client connection id.
|
|
||||||
*/
|
|
||||||
uint16_t NimBLEServer::getConnId() {
|
|
||||||
return m_connId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -143,6 +132,8 @@ void NimBLEServer::start() {
|
||||||
#if CONFIG_LOG_DEFAULT_LEVEL > 3 || (ARDUINO_ARCH_ESP32 && CORE_DEBUG_LEVEL >= 4)
|
#if CONFIG_LOG_DEFAULT_LEVEL > 3 || (ARDUINO_ARCH_ESP32 && CORE_DEBUG_LEVEL >= 4)
|
||||||
ble_gatts_show_local();
|
ble_gatts_show_local();
|
||||||
#endif
|
#endif
|
||||||
|
/*** Future use ***
|
||||||
|
* TODO: implement service changed handling
|
||||||
|
|
||||||
ble_uuid16_t svc = {BLE_UUID_TYPE_16, 0x1801};
|
ble_uuid16_t svc = {BLE_UUID_TYPE_16, 0x1801};
|
||||||
ble_uuid16_t chr = {BLE_UUID_TYPE_16, 0x2a05};
|
ble_uuid16_t chr = {BLE_UUID_TYPE_16, 0x2a05};
|
||||||
|
@ -155,36 +146,25 @@ void NimBLEServer::start() {
|
||||||
}
|
}
|
||||||
|
|
||||||
NIMBLE_LOGI(LOG_TAG, "Service changed characterisic handle: %d", m_svcChgChrHdl);
|
NIMBLE_LOGI(LOG_TAG, "Service changed characterisic handle: %d", m_svcChgChrHdl);
|
||||||
|
*/
|
||||||
|
// Build a vector of characteristics with Notify / Indicate capabilities for event handling
|
||||||
|
for(auto &svc : m_svcVec) {
|
||||||
|
for(auto &chr : svc->m_chrVec) {
|
||||||
|
// if Notify / Indicate is enabled but we didn't create the descriptor
|
||||||
|
// we do it now.
|
||||||
|
if((chr->m_properties & BLE_GATT_CHR_F_INDICATE) ||
|
||||||
|
(chr->m_properties & BLE_GATT_CHR_F_NOTIFY)) {
|
||||||
|
|
||||||
// Build a map of characteristics with Notify / Indicate capabilities for event handling
|
if(nullptr == chr->getDescriptorByUUID(uint16_t(0x2902))) {
|
||||||
uint8_t numSvcs = m_serviceMap.getRegisteredServiceCount();
|
chr->createDescriptor(uint16_t(0x2902));
|
||||||
NimBLEService* pService = m_serviceMap.getFirst();
|
|
||||||
|
|
||||||
for(int i = 0; i < numSvcs; i++) {
|
|
||||||
uint8_t numChrs = pService->m_characteristicMap.getSize();
|
|
||||||
NimBLECharacteristic* pChr = pService->m_characteristicMap.getFirst();
|
|
||||||
|
|
||||||
if(pChr != nullptr) {
|
|
||||||
for( int d = 0; d < numChrs; d++) {
|
|
||||||
// if Notify / Indicate is enabled but we didn't create the descriptor
|
|
||||||
// we do it now.
|
|
||||||
if((pChr->m_properties & BLE_GATT_CHR_F_INDICATE) ||
|
|
||||||
(pChr->m_properties & BLE_GATT_CHR_F_NOTIFY)) {
|
|
||||||
|
|
||||||
if(nullptr == pChr->getDescriptorByUUID("2902")) {
|
|
||||||
pChr->createDescriptor("2902");
|
|
||||||
}
|
|
||||||
m_notifyChrMap.insert(std::pair<uint16_t, NimBLECharacteristic*>
|
|
||||||
(pChr->getHandle(), pChr));
|
|
||||||
}
|
}
|
||||||
pChr = pService->m_characteristicMap.getNext();
|
m_notifyChrVec.push_back(chr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pService = m_serviceMap.getNext();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_gattsStarted = true;
|
m_gattsStarted = true;
|
||||||
}
|
} // start
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -204,15 +184,24 @@ int NimBLEServer::disconnect(uint16_t connId, uint8_t reason) {
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< disconnect()");
|
NIMBLE_LOGD(LOG_TAG, "<< disconnect()");
|
||||||
}
|
} // disconnect
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the server to automatically start advertising when a client disconnects.
|
||||||
|
* @param [in] bool true == advertise, false == don't advertise.
|
||||||
|
*/
|
||||||
|
void NimBLEServer::advertiseOnDisconnect(bool aod) {
|
||||||
|
m_advertiseOnDisconnect = aod;
|
||||||
|
} // advertiseOnDisconnect
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return the number of connected clients.
|
* @brief Return the number of connected clients.
|
||||||
* @return The number of connected clients.
|
* @return The number of connected clients.
|
||||||
*/
|
*/
|
||||||
uint32_t NimBLEServer::getConnectedCount() {
|
size_t NimBLEServer::getConnectedCount() {
|
||||||
return m_connectedServersMap.size();
|
return m_connectedPeersVec.size();
|
||||||
} // getConnectedCount
|
} // getConnectedCount
|
||||||
|
|
||||||
|
|
||||||
|
@ -227,7 +216,7 @@ uint32_t NimBLEServer::getConnectedCount() {
|
||||||
/*STATIC*/int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
/*STATIC*/int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||||
NimBLEServer* server = (NimBLEServer*)arg;
|
NimBLEServer* server = (NimBLEServer*)arg;
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> handleGapEvent: %s",
|
NIMBLE_LOGD(LOG_TAG, ">> handleGapEvent: %s",
|
||||||
NimBLEUtils::gapEventToString(event->type));
|
NimBLEUtils::gapEventToString(event->type));
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct ble_gap_conn_desc desc;
|
struct ble_gap_conn_desc desc;
|
||||||
|
|
||||||
|
@ -236,13 +225,11 @@ uint32_t NimBLEServer::getConnectedCount() {
|
||||||
case BLE_GAP_EVENT_CONNECT: {
|
case BLE_GAP_EVENT_CONNECT: {
|
||||||
if (event->connect.status != 0) {
|
if (event->connect.status != 0) {
|
||||||
/* Connection failed; resume advertising */
|
/* Connection failed; resume advertising */
|
||||||
NIMBLE_LOGC(LOG_TAG, "Connection failed");
|
NIMBLE_LOGE(LOG_TAG, "Connection failed");
|
||||||
NimBLEDevice::startAdvertising();
|
NimBLEDevice::startAdvertising();
|
||||||
server->m_connId = BLE_HS_CONN_HANDLE_NONE;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
server->m_connId = event->connect.conn_handle;
|
server->m_connectedPeersVec.push_back(event->connect.conn_handle);
|
||||||
server->addPeerDevice((void*)server, false, server->m_connId);
|
|
||||||
|
|
||||||
ble_gap_conn_desc desc;
|
ble_gap_conn_desc desc;
|
||||||
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
|
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
|
||||||
|
@ -271,10 +258,15 @@ uint32_t NimBLEServer::getConnectedCount() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
server->removePeerDevice(event->disconnect.conn.conn_handle, false);
|
server->m_connectedPeersVec.erase(std::remove(server->m_connectedPeersVec.begin(),
|
||||||
server->m_connId = BLE_HS_CONN_HANDLE_NONE;
|
server->m_connectedPeersVec.end(),
|
||||||
|
event->disconnect.conn.conn_handle),
|
||||||
|
server->m_connectedPeersVec.end());
|
||||||
server->m_pServerCallbacks->onDisconnect(server);
|
server->m_pServerCallbacks->onDisconnect(server);
|
||||||
|
|
||||||
|
if(server->m_advertiseOnDisconnect) {
|
||||||
|
server->startAdvertising();
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} // BLE_GAP_EVENT_DISCONNECT
|
} // BLE_GAP_EVENT_DISCONNECT
|
||||||
|
|
||||||
|
@ -283,9 +275,11 @@ uint32_t NimBLEServer::getConnectedCount() {
|
||||||
"val_handle=%d\n",
|
"val_handle=%d\n",
|
||||||
event->subscribe.cur_notify, event->subscribe.attr_handle);
|
event->subscribe.cur_notify, event->subscribe.attr_handle);
|
||||||
|
|
||||||
auto it = server->m_notifyChrMap.find(event->subscribe.attr_handle);
|
for(auto &it : server->m_notifyChrVec) {
|
||||||
if(it != server->m_notifyChrMap.cend()) {
|
if(it->getHandle() == event->subscribe.attr_handle) {
|
||||||
(*it).second->setSubscribe(event);
|
it->setSubscribe(event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -295,15 +289,18 @@ uint32_t NimBLEServer::getConnectedCount() {
|
||||||
NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d",
|
NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d",
|
||||||
event->mtu.conn_handle,
|
event->mtu.conn_handle,
|
||||||
event->mtu.value);
|
event->mtu.value);
|
||||||
server->updatePeerMTU(event->mtu.conn_handle, event->mtu.value);
|
|
||||||
return 0;
|
return 0;
|
||||||
} // BLE_GAP_EVENT_MTU
|
} // BLE_GAP_EVENT_MTU
|
||||||
|
|
||||||
case BLE_GAP_EVENT_NOTIFY_TX: {
|
case BLE_GAP_EVENT_NOTIFY_TX: {
|
||||||
if(event->notify_tx.indication && event->notify_tx.status != 0) {
|
if(event->notify_tx.indication && event->notify_tx.status != 0) {
|
||||||
auto it = server->m_notifyChrMap.find(event->notify_tx.attr_handle);
|
for(auto &it : server->m_notifyChrVec) {
|
||||||
if(it != server->m_notifyChrMap.cend()) {
|
if(it->getHandle() == event->notify_tx.attr_handle) {
|
||||||
(*it).second->m_semaphoreConfEvt.give(event->notify_tx.status);
|
if(it->m_pIndSemaphore != nullptr) {
|
||||||
|
it->m_pIndSemaphore->give(event->notify_tx.status);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,7 +346,7 @@ uint32_t NimBLEServer::getConnectedCount() {
|
||||||
} // BLE_GAP_EVENT_ENC_CHANGE
|
} // BLE_GAP_EVENT_ENC_CHANGE
|
||||||
|
|
||||||
case BLE_GAP_EVENT_PASSKEY_ACTION: {
|
case BLE_GAP_EVENT_PASSKEY_ACTION: {
|
||||||
struct ble_sm_io pkey = {0};
|
struct ble_sm_io pkey = {0,0};
|
||||||
|
|
||||||
if (event->passkey.params.action == BLE_SM_IOACT_DISP) {
|
if (event->passkey.params.action == BLE_SM_IOACT_DISP) {
|
||||||
pkey.action = event->passkey.params.action;
|
pkey.action = event->passkey.params.action;
|
||||||
|
@ -416,7 +413,7 @@ uint32_t NimBLEServer::getConnectedCount() {
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< handleGATTServerEvent");
|
NIMBLE_LOGD(LOG_TAG, "<< handleGATTServerEvent");
|
||||||
return 0;
|
return 0;
|
||||||
} // handleGATTServerEvent
|
} // handleGapEvent
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -437,18 +434,6 @@ void NimBLEServer::setCallbacks(NimBLEServerCallbacks* pCallbacks) {
|
||||||
} // setCallbacks
|
} // setCallbacks
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Remove service
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
void BLEServer::removeService(BLEService* service) {
|
|
||||||
service->stop();
|
|
||||||
service->executeDelete();
|
|
||||||
m_serviceMap.removeService(service);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Start advertising.
|
* @brief Start advertising.
|
||||||
*
|
*
|
||||||
|
@ -456,9 +441,7 @@ void BLEServer::removeService(BLEService* service) {
|
||||||
* retrieving the advertising object and invoking start upon it.
|
* retrieving the advertising object and invoking start upon it.
|
||||||
*/
|
*/
|
||||||
void NimBLEServer::startAdvertising() {
|
void NimBLEServer::startAdvertising() {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> startAdvertising");
|
|
||||||
NimBLEDevice::startAdvertising();
|
NimBLEDevice::startAdvertising();
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< startAdvertising");
|
|
||||||
} // startAdvertising
|
} // startAdvertising
|
||||||
|
|
||||||
|
|
||||||
|
@ -466,38 +449,43 @@ void NimBLEServer::startAdvertising() {
|
||||||
* @brief Stop advertising.
|
* @brief Stop advertising.
|
||||||
*/
|
*/
|
||||||
void NimBLEServer::stopAdvertising() {
|
void NimBLEServer::stopAdvertising() {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> stopAdvertising");
|
|
||||||
NimBLEDevice::stopAdvertising();
|
NimBLEDevice::stopAdvertising();
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< stopAdvertising");
|
|
||||||
} // startAdvertising
|
} // startAdvertising
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow to connect GATT server to peer device
|
* @brief Get the MTU of the client.
|
||||||
* Probably can be used in ANCS for iPhone
|
* @returns The client MTU or 0 if not found/connected.
|
||||||
*/
|
*/
|
||||||
/*
|
uint16_t NimBLEServer::getPeerMTU(uint16_t conn_id) {
|
||||||
bool BLEServer::connect(BLEAddress address) {
|
return ble_att_mtu(conn_id);
|
||||||
esp_bd_addr_t addr;
|
} //getPeerMTU
|
||||||
memcpy(&addr, address.getNative(), 6);
|
|
||||||
// Perform the open connection request against the target BLE Server.
|
|
||||||
m_semaphoreOpenEvt.take("connect");
|
/**
|
||||||
esp_err_t errRc = ::esp_ble_gatts_open(
|
* Update connection parameters can be called only after connection has been established
|
||||||
getGattsIf(),
|
*/
|
||||||
addr, // address
|
void NimBLEServer::updateConnParams(uint16_t conn_handle,
|
||||||
1 // direct connection
|
uint16_t minInterval, uint16_t maxInterval,
|
||||||
);
|
uint16_t latency, uint16_t timeout)
|
||||||
if (errRc != ESP_OK) {
|
{
|
||||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_open: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
ble_gap_upd_params params;
|
||||||
return false;
|
|
||||||
|
params.latency = latency;
|
||||||
|
params.itvl_max = maxInterval; // max_int = 0x20*1.25ms = 40ms
|
||||||
|
params.itvl_min = minInterval; // min_int = 0x10*1.25ms = 20ms
|
||||||
|
params.supervision_timeout = timeout; // timeout = 400*10ms = 4000ms
|
||||||
|
params.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; // Minimum length of connection event in 0.625ms units
|
||||||
|
params.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; // Maximum length of connection event in 0.625ms units
|
||||||
|
|
||||||
|
int rc = ble_gap_update_params(conn_handle, ¶ms);
|
||||||
|
if(rc != 0) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
}
|
}
|
||||||
|
} // updateConnParams
|
||||||
|
|
||||||
uint32_t rc = m_semaphoreOpenEvt.wait("connect"); // Wait for the connection to complete.
|
|
||||||
ESP_LOGD(LOG_TAG, "<< connect(), rc=%d", rc==ESP_GATT_OK);
|
|
||||||
return rc == ESP_GATT_OK;
|
|
||||||
} // connect
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
/** Default callback handlers */
|
||||||
|
|
||||||
void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer) {
|
void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer) {
|
||||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onConnect(): Default");
|
NIMBLE_LOGD("NimBLEServerCallbacks", "onConnect(): Default");
|
||||||
|
@ -534,80 +522,6 @@ bool NimBLEServerCallbacks::onConfirmPIN(uint32_t pin){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* multi connect support */
|
|
||||||
void NimBLEServer::updatePeerMTU(uint16_t conn_id, uint16_t mtu) {
|
|
||||||
const std::map<uint16_t, conn_status_t>::iterator it = m_connectedServersMap.find(conn_id);
|
|
||||||
if (it != m_connectedServersMap.end()) {
|
|
||||||
it->second.mtu = mtu;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<uint16_t, conn_status_t> NimBLEServer::getPeerDevices() {
|
|
||||||
return m_connectedServersMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the MTU of the client.
|
|
||||||
* @returns The client MTU or 0 if not found/connected.
|
|
||||||
*/
|
|
||||||
uint16_t NimBLEServer::getPeerMTU(uint16_t conn_id) {
|
|
||||||
auto it = m_connectedServersMap.find(conn_id);
|
|
||||||
if(it != m_connectedServersMap.cend()) {
|
|
||||||
return (*it).second.mtu;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NimBLEServer::addPeerDevice(void* peer, bool _client, uint16_t conn_id) {
|
|
||||||
conn_status_t status = {
|
|
||||||
.peer_device = peer,
|
|
||||||
.connected = true,
|
|
||||||
.mtu = 23
|
|
||||||
};
|
|
||||||
|
|
||||||
m_connectedServersMap.insert(std::pair<uint16_t, conn_status_t>(conn_id, status));
|
|
||||||
}
|
|
||||||
|
|
||||||
void NimBLEServer::removePeerDevice(uint16_t conn_id, bool _client) {
|
|
||||||
m_connectedServersMap.erase(conn_id);
|
|
||||||
}
|
|
||||||
/* multi connect support */
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update connection parameters can be called only after connection has been established
|
|
||||||
*/
|
|
||||||
void NimBLEServer::updateConnParams(uint16_t conn_handle,
|
|
||||||
uint16_t minInterval, uint16_t maxInterval,
|
|
||||||
uint16_t latency, uint16_t timeout,
|
|
||||||
uint16_t minConnTime, uint16_t maxConnTime)
|
|
||||||
{
|
|
||||||
ble_gap_upd_params params;
|
|
||||||
|
|
||||||
params.latency = latency;
|
|
||||||
params.itvl_max = maxInterval; // max_int = 0x20*1.25ms = 40ms
|
|
||||||
params.itvl_min = minInterval; // min_int = 0x10*1.25ms = 20ms
|
|
||||||
params.supervision_timeout = timeout; // timeout = 400*10ms = 4000ms
|
|
||||||
params.min_ce_len = minConnTime; // Minimum length of connection event in 0.625ms units
|
|
||||||
params.max_ce_len = maxConnTime; // Maximum length of connection event in 0.625ms units
|
|
||||||
|
|
||||||
int rc = ble_gap_update_params(conn_handle, ¶ms);
|
|
||||||
if(rc != 0) {
|
|
||||||
NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Don't think this is needed
|
|
||||||
|
|
||||||
void NimBLEServer::onHostReset() {
|
|
||||||
for(auto it = m_notifyChrMap.cbegin(); it != m_notifyChrMap.cend(); ++it) {
|
|
||||||
(*it).second->m_semaphoreConfEvt.give(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
#endif // CONFIG_BT_ENABLED
|
#endif // CONFIG_BT_ENABLED
|
||||||
|
|
|
@ -21,102 +21,58 @@
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
|
||||||
#include "NimBLEAddress.h"
|
#include "NimBLEAddress.h"
|
||||||
#include "NimBLEUUID.h"
|
|
||||||
#include "NimBLEAdvertising.h"
|
#include "NimBLEAdvertising.h"
|
||||||
#include "NimBLEService.h"
|
#include "NimBLEService.h"
|
||||||
#include "NimBLESecurity.h"
|
#include "NimBLESecurity.h"
|
||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
class NimBLEService;
|
class NimBLEService;
|
||||||
class NimBLECharacteristic;
|
class NimBLECharacteristic;
|
||||||
class NimBLEServerCallbacks;
|
class NimBLEServerCallbacks;
|
||||||
|
|
||||||
/* TODO possibly refactor this struct */
|
|
||||||
typedef struct {
|
|
||||||
void *peer_device; // peer device BLEClient or BLEServer - maybe its better to have 2 structures or union here
|
|
||||||
bool connected; // do we need it?
|
|
||||||
uint16_t mtu; // every peer device negotiate own mtu
|
|
||||||
} conn_status_t;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A data structure that manages the %BLE servers owned by a BLE server.
|
|
||||||
*/
|
|
||||||
class NimBLEServiceMap {
|
|
||||||
public:
|
|
||||||
// NimBLEService* getByHandle(uint16_t handle);
|
|
||||||
NimBLEService* getByUUID(const char* uuid);
|
|
||||||
NimBLEService* getByUUID(const NimBLEUUID &uuid, uint8_t inst_id = 0);
|
|
||||||
// void setByHandle(uint16_t handle, NimBLEService* service);
|
|
||||||
void setByUUID(const char* uuid, NimBLEService* service);
|
|
||||||
void setByUUID(const NimBLEUUID &uuid, NimBLEService* service);
|
|
||||||
std::string toString();
|
|
||||||
NimBLEService* getFirst();
|
|
||||||
NimBLEService* getNext();
|
|
||||||
void removeService(NimBLEService *service);
|
|
||||||
int getRegisteredServiceCount();
|
|
||||||
|
|
||||||
private:
|
|
||||||
// std::map<uint16_t, NimBLEService*> m_handleMap;
|
|
||||||
std::map<NimBLEService*, std::string> m_uuidMap;
|
|
||||||
std::map<NimBLEService*, std::string>::iterator m_iterator;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The model of a %BLE server.
|
* @brief The model of a %BLE server.
|
||||||
*/
|
*/
|
||||||
class NimBLEServer {
|
class NimBLEServer {
|
||||||
public:
|
public:
|
||||||
uint32_t getConnectedCount();
|
size_t getConnectedCount();
|
||||||
NimBLEService* createService(const char* uuid);
|
NimBLEService* createService(const char* uuid);
|
||||||
NimBLEService* createService(const NimBLEUUID &uuid, uint32_t numHandles=15, uint8_t inst_id=0);
|
NimBLEService* createService(const NimBLEUUID &uuid, uint32_t numHandles=15,
|
||||||
NimBLEAdvertising* getAdvertising();
|
uint8_t inst_id=0);
|
||||||
void setCallbacks(NimBLEServerCallbacks* pCallbacks);
|
NimBLEAdvertising* getAdvertising();
|
||||||
void startAdvertising();
|
void setCallbacks(NimBLEServerCallbacks* pCallbacks);
|
||||||
void stopAdvertising();
|
void startAdvertising();
|
||||||
void start();
|
void stopAdvertising();
|
||||||
// void removeService(BLEService* service);
|
void start();
|
||||||
NimBLEService* getServiceByUUID(const char* uuid);
|
NimBLEService* getServiceByUUID(const char* uuid);
|
||||||
NimBLEService* getServiceByUUID(const NimBLEUUID &uuid);
|
NimBLEService* getServiceByUUID(const NimBLEUUID &uuid);
|
||||||
int disconnect(uint16_t connID, uint8_t reason = BLE_ERR_REM_USER_CONN_TERM);
|
int disconnect(uint16_t connID,
|
||||||
// bool connect(BLEAddress address);
|
uint8_t reason = BLE_ERR_REM_USER_CONN_TERM);
|
||||||
void updateConnParams(uint16_t conn_handle,
|
void updateConnParams(uint16_t conn_handle,
|
||||||
uint16_t minInterval, uint16_t maxInterval,
|
uint16_t minInterval, uint16_t maxInterval,
|
||||||
uint16_t latency, uint16_t timeout,
|
uint16_t latency, uint16_t timeout);
|
||||||
uint16_t minConnTime=0, uint16_t maxConnTime=0);
|
uint16_t getPeerMTU(uint16_t conn_id);
|
||||||
|
std::vector<uint16_t> getPeerDevices();
|
||||||
/* multi connection support */
|
void advertiseOnDisconnect(bool);
|
||||||
std::map<uint16_t, conn_status_t> getPeerDevices();
|
|
||||||
void addPeerDevice(void* peer, bool is_client, uint16_t conn_id);
|
|
||||||
void removePeerDevice(uint16_t conn_id, bool client);
|
|
||||||
NimBLEServer* getServerByConnId(uint16_t conn_id);
|
|
||||||
void updatePeerMTU(uint16_t connId, uint16_t mtu);
|
|
||||||
uint16_t getPeerMTU(uint16_t conn_id);
|
|
||||||
uint16_t getConnId();
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NimBLEServer();
|
NimBLEServer();
|
||||||
//friend class BLEService;
|
friend class NimBLECharacteristic;
|
||||||
friend class NimBLECharacteristic;
|
friend class NimBLEDevice;
|
||||||
friend class NimBLEDevice;
|
friend class NimBLEAdvertising;
|
||||||
friend class NimBLEAdvertising;
|
|
||||||
// void onHostReset();
|
|
||||||
// BLEAdvertising m_bleAdvertising;
|
|
||||||
uint16_t m_connId;
|
|
||||||
uint16_t m_svcChgChrHdl;
|
|
||||||
bool m_gattsStarted;
|
bool m_gattsStarted;
|
||||||
|
bool m_advertiseOnDisconnect;
|
||||||
std::map<uint16_t, conn_status_t> m_connectedServersMap;
|
|
||||||
std::map<uint16_t, NimBLECharacteristic*> m_notifyChrMap;
|
|
||||||
|
|
||||||
NimBLEServiceMap m_serviceMap;
|
|
||||||
NimBLEServerCallbacks* m_pServerCallbacks;
|
NimBLEServerCallbacks* m_pServerCallbacks;
|
||||||
|
std::vector<uint16_t> m_connectedPeersVec;
|
||||||
|
|
||||||
static int handleGapEvent(struct ble_gap_event *event, void *arg);
|
// uint16_t m_svcChgChrHdl; // Future use
|
||||||
|
|
||||||
|
std::vector<NimBLEService*> m_svcVec;
|
||||||
|
std::vector<NimBLECharacteristic*> m_notifyChrVec;
|
||||||
|
|
||||||
|
static int handleGapEvent(struct ble_gap_event *event, void *arg);
|
||||||
}; // NimBLEServer
|
}; // NimBLEServer
|
||||||
|
|
||||||
|
|
||||||
|
@ -149,7 +105,7 @@ public:
|
||||||
virtual bool onSecurityRequest(); //{return true;}
|
virtual bool onSecurityRequest(); //{return true;}
|
||||||
virtual void onAuthenticationComplete(ble_gap_conn_desc* desc);//{};
|
virtual void onAuthenticationComplete(ble_gap_conn_desc* desc);//{};
|
||||||
virtual bool onConfirmPIN(uint32_t pin);//{return true;}
|
virtual bool onConfirmPIN(uint32_t pin);//{return true;}
|
||||||
}; // BLEServerCallbacks
|
}; // NimBLEServerCallbacks
|
||||||
|
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
|
|
@ -32,9 +32,10 @@ static const char* LOG_TAG = "NimBLEService"; // Tag for logging.
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Construct an instance of the BLEService
|
* @brief Construct an instance of the NimBLEService
|
||||||
* @param [in] uuid The UUID of the service.
|
* @param [in] uuid The UUID of the service.
|
||||||
* @param [in] numHandles The maximum number of handles associated with the service.
|
* @param [in] numHandles The maximum number of handles associated with the service.
|
||||||
|
* @param [in] a pointer to the server instance that this service belongs to.
|
||||||
*/
|
*/
|
||||||
NimBLEService::NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer)
|
NimBLEService::NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer)
|
||||||
: NimBLEService(NimBLEUUID(uuid), numHandles, pServer) {
|
: NimBLEService(NimBLEUUID(uuid), numHandles, pServer) {
|
||||||
|
@ -45,11 +46,12 @@ NimBLEService::NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer
|
||||||
* @brief Construct an instance of the BLEService
|
* @brief Construct an instance of the BLEService
|
||||||
* @param [in] uuid The UUID of the service.
|
* @param [in] uuid The UUID of the service.
|
||||||
* @param [in] numHandles The maximum number of handles associated with the service.
|
* @param [in] numHandles The maximum number of handles associated with the service.
|
||||||
|
* @param [in] a pointer to the server instance that this service belongs to.
|
||||||
*/
|
*/
|
||||||
NimBLEService::NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLEServer* pServer) {
|
NimBLEService::NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLEServer* pServer) {
|
||||||
m_uuid = uuid;
|
m_uuid = uuid;
|
||||||
m_handle = NULL_HANDLE;
|
m_handle = NULL_HANDLE;
|
||||||
m_pServer = pServer;
|
m_pServer = pServer;
|
||||||
m_numHandles = numHandles;
|
m_numHandles = numHandles;
|
||||||
} // NimBLEService
|
} // NimBLEService
|
||||||
|
|
||||||
|
@ -59,10 +61,22 @@ NimBLEService::NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLE
|
||||||
* @return N/A.
|
* @return N/A.
|
||||||
*/
|
*/
|
||||||
void NimBLEService::dump() {
|
void NimBLEService::dump() {
|
||||||
NIMBLE_LOGD(LOG_TAG, "Service: uuid:%s, handle: 0x%.2x",
|
NIMBLE_LOGD(LOG_TAG, "Service: uuid:%s, handle: 0x%2x",
|
||||||
m_uuid.toString().c_str(),
|
m_uuid.toString().c_str(),
|
||||||
m_handle);
|
m_handle);
|
||||||
NIMBLE_LOGD(LOG_TAG, "Characteristics:\n%s", m_characteristicMap.toString().c_str());
|
|
||||||
|
std::string res;
|
||||||
|
int count = 0;
|
||||||
|
char hex[5];
|
||||||
|
for (auto &it: m_chrVec) {
|
||||||
|
if (count > 0) {res += "\n";}
|
||||||
|
snprintf(hex, sizeof(hex), "%04x", it->getHandle());
|
||||||
|
count++;
|
||||||
|
res += "handle: 0x";
|
||||||
|
res += hex;
|
||||||
|
res += ", uuid: " + std::string(it->getUUID());
|
||||||
|
}
|
||||||
|
NIMBLE_LOGD(LOG_TAG, "Characteristics:\n%s", res.c_str());
|
||||||
} // dump
|
} // dump
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,10 +90,9 @@ NimBLEUUID NimBLEService::getUUID() {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Start the service.
|
* @brief Builds the database of characteristics/descriptors for the service
|
||||||
* Here we wish to start the service which means that we will respond to partner requests about it.
|
* and registers it with the NimBLE stack.
|
||||||
* Starting a service also means that we can create the corresponding characteristics.
|
* @return bool success/failure .
|
||||||
* @return Start the service.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool NimBLEService::start() {
|
bool NimBLEService::start() {
|
||||||
|
@ -96,7 +109,7 @@ bool NimBLEService::start() {
|
||||||
svc[0].uuid = &m_uuid.getNative()->u;
|
svc[0].uuid = &m_uuid.getNative()->u;
|
||||||
svc[0].includes = NULL;
|
svc[0].includes = NULL;
|
||||||
|
|
||||||
uint8_t numChrs = m_characteristicMap.getSize();
|
size_t numChrs = m_chrVec.size();
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG,"Adding %d characteristics for service %s", numChrs, toString().c_str());
|
NIMBLE_LOGD(LOG_TAG,"Adding %d characteristics for service %s", numChrs, toString().c_str());
|
||||||
|
|
||||||
|
@ -107,16 +120,17 @@ bool NimBLEService::start() {
|
||||||
// of the characteristics for the service. We create 1 extra and set it to null
|
// of the characteristics for the service. We create 1 extra and set it to null
|
||||||
// for this purpose.
|
// for this purpose.
|
||||||
pChr_a = new ble_gatt_chr_def[numChrs+1];
|
pChr_a = new ble_gatt_chr_def[numChrs+1];
|
||||||
NimBLECharacteristic* pCharacteristic = m_characteristicMap.getFirst();
|
NimBLECharacteristic* pCharacteristic = *m_chrVec.begin();
|
||||||
|
|
||||||
for(uint8_t i=0; i < numChrs; i++) {
|
for(uint8_t i=0; i < numChrs;) {
|
||||||
uint8_t numDscs = pCharacteristic->m_descriptorMap.getSize();
|
uint8_t numDscs = pCharacteristic->m_dscVec.size();
|
||||||
if(numDscs) {
|
if(numDscs) {
|
||||||
// skip 2902 as it's automatically created by NimBLE
|
// skip 2902 as it's automatically created by NimBLE
|
||||||
// if Indicate or Notify flags are set
|
// if Indicate or Notify flags are set
|
||||||
if(((pCharacteristic->m_properties & BLE_GATT_CHR_F_INDICATE) ||
|
if(((pCharacteristic->m_properties & BLE_GATT_CHR_F_INDICATE) ||
|
||||||
(pCharacteristic->m_properties & BLE_GATT_CHR_F_NOTIFY)) &&
|
(pCharacteristic->m_properties & BLE_GATT_CHR_F_NOTIFY)) &&
|
||||||
pCharacteristic->getDescriptorByUUID("2902") != nullptr) {
|
pCharacteristic->getDescriptorByUUID("2902") != nullptr)
|
||||||
|
{
|
||||||
numDscs--;
|
numDscs--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,12 +141,12 @@ bool NimBLEService::start() {
|
||||||
// Must have last descriptor uuid = 0 so we have to create 1 extra
|
// Must have last descriptor uuid = 0 so we have to create 1 extra
|
||||||
//NIMBLE_LOGD(LOG_TAG, "Adding %d descriptors", numDscs);
|
//NIMBLE_LOGD(LOG_TAG, "Adding %d descriptors", numDscs);
|
||||||
pDsc_a = new ble_gatt_dsc_def[numDscs+1];
|
pDsc_a = new ble_gatt_dsc_def[numDscs+1];
|
||||||
NimBLEDescriptor* pDescriptor = pCharacteristic->m_descriptorMap.getFirst();
|
NimBLEDescriptor* pDescriptor = *pCharacteristic->m_dscVec.begin();
|
||||||
for(uint8_t d=0; d < numDscs;) {
|
for(uint8_t d=0; d < numDscs;) {
|
||||||
// skip 2902
|
// skip 2902
|
||||||
if(pDescriptor->m_uuid.equals(NimBLEUUID((uint16_t)0x2902))) {
|
if(pDescriptor->m_uuid == NimBLEUUID(uint16_t(0x2902))) {
|
||||||
//NIMBLE_LOGD(LOG_TAG, "Skipped 0x2902");
|
//NIMBLE_LOGD(LOG_TAG, "Skipped 0x2902");
|
||||||
pDescriptor = pCharacteristic->m_descriptorMap.getNext();
|
pDescriptor = *(pCharacteristic->m_dscVec.begin()+d+1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
pDsc_a[d].uuid = &pDescriptor->m_uuid.getNative()->u;
|
pDsc_a[d].uuid = &pDescriptor->m_uuid.getNative()->u;
|
||||||
|
@ -140,8 +154,8 @@ bool NimBLEService::start() {
|
||||||
pDsc_a[d].min_key_size = 0;
|
pDsc_a[d].min_key_size = 0;
|
||||||
pDsc_a[d].access_cb = NimBLEDescriptor::handleGapEvent;
|
pDsc_a[d].access_cb = NimBLEDescriptor::handleGapEvent;
|
||||||
pDsc_a[d].arg = pDescriptor;
|
pDsc_a[d].arg = pDescriptor;
|
||||||
pDescriptor = pCharacteristic->m_descriptorMap.getNext();
|
|
||||||
d++;
|
d++;
|
||||||
|
pDescriptor = *(pCharacteristic->m_dscVec.begin() + d);
|
||||||
}
|
}
|
||||||
|
|
||||||
pDsc_a[numDscs].uuid = NULL;
|
pDsc_a[numDscs].uuid = NULL;
|
||||||
|
@ -154,7 +168,8 @@ bool NimBLEService::start() {
|
||||||
pChr_a[i].flags = pCharacteristic->m_properties;
|
pChr_a[i].flags = pCharacteristic->m_properties;
|
||||||
pChr_a[i].min_key_size = 0;
|
pChr_a[i].min_key_size = 0;
|
||||||
pChr_a[i].val_handle = &pCharacteristic->m_handle;
|
pChr_a[i].val_handle = &pCharacteristic->m_handle;
|
||||||
pCharacteristic = m_characteristicMap.getNext();
|
i++;
|
||||||
|
pCharacteristic = *(m_chrVec.begin() + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
pChr_a[numChrs].uuid = NULL;
|
pChr_a[numChrs].uuid = NULL;
|
||||||
|
@ -182,21 +197,6 @@ bool NimBLEService::start() {
|
||||||
} // start
|
} // start
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the handle associated with this service.
|
|
||||||
* @param [in] handle The handle associated with the service.
|
|
||||||
*/
|
|
||||||
void NimBLEService::setHandle(uint16_t handle) {
|
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> setHandle - Handle=0x%.2x, service UUID=%s)", handle, getUUID().toString().c_str());
|
|
||||||
if (m_handle != NULL_HANDLE) {
|
|
||||||
NIMBLE_LOGE(LOG_TAG, "!!! Handle is already set %.2x", m_handle);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_handle = handle;
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< setHandle");
|
|
||||||
} // setHandle
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the handle associated with this service.
|
* @brief Get the handle associated with this service.
|
||||||
* @return The handle associated with this service.
|
* @return The handle associated with this service.
|
||||||
|
@ -206,34 +206,6 @@ uint16_t NimBLEService::getHandle() {
|
||||||
} // getHandle
|
} // getHandle
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Add a characteristic to the service.
|
|
||||||
* @param [in] pCharacteristic A pointer to the characteristic to be added.
|
|
||||||
*/
|
|
||||||
void NimBLEService::addCharacteristic(NimBLECharacteristic* pCharacteristic) {
|
|
||||||
// We maintain a mapping of characteristics owned by this service. These are managed by the
|
|
||||||
// BLECharacteristicMap class instance found in m_characteristicMap. We add the characteristic
|
|
||||||
// to the map and then ask the service to add the characteristic at the BLE level (ESP-IDF).
|
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> addCharacteristic()");
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "Adding characteristic: uuid=%s to service: %s",
|
|
||||||
pCharacteristic->getUUID().toString().c_str(),
|
|
||||||
toString().c_str());
|
|
||||||
|
|
||||||
// Check that we don't add the same characteristic twice.
|
|
||||||
if (m_characteristicMap.getByUUID(pCharacteristic->getUUID()) != nullptr) {
|
|
||||||
NIMBLE_LOGW(LOG_TAG, "<< Adding a new characteristic with the same UUID as a previous one");
|
|
||||||
//return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remember this characteristic in our map of characteristics. At this point, we can lookup by UUID
|
|
||||||
// but not by handle. The handle is allocated to us on the ESP_GATTS_ADD_CHAR_EVT.
|
|
||||||
m_characteristicMap.setByUUID(pCharacteristic, pCharacteristic->getUUID());
|
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< addCharacteristic()");
|
|
||||||
} // addCharacteristic
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a new BLE Characteristic associated with this service.
|
* @brief Create a new BLE Characteristic associated with this service.
|
||||||
* @param [in] uuid - The UUID of the characteristic.
|
* @param [in] uuid - The UUID of the characteristic.
|
||||||
|
@ -253,8 +225,15 @@ NimBLECharacteristic* NimBLEService::createCharacteristic(const char* uuid, uint
|
||||||
*/
|
*/
|
||||||
NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid, uint32_t properties) {
|
NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid, uint32_t properties) {
|
||||||
NimBLECharacteristic* pCharacteristic = new NimBLECharacteristic(uuid, properties, this);
|
NimBLECharacteristic* pCharacteristic = new NimBLECharacteristic(uuid, properties, this);
|
||||||
addCharacteristic(pCharacteristic);
|
// Check that we don't add the same characteristic twice.
|
||||||
//pCharacteristic->executeCreate(this);
|
if (getCharacteristic(uuid) != nullptr) {
|
||||||
|
NIMBLE_LOGW(LOG_TAG, "<< Adding a duplicate characteristic with UUID: %s",
|
||||||
|
std::string(uuid).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remember this characteristic in our vector of characteristics.
|
||||||
|
m_chrVec.push_back(pCharacteristic);
|
||||||
|
|
||||||
return pCharacteristic;
|
return pCharacteristic;
|
||||||
} // createCharacteristic
|
} // createCharacteristic
|
||||||
|
|
||||||
|
@ -265,7 +244,13 @@ NimBLECharacteristic* NimBLEService::getCharacteristic(const char* uuid) {
|
||||||
|
|
||||||
|
|
||||||
NimBLECharacteristic* NimBLEService::getCharacteristic(const NimBLEUUID &uuid) {
|
NimBLECharacteristic* NimBLEService::getCharacteristic(const NimBLEUUID &uuid) {
|
||||||
return m_characteristicMap.getByUUID(uuid);
|
for (auto &it : m_chrVec) {
|
||||||
|
if (it->getUUID() == uuid) {
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,28 +29,6 @@
|
||||||
class NimBLEServer;
|
class NimBLEServer;
|
||||||
class NimBLECharacteristic;
|
class NimBLECharacteristic;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A data mapping used to manage the set of %BLE characteristics known to the server.
|
|
||||||
*/
|
|
||||||
class NimBLECharacteristicMap {
|
|
||||||
public:
|
|
||||||
void setByUUID(NimBLECharacteristic* pCharacteristic, const char* uuid);
|
|
||||||
void setByUUID(NimBLECharacteristic* pCharacteristic, const NimBLEUUID &uuid);
|
|
||||||
void setByHandle(uint16_t handle, NimBLECharacteristic* pCharacteristic);
|
|
||||||
NimBLECharacteristic* getByUUID(const char* uuid);
|
|
||||||
NimBLECharacteristic* getByUUID(const NimBLEUUID &uuid);
|
|
||||||
NimBLECharacteristic* getByHandle(uint16_t handle);
|
|
||||||
NimBLECharacteristic* getFirst();
|
|
||||||
NimBLECharacteristic* getNext();
|
|
||||||
uint8_t getSize();
|
|
||||||
std::string toString();
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::map<NimBLECharacteristic*, std::string> m_uuidMap;
|
|
||||||
std::map<uint16_t, NimBLECharacteristic*> m_handleMap;
|
|
||||||
std::map<NimBLECharacteristic*, std::string>::iterator m_iterator;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The model of a %BLE service.
|
* @brief The model of a %BLE service.
|
||||||
|
@ -59,40 +37,39 @@ private:
|
||||||
class NimBLEService {
|
class NimBLEService {
|
||||||
public:
|
public:
|
||||||
NimBLECharacteristic* createCharacteristic(const char* uuid,
|
NimBLECharacteristic* createCharacteristic(const char* uuid,
|
||||||
uint32_t properties = NIMBLE_PROPERTY::READ |
|
uint32_t properties =
|
||||||
|
NIMBLE_PROPERTY::READ |
|
||||||
NIMBLE_PROPERTY::WRITE);
|
NIMBLE_PROPERTY::WRITE);
|
||||||
|
|
||||||
NimBLECharacteristic* createCharacteristic(const NimBLEUUID &uuid,
|
NimBLECharacteristic* createCharacteristic(const NimBLEUUID &uuid,
|
||||||
uint32_t properties = NIMBLE_PROPERTY::READ |
|
uint32_t properties =
|
||||||
NIMBLE_PROPERTY::WRITE);
|
NIMBLE_PROPERTY::READ |
|
||||||
|
NIMBLE_PROPERTY::WRITE);
|
||||||
|
|
||||||
void dump();
|
void dump();
|
||||||
NimBLECharacteristic* getCharacteristic(const char* uuid);
|
NimBLECharacteristic* getCharacteristic(const char* uuid);
|
||||||
NimBLECharacteristic* getCharacteristic(const NimBLEUUID &uuid);
|
NimBLECharacteristic* getCharacteristic(const NimBLEUUID &uuid);
|
||||||
NimBLEUUID getUUID();
|
NimBLEUUID getUUID();
|
||||||
NimBLEServer* getServer();
|
NimBLEServer* getServer();
|
||||||
bool start();
|
bool start();
|
||||||
// void stop();
|
std::string toString();
|
||||||
std::string toString();
|
uint16_t getHandle();
|
||||||
uint16_t getHandle();
|
|
||||||
uint8_t m_instId = 0;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer);
|
NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer);
|
||||||
NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLEServer* pServer);
|
NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLEServer* pServer);
|
||||||
friend class NimBLEServer;
|
|
||||||
friend class NimBLEDevice;
|
|
||||||
|
|
||||||
void addCharacteristic(NimBLECharacteristic* pCharacteristic);
|
friend class NimBLEServer;
|
||||||
|
friend class NimBLEDevice;
|
||||||
|
|
||||||
NimBLECharacteristicMap m_characteristicMap;
|
uint16_t m_handle;
|
||||||
uint16_t m_handle;
|
NimBLEServer* m_pServer;
|
||||||
NimBLEServer* m_pServer = nullptr;
|
NimBLEUUID m_uuid;
|
||||||
NimBLEUUID m_uuid;
|
uint16_t m_numHandles;
|
||||||
|
|
||||||
uint16_t m_numHandles;
|
std::vector<NimBLECharacteristic*> m_chrVec;
|
||||||
void setHandle(uint16_t handle);
|
|
||||||
}; // BLEService
|
}; // NimBLEService
|
||||||
|
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
|
|
@ -1,145 +0,0 @@
|
||||||
/*
|
|
||||||
* NimBLEService.cpp
|
|
||||||
*
|
|
||||||
* Created: on March 7, 2020
|
|
||||||
* Author H2zero
|
|
||||||
*
|
|
||||||
* Originally:
|
|
||||||
*
|
|
||||||
* BLEServiceMap.cpp
|
|
||||||
*
|
|
||||||
* Created on: Jun 22, 2017
|
|
||||||
* Author: kolban
|
|
||||||
*/
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
|
|
||||||
#include "NimBLEService.h"
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the service by UUID.
|
|
||||||
* @param [in] UUID The UUID to look up the service.
|
|
||||||
* @return The characteristic.
|
|
||||||
*/
|
|
||||||
NimBLEService* NimBLEServiceMap::getByUUID(const char* uuid) {
|
|
||||||
return getByUUID(NimBLEUUID(uuid));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the service by UUID.
|
|
||||||
* @param [in] UUID The UUID to look up the service.
|
|
||||||
* @return The characteristic.
|
|
||||||
*/
|
|
||||||
NimBLEService* NimBLEServiceMap::getByUUID(const NimBLEUUID &uuid, uint8_t inst_id) {
|
|
||||||
for (auto &myPair : m_uuidMap) {
|
|
||||||
if (myPair.first->getUUID().equals(uuid)) {
|
|
||||||
return myPair.first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//return m_uuidMap.at(uuid.toString());
|
|
||||||
return nullptr;
|
|
||||||
} // getByUUID
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the service by handle.
|
|
||||||
* @param [in] handle The handle to look up the service.
|
|
||||||
* @return The service.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
NimBLEService* NimBLEServiceMap::getByHandle(uint16_t handle) {
|
|
||||||
return m_handleMap.at(handle);
|
|
||||||
} // getByHandle
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the service by UUID.
|
|
||||||
* @param [in] uuid The uuid of the service.
|
|
||||||
* @param [in] characteristic The service to cache.
|
|
||||||
* @return N/A.
|
|
||||||
*/
|
|
||||||
void NimBLEServiceMap::setByUUID(const NimBLEUUID &uuid, NimBLEService* service) {
|
|
||||||
m_uuidMap.insert(std::pair<NimBLEService*, std::string>(service, uuid.toString()));
|
|
||||||
} // setByUUID
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the service by handle.
|
|
||||||
* @param [in] handle The handle of the service.
|
|
||||||
* @param [in] service The service to cache.
|
|
||||||
* @return N/A.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
void NimBLEServiceMap::setByHandle(uint16_t handle, NimBLEService* service) {
|
|
||||||
m_handleMap.insert(std::pair<uint16_t, NimBLEService*>(handle, service));
|
|
||||||
} // setByHandle
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return a string representation of the service map.
|
|
||||||
* @return A string representation of the service map.
|
|
||||||
*/
|
|
||||||
std::string NimBLEServiceMap::toString() {
|
|
||||||
std::string res;
|
|
||||||
//char hex[5];
|
|
||||||
for (auto &myPair: m_uuidMap) {
|
|
||||||
// res += "handle: 0x";
|
|
||||||
// snprintf(hex, sizeof(hex), "%04x", myPair.first);
|
|
||||||
// res += hex;
|
|
||||||
res += ", uuid: " + myPair.second + "\n";
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
} // toString
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the first service in the map.
|
|
||||||
* @return The first service in the map.
|
|
||||||
*/
|
|
||||||
NimBLEService* NimBLEServiceMap::getFirst() {
|
|
||||||
m_iterator = m_uuidMap.begin();
|
|
||||||
if (m_iterator == m_uuidMap.end()) return nullptr;
|
|
||||||
NimBLEService* pRet = m_iterator->first;
|
|
||||||
m_iterator++;
|
|
||||||
return pRet;
|
|
||||||
} // getFirst
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the next service in the map.
|
|
||||||
* @return The next service in the map.
|
|
||||||
*/
|
|
||||||
NimBLEService* NimBLEServiceMap::getNext() {
|
|
||||||
if (m_iterator == m_uuidMap.end()) return nullptr;
|
|
||||||
NimBLEService* pRet = m_iterator->first;
|
|
||||||
m_iterator++;
|
|
||||||
return pRet;
|
|
||||||
} // getNext
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Removes service from maps.
|
|
||||||
* @return N/A.
|
|
||||||
*/
|
|
||||||
void NimBLEServiceMap::removeService(NimBLEService* service) {
|
|
||||||
//m_handleMap.erase(service->getHandle());
|
|
||||||
m_uuidMap.erase(service);
|
|
||||||
} // removeService
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the amount of registered services
|
|
||||||
* @return amount of registered services
|
|
||||||
*/
|
|
||||||
int NimBLEServiceMap::getRegisteredServiceCount(){
|
|
||||||
//return m_handleMap.size();
|
|
||||||
return m_uuidMap.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
|
@ -1,143 +0,0 @@
|
||||||
/*
|
|
||||||
* NimNimBLEValue.cpp
|
|
||||||
*
|
|
||||||
* Created: on March 6, 2020
|
|
||||||
* Author H2zero
|
|
||||||
*
|
|
||||||
* Originally:
|
|
||||||
*
|
|
||||||
* BLEValue.cpp
|
|
||||||
*
|
|
||||||
* Created on: Jul 17, 2017
|
|
||||||
* Author: kolban
|
|
||||||
*/
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
|
|
||||||
#include "NimBLEValue.h"
|
|
||||||
#include "NimBLELog.h"
|
|
||||||
|
|
||||||
static const char* LOG_TAG="NimBLEValue";
|
|
||||||
|
|
||||||
NimBLEValue::NimBLEValue() {
|
|
||||||
m_accumulation = "";
|
|
||||||
m_value = "";
|
|
||||||
m_readOffset = 0;
|
|
||||||
} // NimBLEValue
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Add a message part to the accumulation.
|
|
||||||
* The accumulation is a growing set of data that is added to until a commit or cancel.
|
|
||||||
* @param [in] part A message part being added.
|
|
||||||
*/
|
|
||||||
void NimBLEValue::addPart(const std::string &part) {
|
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> addPart: length=%d", part.length());
|
|
||||||
m_accumulation += part;
|
|
||||||
} // addPart
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Add a message part to the accumulation.
|
|
||||||
* The accumulation is a growing set of data that is added to until a commit or cancel.
|
|
||||||
* @param [in] pData A message part being added.
|
|
||||||
* @param [in] length The number of bytes being added.
|
|
||||||
*/
|
|
||||||
void NimBLEValue::addPart(const uint8_t* pData, size_t length) {
|
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> addPart: length=%d", length);
|
|
||||||
m_accumulation += std::string((char*) pData, length);
|
|
||||||
} // addPart
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Cancel the current accumulation.
|
|
||||||
*/
|
|
||||||
void NimBLEValue::cancel() {
|
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> cancel");
|
|
||||||
m_accumulation = "";
|
|
||||||
m_readOffset = 0;
|
|
||||||
} // cancel
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Commit the current accumulation.
|
|
||||||
* When writing a value, we may find that we write it in "parts" meaning that the writes come in in pieces
|
|
||||||
* of the overall message. After the last part has been received, we may perform a commit which means that
|
|
||||||
* we now have the complete message and commit the change as a unit.
|
|
||||||
*/
|
|
||||||
void NimBLEValue::commit() {
|
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> commit");
|
|
||||||
// If there is nothing to commit, do nothing.
|
|
||||||
if (m_accumulation.length() == 0) return;
|
|
||||||
setValue(m_accumulation);
|
|
||||||
m_accumulation = "";
|
|
||||||
m_readOffset = 0;
|
|
||||||
} // commit
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get a pointer to the data.
|
|
||||||
* @return A pointer to the data.
|
|
||||||
*/
|
|
||||||
uint8_t* NimBLEValue::getData() {
|
|
||||||
return (uint8_t*) m_value.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the length of the data in bytes.
|
|
||||||
* @return The length of the data in bytes.
|
|
||||||
*/
|
|
||||||
size_t NimBLEValue::getLength() {
|
|
||||||
return m_value.length();
|
|
||||||
} // getLength
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the read offset.
|
|
||||||
* @return The read offset into the read.
|
|
||||||
*/
|
|
||||||
uint16_t NimBLEValue::getReadOffset() {
|
|
||||||
return m_readOffset;
|
|
||||||
} // getReadOffset
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the current value.
|
|
||||||
*/
|
|
||||||
std::string NimBLEValue::getValue() {
|
|
||||||
return m_value;
|
|
||||||
} // getValue
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the read offset
|
|
||||||
* @param [in] readOffset The offset into the read.
|
|
||||||
*/
|
|
||||||
void NimBLEValue::setReadOffset(uint16_t readOffset) {
|
|
||||||
m_readOffset = readOffset;
|
|
||||||
} // setReadOffset
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the current value.
|
|
||||||
*/
|
|
||||||
void NimBLEValue::setValue(const std::string &value) {
|
|
||||||
m_value = value;
|
|
||||||
} // setValue
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the current value.
|
|
||||||
* @param [in] pData The data for the current value.
|
|
||||||
* @param [in] The length of the new current value.
|
|
||||||
*/
|
|
||||||
void NimBLEValue::setValue(const uint8_t* pData, size_t length) {
|
|
||||||
m_value = std::string((char*) pData, length);
|
|
||||||
} // setValue
|
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
#endif // CONFIG_BT_ENABLED
|
|
|
@ -1,52 +0,0 @@
|
||||||
/*
|
|
||||||
* NimBLEValue.h
|
|
||||||
*
|
|
||||||
* Created: on March 6, 2020
|
|
||||||
* Author H2zero
|
|
||||||
*
|
|
||||||
* Originally:
|
|
||||||
*
|
|
||||||
* BLEValue.h
|
|
||||||
*
|
|
||||||
* Created on: Jul 17, 2017
|
|
||||||
* Author: kolban
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MAIN_BLEVALUE_H_
|
|
||||||
#define MAIN_BLEVALUE_H_
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The model of a %BLE value.
|
|
||||||
*/
|
|
||||||
class NimBLEValue {
|
|
||||||
public:
|
|
||||||
NimBLEValue();
|
|
||||||
void addPart(const std::string &part);
|
|
||||||
void addPart(const uint8_t* pData, size_t length);
|
|
||||||
void cancel();
|
|
||||||
void commit();
|
|
||||||
uint8_t* getData();
|
|
||||||
size_t getLength();
|
|
||||||
uint16_t getReadOffset();
|
|
||||||
std::string getValue();
|
|
||||||
void setReadOffset(uint16_t readOffset);
|
|
||||||
void setValue(const std::string &value);
|
|
||||||
void setValue(const uint8_t* pData, size_t length);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string m_accumulation;
|
|
||||||
uint16_t m_readOffset;
|
|
||||||
std::string m_value;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
#endif // CONFIG_BT_ENABLED
|
|
||||||
#endif /* MAIN_BLEVALUE_H_ */
|
|
Loading…
Reference in a new issue