mirror of
https://github.com/h2zero/esp-nimble-cpp.git
synced 2024-12-22 19:10:46 +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/NimBLEBeacon.cpp"
|
||||
"src/NimBLECharacteristic.cpp"
|
||||
"src/NimBLECharacteristicMap.cpp"
|
||||
"src/NimBLEClient.cpp"
|
||||
"src/NimBLEDescriptor.cpp"
|
||||
"src/NimBLEDescriptorMap.cpp"
|
||||
"src/NimBLEDevice.cpp"
|
||||
"src/NimBLEEddystoneTLM.cpp"
|
||||
"src/NimBLEEddystoneURL.cpp"
|
||||
|
@ -26,9 +24,7 @@ idf_component_register(SRCS "src/FreeRTOS.cpp"
|
|||
"src/NimBLESecurity.cpp"
|
||||
"src/NimBLEServer.cpp"
|
||||
"src/NimBLEService.cpp"
|
||||
"src/NimBLEServiceMap.cpp"
|
||||
"src/NimBLEUtils.cpp"
|
||||
"src/NimBLEUUID.cpp"
|
||||
"src/NimBLEValue.cpp"
|
||||
INCLUDE_DIRS "src"
|
||||
REQUIRES bt)
|
||||
|
|
|
@ -22,11 +22,16 @@
|
|||
|
||||
#include "NimBLEDescriptor.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#define NIMBLE_DESC_FLAG_NOTIFY 0x0001
|
||||
#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.
|
||||
|
@ -45,7 +50,7 @@ public:
|
|||
private:
|
||||
NimBLE2902(NimBLECharacteristic* pCharacterisitic);
|
||||
friend class NimBLECharacteristic;
|
||||
std::map<uint16_t, uint16_t> m_subscribedMap;
|
||||
std::vector<chr_sub_status_t> m_subscribedVec;
|
||||
|
||||
}; // NimBLE2902
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ struct BLE2904_Data {
|
|||
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/**
|
||||
* @brief Descriptor for Characteristic Presentation Format.
|
||||
*
|
||||
|
|
|
@ -100,7 +100,8 @@ void NimBLEAdvertising::setMaxInterval(uint16_t maxinterval) {
|
|||
m_advParams.itvl_max = maxinterval;
|
||||
} // setMaxInterval
|
||||
|
||||
// These are dummy functions for now for compatibility
|
||||
|
||||
/* These are dummy functions for now for compatibility */
|
||||
void NimBLEAdvertising::setMinPreferred(uint16_t mininterval) {
|
||||
//m_advData.min_interval = mininterval;
|
||||
} //
|
||||
|
@ -108,7 +109,8 @@ void NimBLEAdvertising::setMinPreferred(uint16_t mininterval) {
|
|||
void NimBLEAdvertising::setMaxPreferred(uint16_t maxinterval) {
|
||||
//m_advData.max_interval = maxinterval;
|
||||
} //
|
||||
//////////////////////////////////////////////////////////
|
||||
/*******************************************************/
|
||||
|
||||
|
||||
void NimBLEAdvertising::setScanResponse(bool set) {
|
||||
m_scanResp = set;
|
||||
|
@ -204,19 +206,19 @@ void NimBLEAdvertising::start() {
|
|||
}
|
||||
#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(ble_gap_adv_active()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_customAdvData && !m_advSvcsSet && numServices > 0) {
|
||||
for (int i = 0; i < numServices; i++) {
|
||||
if(m_serviceUUIDs[i].getNative()->u.type == BLE_UUID_TYPE_16) {
|
||||
int rc = 0;
|
||||
|
||||
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;
|
||||
if((payloadLen + add) > 31){
|
||||
m_advData.uuids16_is_complete = 0;
|
||||
|
@ -225,19 +227,19 @@ void NimBLEAdvertising::start() {
|
|||
payloadLen += add;
|
||||
|
||||
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");
|
||||
abort();
|
||||
}
|
||||
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_is_complete = 1;
|
||||
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;
|
||||
if((payloadLen + add) > 31){
|
||||
m_advData.uuids32_is_complete = 0;
|
||||
|
@ -246,19 +248,19 @@ void NimBLEAdvertising::start() {
|
|||
payloadLen += add;
|
||||
|
||||
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");
|
||||
abort();
|
||||
}
|
||||
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_is_complete = 1;
|
||||
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;
|
||||
if((payloadLen + add) > 31){
|
||||
m_advData.uuids128_is_complete = 0;
|
||||
|
@ -267,12 +269,13 @@ void NimBLEAdvertising::start() {
|
|||
payloadLen += add;
|
||||
|
||||
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");
|
||||
abort();
|
||||
}
|
||||
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_is_complete = 1;
|
||||
|
@ -315,11 +318,11 @@ void NimBLEAdvertising::start() {
|
|||
|
||||
rc = ble_gap_adv_rsp_set_fields(&m_scanData);
|
||||
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();
|
||||
}
|
||||
// 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) {
|
||||
m_advData.tx_pwr_lvl_is_present = 1;
|
||||
m_advData.tx_pwr_lvl = NimBLEDevice::getPower();
|
||||
|
@ -327,7 +330,7 @@ void NimBLEAdvertising::start() {
|
|||
|
||||
rc = ble_gap_adv_set_fields(&m_advData);
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -349,22 +352,16 @@ void NimBLEAdvertising::start() {
|
|||
m_advData.num_uuids16 = 0;
|
||||
}
|
||||
|
||||
m_advSvcsSet = 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();
|
||||
m_advDataSet = true;
|
||||
}
|
||||
|
||||
#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,
|
||||
(pServer != nullptr) ? NimBLEServer::handleGapEvent : NULL,
|
||||
pServer);
|
||||
#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);
|
||||
#endif
|
||||
if (rc != 0) {
|
||||
|
@ -398,7 +395,7 @@ void NimBLEAdvertising::stop() {
|
|||
* we need clear the flag so it reloads it.
|
||||
*/
|
||||
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_customScanResponseData = false; // Are we using custom scan response data?
|
||||
bool m_scanResp = true;
|
||||
bool m_advSvcsSet = false;
|
||||
bool m_advDataSet = false;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -22,18 +22,16 @@
|
|||
#include "NimBLEUtils.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#define NULL_HANDLE (0xffff)
|
||||
|
||||
static NimBLECharacteristicCallbacks defaultCallback;
|
||||
|
||||
static const char* LOG_TAG = "NimBLECharacteristic";
|
||||
|
||||
/**
|
||||
* @brief Construct a characteristic
|
||||
* @param [in] uuid - UUID (const char*) 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(NimBLEUUID(uuid), properties, pService) {
|
||||
|
@ -43,6 +41,7 @@ NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties
|
|||
* @brief Construct a characteristic
|
||||
* @param [in] uuid - UUID 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) {
|
||||
m_uuid = uuid;
|
||||
|
@ -50,39 +49,24 @@ NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t prop
|
|||
m_properties = properties;
|
||||
m_pCallbacks = &defaultCallback;
|
||||
m_pService = pService;
|
||||
// Backward Compatibility - to be removed
|
||||
/* setBroadcastProperty((properties & PROPERTY_BROADCAST) != 0);
|
||||
setReadProperty((properties & PROPERTY_READ) != 0);
|
||||
setWriteProperty((properties & PROPERTY_WRITE) != 0);
|
||||
setNotifyProperty((properties & PROPERTY_NOTIFY) != 0);
|
||||
setIndicateProperty((properties & PROPERTY_INDICATE) != 0);
|
||||
setWriteNoResponseProperty((properties & PROPERTY_WRITE_NR) != 0);
|
||||
*/
|
||||
///////////////////////////////////////////
|
||||
m_value = "";
|
||||
m_valMux = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
if(properties & NIMBLE_PROPERTY::INDICATE){
|
||||
m_pIndSemaphore = new FreeRTOS::Semaphore("ConfEvt");
|
||||
} else {
|
||||
m_pIndSemaphore = nullptr;
|
||||
}
|
||||
} // NimBLECharacteristic
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
NimBLECharacteristic::~NimBLECharacteristic() {
|
||||
} // ~NimBLECharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @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;
|
||||
if(m_pIndSemaphore != nullptr) {
|
||||
delete(m_pIndSemaphore);
|
||||
}
|
||||
m_descriptorMap.setByUUID(pDescriptor->getUUID(), pDescriptor);
|
||||
NIMBLE_LOGD(LOG_TAG, "<< addDescriptor()");
|
||||
} // addDescriptor
|
||||
} // ~NimBLECharacteristic
|
||||
|
||||
|
||||
/**
|
||||
|
@ -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* 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)) {
|
||||
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.
|
||||
pDescriptor = m_descriptorMap.getByUUID(uuid);
|
||||
pDescriptor = getDescriptorByUUID(uuid);
|
||||
if(pDescriptor == nullptr) {
|
||||
pDescriptor = new NimBLE2902(this);
|
||||
} else {
|
||||
return pDescriptor;
|
||||
}
|
||||
|
||||
} else if (uuid.equals(NimBLEUUID((uint16_t)0x2904))) {
|
||||
} else if (uuid == NimBLEUUID(uint16_t(0x2904))) {
|
||||
pDescriptor = new NimBLE2904(this);
|
||||
|
||||
} else {
|
||||
pDescriptor = new NimBLEDescriptor(uuid, properties, max_len, this);
|
||||
}
|
||||
addDescriptor(pDescriptor);
|
||||
|
||||
m_dscVec.push_back(pDescriptor);
|
||||
return pDescriptor;
|
||||
} // createCharacteristic
|
||||
|
||||
|
@ -132,8 +117,8 @@ NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID &uuid,
|
|||
* @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.
|
||||
*/
|
||||
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* descriptorUUID) {
|
||||
return m_descriptorMap.getByUUID(NimBLEUUID(descriptorUUID));
|
||||
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* uuid) {
|
||||
return getDescriptorByUUID(NimBLEUUID(uuid));
|
||||
} // getDescriptorByUUID
|
||||
|
||||
|
||||
|
@ -142,8 +127,13 @@ NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* descript
|
|||
* @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.
|
||||
*/
|
||||
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &descriptorUUID) {
|
||||
return m_descriptorMap.getByUUID(descriptorUUID);
|
||||
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &uuid) {
|
||||
for (auto &it : m_dscVec) {
|
||||
if (it->getUUID() == uuid) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
} // getDescriptorByUUID
|
||||
|
||||
|
||||
|
@ -155,11 +145,6 @@ uint16_t NimBLECharacteristic::getHandle() {
|
|||
return m_handle;
|
||||
} // getHandle
|
||||
|
||||
/*
|
||||
void NimBLECharacteristic::setAccessPermissions(uint16_t perm) {
|
||||
m_permissions = perm;
|
||||
}
|
||||
*/
|
||||
|
||||
uint8_t NimBLECharacteristic::getProperties() {
|
||||
return m_properties;
|
||||
|
@ -188,25 +173,24 @@ NimBLEUUID NimBLECharacteristic::getUUID() {
|
|||
* @return A pointer to storage containing the current characteristic value.
|
||||
*/
|
||||
std::string NimBLECharacteristic::getValue() {
|
||||
return m_value.getValue();
|
||||
portENTER_CRITICAL(&m_valMux);
|
||||
std::string retVal = m_value;
|
||||
portEXIT_CRITICAL(&m_valMux);
|
||||
|
||||
return retVal;
|
||||
} // 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.
|
||||
* @return The length of the current characteristic data.
|
||||
*/
|
||||
size_t NimBLECharacteristic:: getDataLength() {
|
||||
return m_value.getLength();
|
||||
size_t NimBLECharacteristic::getDataLength() {
|
||||
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){
|
||||
switch(ctxt->op) {
|
||||
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
|
||||
// so we don't want to call the onRead() callback again.
|
||||
if(ctxt->om->om_pkthdr_len > 8) {
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
|
||||
//pCharacteristic->setValue(ctxt->om->om_data, ctxt->om->om_len);
|
||||
pCharacteristic->m_value.addPart(ctxt->om->om_data, ctxt->om->om_len);
|
||||
uint8_t buf[BLE_ATT_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){
|
||||
//NIMBLE_LOGD(LOG_TAG, "Found long write data, len:%d", next->om_len);
|
||||
pCharacteristic->m_value.addPart(next->om_data, next->om_len);
|
||||
if((len + next->om_len) > BLE_ATT_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);
|
||||
}
|
||||
pCharacteristic->m_value.commit();
|
||||
|
||||
pCharacteristic->setValue(buf, len);
|
||||
pCharacteristic->m_pCallbacks->onWrite(pCharacteristic);
|
||||
|
||||
return 0;
|
||||
|
@ -278,14 +271,18 @@ void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) {
|
|||
subVal |= NIMBLE_DESC_FLAG_INDICATE;
|
||||
}
|
||||
|
||||
m_semaphoreConfEvt.give((subVal | NIMBLE_DESC_FLAG_INDICATE) ? 0 :
|
||||
NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_DISABLED);
|
||||
if(m_pIndSemaphore != nullptr) {
|
||||
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){
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -294,21 +291,28 @@ void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) {
|
|||
p2902->m_pCallbacks->onWrite(p2902);
|
||||
|
||||
|
||||
auto it = p2902->m_subscribedMap.find(event->subscribe.conn_handle);
|
||||
if(subVal > 0 && it == p2902->m_subscribedMap.cend()) {
|
||||
p2902->m_subscribedMap.insert(std::pair<uint16_t, uint16_t>(event->subscribe.conn_handle, subVal));
|
||||
return;
|
||||
} else if(it != p2902->m_subscribedMap.cend()) {
|
||||
p2902->m_subscribedMap.erase(event->subscribe.conn_handle);
|
||||
return;
|
||||
auto it = p2902->m_subscribedVec.begin();
|
||||
for(;it != p2902->m_subscribedVec.end(); ++it) {
|
||||
if((*it).conn_id == event->subscribe.conn_handle) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
if(event->subscribe.reason == BLE_GAP_SUBSCRIBE_REASON_TERM) {
|
||||
p2902->m_subscribedMap.erase(event->subscribe.conn_handle);
|
||||
return;
|
||||
|
||||
if(subVal > 0) {
|
||||
if(it == p2902->m_subscribedVec.end()) {
|
||||
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
|
||||
*/
|
||||
void NimBLECharacteristic::indicate() {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> indicate: length: %d", m_value.getValue().length());
|
||||
NIMBLE_LOGD(LOG_TAG, ">> indicate: length: %d", getDataLength());
|
||||
notify(false);
|
||||
NIMBLE_LOGD(LOG_TAG, "<< indicate");
|
||||
} // indicate
|
||||
|
@ -331,36 +335,38 @@ void NimBLECharacteristic::indicate() {
|
|||
* @return N/A.
|
||||
*/
|
||||
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);
|
||||
assert(getService()->getServer() != nullptr);
|
||||
NimBLE2902* p2902 = (NimBLE2902*)getDescriptorByUUID(uint16_t(0x2902));
|
||||
|
||||
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) {
|
||||
NIMBLE_LOGD(LOG_TAG, "<< notify: No connected clients.");
|
||||
if (p2902->m_subscribedVec.size() == 0) {
|
||||
NIMBLE_LOGD(LOG_TAG, "<< notify: No clients subscribed.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_pCallbacks->onNotify(this);
|
||||
|
||||
std::string value = getValue();
|
||||
size_t length = value.length();
|
||||
int rc = 0;
|
||||
NimBLE2902* p2902 = (NimBLE2902*)getDescriptorByUUID((uint16_t)0x2902);
|
||||
|
||||
for (auto it = p2902->m_subscribedMap.cbegin(); it != p2902->m_subscribedMap.cend(); ++it) {
|
||||
uint16_t _mtu = getService()->getServer()->getPeerMTU((*it).first);
|
||||
// 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();
|
||||
for (auto &it : p2902->m_subscribedVec) {
|
||||
uint16_t _mtu = getService()->getServer()->getPeerMTU(it.conn_id);
|
||||
os_mbuf *om;
|
||||
|
||||
if(_mtu == 0) {
|
||||
//NIMBLE_LOGD(LOG_TAG, "peer not connected, removing from map");
|
||||
p2902->m_subscribedMap.erase((*it).first);
|
||||
it = p2902->m_subscribedMap.cbegin();
|
||||
if(it == p2902->m_subscribedMap.cend()) {
|
||||
return;
|
||||
}
|
||||
//NIMBLE_LOGD(LOG_TAG, "peer not connected");
|
||||
continue;
|
||||
}
|
||||
|
||||
if(it.sub_val == 0) {
|
||||
//NIMBLE_LOGD(LOG_TAG, "Skipping unsubscribed client");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -368,54 +374,52 @@ void NimBLECharacteristic::notify(bool is_notification) {
|
|||
NIMBLE_LOGW(LOG_TAG, "- Truncating to %d bytes (maximum notify size)", _mtu - 3);
|
||||
}
|
||||
|
||||
if((*it).second == 0) {
|
||||
//NIMBLE_LOGI(LOG_TAG, "Skipping unsubscribed client");
|
||||
continue;
|
||||
}
|
||||
|
||||
if(is_notification && (!((*it).second & NIMBLE_DESC_FLAG_NOTIFY))) {
|
||||
if(is_notification && (!(it.sub_val & NIMBLE_DESC_FLAG_NOTIFY))) {
|
||||
NIMBLE_LOGW(LOG_TAG,
|
||||
"Sending notification to client subscribed to indications, sending indication instead");
|
||||
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,
|
||||
"Sending indication to client subscribed to notifications, sending notifications instead");
|
||||
"Sending indication to client subscribed to notification, sending notification instead");
|
||||
is_notification = true;
|
||||
}
|
||||
|
||||
// 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 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) {
|
||||
m_semaphoreConfEvt.take("indicate");
|
||||
rc = ble_gattc_indicate_custom((*it).first, m_handle, om);
|
||||
NimBLECharacteristicCallbacks::Status statusRC;
|
||||
if(m_pIndSemaphore != nullptr && !is_notification) {
|
||||
m_pIndSemaphore->take("indicate");
|
||||
rc = ble_gattc_indicate_custom(it.conn_id, m_handle, om);
|
||||
if(rc != 0){
|
||||
m_semaphoreConfEvt.give();
|
||||
m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::ERROR_GATT, rc);
|
||||
return;
|
||||
m_pIndSemaphore->give();
|
||||
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_GATT;
|
||||
} else {
|
||||
rc = m_pIndSemaphore->wait();
|
||||
}
|
||||
|
||||
rc = m_semaphoreConfEvt.wait();
|
||||
|
||||
if(rc == BLE_HS_ETIMEOUT) {
|
||||
m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_TIMEOUT, rc);
|
||||
} else if(rc == BLE_HS_EDONE) {
|
||||
m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::SUCCESS_INDICATE, rc);
|
||||
if(rc == 0 || rc == BLE_HS_EDONE) {
|
||||
rc = 0;
|
||||
statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_INDICATE;
|
||||
} else if(rc == BLE_HS_ETIMEOUT) {
|
||||
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_TIMEOUT;
|
||||
} else {
|
||||
m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_FAILURE, rc);
|
||||
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_FAILURE;
|
||||
}
|
||||
} 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) {
|
||||
m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::SUCCESS_NOTIFY, 0);
|
||||
statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_NOTIFY;
|
||||
} 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");
|
||||
|
@ -434,87 +438,6 @@ void NimBLECharacteristic::setCallbacks(NimBLECharacteristicCallbacks* pCallback
|
|||
}
|
||||
} // 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.
|
||||
|
@ -522,21 +445,20 @@ void NimBLECharacteristic::setWriteProperty(bool value) {
|
|||
* @param [in] length The length of the data in bytes.
|
||||
*/
|
||||
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);
|
||||
NIMBLE_LOGD(LOG_TAG, ">> setValue: length=%d, data=%s, characteristic UUID=%s", length, pHex, getUUID().toString().c_str());
|
||||
free(pHex);
|
||||
#endif
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
m_value.setValue(data, length);
|
||||
|
||||
// if(m_handle != NULL_HANDLE) {
|
||||
//ble_gatts_chr_updated(m_handle);
|
||||
// ble_gattc_notify(getService()->getServer()->m_connId, m_handle);
|
||||
// }
|
||||
portENTER_CRITICAL(&m_valMux);
|
||||
m_value = std::string((char*)data, length);
|
||||
portEXIT_CRITICAL(&m_valMux);
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< setValue");
|
||||
} // setValue
|
||||
|
|
|
@ -42,42 +42,16 @@ typedef enum {
|
|||
|
||||
#include "NimBLEService.h"
|
||||
#include "NimBLEDescriptor.h"
|
||||
#include "NimBLEUUID.h"
|
||||
#include "NimBLEValue.h"
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include <vector>
|
||||
|
||||
class NimBLEService;
|
||||
class NimBLEDescriptor;
|
||||
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.
|
||||
*
|
||||
|
@ -87,84 +61,67 @@ private:
|
|||
class NimBLECharacteristic {
|
||||
public:
|
||||
NimBLEDescriptor* createDescriptor(const char* uuid,
|
||||
uint32_t properties = NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = 100);
|
||||
uint32_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = 100);
|
||||
NimBLEDescriptor* createDescriptor(const NimBLEUUID &uuid,
|
||||
uint32_t properties = NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = 100);
|
||||
uint32_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = 100);
|
||||
|
||||
NimBLEDescriptor* getDescriptorByUUID(const char* descriptorUUID);
|
||||
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &descriptorUUID);
|
||||
NimBLEDescriptor* getDescriptorByUUID(const char* uuid);
|
||||
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &uuid);
|
||||
NimBLEUUID getUUID();
|
||||
std::string getValue();
|
||||
uint8_t* getData();
|
||||
size_t getDataLength();
|
||||
|
||||
void indicate();
|
||||
void notify(bool is_notification = true);
|
||||
void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
|
||||
// Backward Compatibility - to be removed
|
||||
void setBroadcastProperty(bool value);
|
||||
void setIndicateProperty(bool value);
|
||||
void setNotifyProperty(bool value);
|
||||
void setReadProperty(bool value);
|
||||
void setWriteProperty(bool value);
|
||||
void setWriteNoResponseProperty(bool value);
|
||||
//////////////////////////////////////////////////////
|
||||
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;
|
||||
*/
|
||||
//////////////////////////////////////////////////////
|
||||
void indicate();
|
||||
void notify(bool is_notification = true);
|
||||
void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
|
||||
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();
|
||||
|
||||
private:
|
||||
|
||||
friend class NimBLEServer;
|
||||
friend class NimBLEService;
|
||||
// friend class NimBLEDescriptor;
|
||||
// friend class NimBLECharacteristicMap;
|
||||
friend class NimBLEServer;
|
||||
friend class NimBLEService;
|
||||
|
||||
NimBLECharacteristic(const char* uuid, uint16_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
|
||||
NimBLEService* pService = nullptr);
|
||||
NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
|
||||
NimBLEService* pService = nullptr);
|
||||
virtual ~NimBLECharacteristic();
|
||||
NimBLECharacteristic(const char* uuid,
|
||||
uint16_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
NimBLEService* pService = nullptr);
|
||||
NimBLECharacteristic(const NimBLEUUID &uuid,
|
||||
uint16_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
NimBLEService* pService = nullptr);
|
||||
|
||||
NimBLEUUID m_uuid;
|
||||
NimBLEDescriptorMap m_descriptorMap;
|
||||
uint16_t m_handle;
|
||||
uint16_t m_properties;
|
||||
NimBLECharacteristicCallbacks* m_pCallbacks;
|
||||
NimBLEService* m_pService;
|
||||
NimBLEValue m_value;
|
||||
// uint16_t m_permissions;
|
||||
~NimBLECharacteristic();
|
||||
|
||||
void addDescriptor(NimBLEDescriptor* pDescriptor);
|
||||
NimBLEService* getService();
|
||||
uint8_t getProperties();
|
||||
void setSubscribe(struct ble_gap_event *event);
|
||||
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
|
||||
|
||||
|
||||
|
|
|
@ -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_pCallbacks = &defaultCallbacks; // No initial callback.
|
||||
m_value.attr_value = (uint8_t*) calloc(max_len,1); // Allocate storage for the value.
|
||||
m_valMux = portMUX_INITIALIZER_UNLOCKED;
|
||||
m_properties = 0;
|
||||
|
||||
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){
|
||||
switch(ctxt->op) {
|
||||
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());
|
||||
portEXIT_CRITICAL(&pDescriptor->m_valMux);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
@ -191,12 +212,14 @@ void NimBLEDescriptor::setHandle(uint16_t handle) {
|
|||
* @param [in] length The length of the data in bytes.
|
||||
*/
|
||||
void NimBLEDescriptor::setValue(const uint8_t* data, size_t length) {
|
||||
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);
|
||||
if (length > m_value.attr_max_len) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, m_value.attr_max_len);
|
||||
return;
|
||||
}
|
||||
portENTER_CRITICAL(&m_valMux);
|
||||
m_value.attr_len = length;
|
||||
memcpy(m_value.attr_value, data, length);
|
||||
portEXIT_CRITICAL(&m_valMux);
|
||||
} // setValue
|
||||
|
||||
|
||||
|
@ -209,13 +232,6 @@ void NimBLEDescriptor::setValue(const std::string &value) {
|
|||
} // setValue
|
||||
|
||||
|
||||
/*
|
||||
void NimBLEDescriptor::setAccessPermissions(uint8_t perm) {
|
||||
m_permissions = perm;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return a string representation of the descriptor.
|
||||
* @return A string representation of the descriptor.
|
||||
|
|
|
@ -29,13 +29,11 @@
|
|||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t attr_max_len; /*!< attribute max value length */
|
||||
uint16_t attr_len; /*!< attribute current value length */
|
||||
uint8_t *attr_value; /*!< the pointer to attribute value */
|
||||
uint16_t attr_max_len; /*!< attribute max value length */
|
||||
uint16_t attr_len; /*!< attribute current value length */
|
||||
uint8_t *attr_value; /*!< the pointer to attribute value */
|
||||
} attr_value_t;
|
||||
|
||||
typedef attr_value_t esp_attr_value_t; /*!< compatibility for esp32 */
|
||||
|
||||
class NimBLEService;
|
||||
class NimBLECharacteristic;
|
||||
class NimBLEDescriptorCallbacks;
|
||||
|
@ -46,32 +44,34 @@ class NimBLEDescriptorCallbacks;
|
|||
*/
|
||||
class NimBLEDescriptor {
|
||||
public:
|
||||
virtual ~NimBLEDescriptor();
|
||||
uint16_t getHandle(); // Get the handle of the descriptor.
|
||||
size_t getLength(); // Get the length of the value of the descriptor.
|
||||
NimBLEUUID getUUID(); // Get the UUID of the descriptor.
|
||||
uint8_t* getValue(); // Get a pointer to the value of the descriptor.
|
||||
// void setAccessPermissions(uint8_t perm); // Set the permissions of the descriptor.
|
||||
void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks); // Set callbacks to be invoked for the descriptor.
|
||||
void setValue(const uint8_t* data, size_t size); // Set the value of the descriptor as a pointer to data.
|
||||
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.
|
||||
uint16_t getHandle();
|
||||
size_t getLength();
|
||||
NimBLEUUID getUUID();
|
||||
uint8_t* getValue();
|
||||
void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks);
|
||||
void setValue(const uint8_t* data, size_t size);
|
||||
void setValue(const std::string &value);
|
||||
std::string toString();
|
||||
|
||||
private:
|
||||
friend class NimBLEDescriptorMap;
|
||||
friend class NimBLECharacteristic;
|
||||
friend class NimBLEService;
|
||||
friend class NimBLE2902;
|
||||
friend class NimBLE2904;
|
||||
|
||||
NimBLEDescriptor(const char* uuid, uint16_t properties,
|
||||
uint16_t max_len,
|
||||
NimBLECharacteristic* pCharacteristic);
|
||||
uint16_t max_len,
|
||||
NimBLECharacteristic* pCharacteristic);
|
||||
|
||||
NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties,
|
||||
uint16_t max_len,
|
||||
NimBLECharacteristic* pCharacteristic);
|
||||
uint16_t max_len,
|
||||
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;
|
||||
uint16_t m_handle;
|
||||
|
@ -79,12 +79,8 @@ private:
|
|||
NimBLECharacteristic* m_pCharacteristic;
|
||||
uint8_t m_properties;
|
||||
attr_value_t m_value;
|
||||
|
||||
static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
|
||||
void setHandle(uint16_t handle);
|
||||
}; // BLEDescriptor
|
||||
portMUX_TYPE m_valMux;
|
||||
}; // NimBLEDescriptor
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -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)
|
||||
|
||||
#include "NimBLEServer.h"
|
||||
#include "NimBLE2902.h"
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLEDevice.h"
|
||||
#include "NimBLELog.h"
|
||||
|
@ -32,51 +31,46 @@ static NimBLEServerCallbacks defaultCallbacks;
|
|||
* @brief Construct a %BLE Server
|
||||
*
|
||||
* 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() {
|
||||
m_connId = BLE_HS_CONN_HANDLE_NONE;
|
||||
m_svcChgChrHdl = 0xffff;
|
||||
m_pServerCallbacks = &defaultCallbacks;
|
||||
m_gattsStarted = false;
|
||||
} // BLEServer
|
||||
// m_svcChgChrHdl = 0xffff; // Future Use
|
||||
m_pServerCallbacks = &defaultCallbacks;
|
||||
m_gattsStarted = false;
|
||||
m_advertiseOnDisconnect = true;
|
||||
} // NimBLEServer
|
||||
|
||||
|
||||
/**
|
||||
* @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.
|
||||
* @return A reference to the new service object.
|
||||
*/
|
||||
NimBLEService* NimBLEServer::createService(const char* uuid) {
|
||||
return createService(NimBLEUUID(uuid));
|
||||
}
|
||||
} // createService
|
||||
|
||||
|
||||
/**
|
||||
* @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] 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.
|
||||
*/
|
||||
NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid, uint32_t numHandles, uint8_t inst_id) {
|
||||
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.
|
||||
if (m_serviceMap.getByUUID(uuid) != nullptr) {
|
||||
NIMBLE_LOGW(LOG_TAG, "<< Attempt to create a new service with uuid %s but a service with that UUID already exists.",
|
||||
uuid.toString().c_str());
|
||||
if(getServiceByUUID(uuid) != nullptr) {
|
||||
NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s",
|
||||
std::string(uuid).c_str());
|
||||
}
|
||||
|
||||
NimBLEService* pService = new NimBLEService(uuid, numHandles, this);
|
||||
pService->m_instId = inst_id;
|
||||
m_serviceMap.setByUUID(uuid, pService); // Save a reference to this service being on this server.
|
||||
m_svcVec.push_back(pService); // Save a reference to this service being on this server.
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< createService");
|
||||
return pService;
|
||||
|
@ -89,8 +83,8 @@ NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid, uint32_t numH
|
|||
* @return A reference to the service object.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
NimBLEAdvertising* NimBLEServer::getAdvertising() {
|
||||
return BLEDevice::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;
|
||||
}
|
||||
return NimBLEDevice::getAdvertising();
|
||||
} // getAdvertising
|
||||
|
||||
|
||||
/**
|
||||
|
@ -143,6 +132,8 @@ void NimBLEServer::start() {
|
|||
#if CONFIG_LOG_DEFAULT_LEVEL > 3 || (ARDUINO_ARCH_ESP32 && CORE_DEBUG_LEVEL >= 4)
|
||||
ble_gatts_show_local();
|
||||
#endif
|
||||
/*** Future use ***
|
||||
* TODO: implement service changed handling
|
||||
|
||||
ble_uuid16_t svc = {BLE_UUID_TYPE_16, 0x1801};
|
||||
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);
|
||||
*/
|
||||
// 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
|
||||
uint8_t numSvcs = m_serviceMap.getRegisteredServiceCount();
|
||||
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));
|
||||
if(nullptr == chr->getDescriptorByUUID(uint16_t(0x2902))) {
|
||||
chr->createDescriptor(uint16_t(0x2902));
|
||||
}
|
||||
pChr = pService->m_characteristicMap.getNext();
|
||||
m_notifyChrVec.push_back(chr);
|
||||
}
|
||||
}
|
||||
pService = m_serviceMap.getNext();
|
||||
}
|
||||
|
||||
m_gattsStarted = true;
|
||||
}
|
||||
} // start
|
||||
|
||||
|
||||
/**
|
||||
|
@ -204,15 +184,24 @@ int NimBLEServer::disconnect(uint16_t connId, uint8_t reason) {
|
|||
|
||||
return rc;
|
||||
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.
|
||||
* @return The number of connected clients.
|
||||
*/
|
||||
uint32_t NimBLEServer::getConnectedCount() {
|
||||
return m_connectedServersMap.size();
|
||||
size_t NimBLEServer::getConnectedCount() {
|
||||
return m_connectedPeersVec.size();
|
||||
} // getConnectedCount
|
||||
|
||||
|
||||
|
@ -227,7 +216,7 @@ uint32_t NimBLEServer::getConnectedCount() {
|
|||
/*STATIC*/int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||
NimBLEServer* server = (NimBLEServer*)arg;
|
||||
NIMBLE_LOGD(LOG_TAG, ">> handleGapEvent: %s",
|
||||
NimBLEUtils::gapEventToString(event->type));
|
||||
NimBLEUtils::gapEventToString(event->type));
|
||||
int rc = 0;
|
||||
struct ble_gap_conn_desc desc;
|
||||
|
||||
|
@ -236,13 +225,11 @@ uint32_t NimBLEServer::getConnectedCount() {
|
|||
case BLE_GAP_EVENT_CONNECT: {
|
||||
if (event->connect.status != 0) {
|
||||
/* Connection failed; resume advertising */
|
||||
NIMBLE_LOGC(LOG_TAG, "Connection failed");
|
||||
NIMBLE_LOGE(LOG_TAG, "Connection failed");
|
||||
NimBLEDevice::startAdvertising();
|
||||
server->m_connId = BLE_HS_CONN_HANDLE_NONE;
|
||||
}
|
||||
else {
|
||||
server->m_connId = event->connect.conn_handle;
|
||||
server->addPeerDevice((void*)server, false, server->m_connId);
|
||||
server->m_connectedPeersVec.push_back(event->connect.conn_handle);
|
||||
|
||||
ble_gap_conn_desc desc;
|
||||
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
|
||||
|
@ -271,10 +258,15 @@ uint32_t NimBLEServer::getConnectedCount() {
|
|||
break;
|
||||
}
|
||||
|
||||
server->removePeerDevice(event->disconnect.conn.conn_handle, false);
|
||||
server->m_connId = BLE_HS_CONN_HANDLE_NONE;
|
||||
server->m_connectedPeersVec.erase(std::remove(server->m_connectedPeersVec.begin(),
|
||||
server->m_connectedPeersVec.end(),
|
||||
event->disconnect.conn.conn_handle),
|
||||
server->m_connectedPeersVec.end());
|
||||
server->m_pServerCallbacks->onDisconnect(server);
|
||||
|
||||
if(server->m_advertiseOnDisconnect) {
|
||||
server->startAdvertising();
|
||||
}
|
||||
return 0;
|
||||
} // BLE_GAP_EVENT_DISCONNECT
|
||||
|
||||
|
@ -283,9 +275,11 @@ uint32_t NimBLEServer::getConnectedCount() {
|
|||
"val_handle=%d\n",
|
||||
event->subscribe.cur_notify, event->subscribe.attr_handle);
|
||||
|
||||
auto it = server->m_notifyChrMap.find(event->subscribe.attr_handle);
|
||||
if(it != server->m_notifyChrMap.cend()) {
|
||||
(*it).second->setSubscribe(event);
|
||||
for(auto &it : server->m_notifyChrVec) {
|
||||
if(it->getHandle() == event->subscribe.attr_handle) {
|
||||
it->setSubscribe(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -295,15 +289,18 @@ uint32_t NimBLEServer::getConnectedCount() {
|
|||
NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d",
|
||||
event->mtu.conn_handle,
|
||||
event->mtu.value);
|
||||
server->updatePeerMTU(event->mtu.conn_handle, event->mtu.value);
|
||||
return 0;
|
||||
} // BLE_GAP_EVENT_MTU
|
||||
|
||||
case BLE_GAP_EVENT_NOTIFY_TX: {
|
||||
if(event->notify_tx.indication && event->notify_tx.status != 0) {
|
||||
auto it = server->m_notifyChrMap.find(event->notify_tx.attr_handle);
|
||||
if(it != server->m_notifyChrMap.cend()) {
|
||||
(*it).second->m_semaphoreConfEvt.give(event->notify_tx.status);
|
||||
for(auto &it : server->m_notifyChrVec) {
|
||||
if(it->getHandle() == event->notify_tx.attr_handle) {
|
||||
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
|
||||
|
||||
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) {
|
||||
pkey.action = event->passkey.params.action;
|
||||
|
@ -416,7 +413,7 @@ uint32_t NimBLEServer::getConnectedCount() {
|
|||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< handleGATTServerEvent");
|
||||
return 0;
|
||||
} // handleGATTServerEvent
|
||||
} // handleGapEvent
|
||||
|
||||
|
||||
/**
|
||||
|
@ -437,18 +434,6 @@ void NimBLEServer::setCallbacks(NimBLEServerCallbacks* pCallbacks) {
|
|||
} // setCallbacks
|
||||
|
||||
|
||||
/*
|
||||
* Remove service
|
||||
*/
|
||||
/*
|
||||
void BLEServer::removeService(BLEService* service) {
|
||||
service->stop();
|
||||
service->executeDelete();
|
||||
m_serviceMap.removeService(service);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @brief Start advertising.
|
||||
*
|
||||
|
@ -456,9 +441,7 @@ void BLEServer::removeService(BLEService* service) {
|
|||
* retrieving the advertising object and invoking start upon it.
|
||||
*/
|
||||
void NimBLEServer::startAdvertising() {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> startAdvertising");
|
||||
NimBLEDevice::startAdvertising();
|
||||
NIMBLE_LOGD(LOG_TAG, "<< startAdvertising");
|
||||
} // startAdvertising
|
||||
|
||||
|
||||
|
@ -466,38 +449,43 @@ void NimBLEServer::startAdvertising() {
|
|||
* @brief Stop advertising.
|
||||
*/
|
||||
void NimBLEServer::stopAdvertising() {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> stopAdvertising");
|
||||
NimBLEDevice::stopAdvertising();
|
||||
NIMBLE_LOGD(LOG_TAG, "<< stopAdvertising");
|
||||
} // startAdvertising
|
||||
|
||||
|
||||
/**
|
||||
* Allow to connect GATT server to peer device
|
||||
* Probably can be used in ANCS for iPhone
|
||||
* @brief Get the MTU of the client.
|
||||
* @returns The client MTU or 0 if not found/connected.
|
||||
*/
|
||||
/*
|
||||
bool BLEServer::connect(BLEAddress address) {
|
||||
esp_bd_addr_t addr;
|
||||
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(
|
||||
getGattsIf(),
|
||||
addr, // address
|
||||
1 // direct connection
|
||||
);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_open: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return false;
|
||||
uint16_t NimBLEServer::getPeerMTU(uint16_t conn_id) {
|
||||
return ble_att_mtu(conn_id);
|
||||
} //getPeerMTU
|
||||
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
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 = 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) {
|
||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onConnect(): Default");
|
||||
|
@ -534,80 +522,6 @@ bool NimBLEServerCallbacks::onConfirmPIN(uint32_t pin){
|
|||
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 // CONFIG_BT_ENABLED
|
||||
|
|
|
@ -21,102 +21,58 @@
|
|||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
#include "NimBLEAddress.h"
|
||||
#include "NimBLEUUID.h"
|
||||
#include "NimBLEAdvertising.h"
|
||||
#include "NimBLEService.h"
|
||||
#include "NimBLESecurity.h"
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
class NimBLEService;
|
||||
class NimBLECharacteristic;
|
||||
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.
|
||||
*/
|
||||
class NimBLEServer {
|
||||
public:
|
||||
uint32_t getConnectedCount();
|
||||
NimBLEService* createService(const char* uuid);
|
||||
NimBLEService* createService(const NimBLEUUID &uuid, uint32_t numHandles=15, uint8_t inst_id=0);
|
||||
NimBLEAdvertising* getAdvertising();
|
||||
void setCallbacks(NimBLEServerCallbacks* pCallbacks);
|
||||
void startAdvertising();
|
||||
void stopAdvertising();
|
||||
void start();
|
||||
// void removeService(BLEService* service);
|
||||
NimBLEService* getServiceByUUID(const char* uuid);
|
||||
NimBLEService* getServiceByUUID(const NimBLEUUID &uuid);
|
||||
int disconnect(uint16_t connID, uint8_t reason = BLE_ERR_REM_USER_CONN_TERM);
|
||||
// bool connect(BLEAddress address);
|
||||
void updateConnParams(uint16_t conn_handle,
|
||||
uint16_t minInterval, uint16_t maxInterval,
|
||||
uint16_t latency, uint16_t timeout,
|
||||
uint16_t minConnTime=0, uint16_t maxConnTime=0);
|
||||
|
||||
/* multi connection support */
|
||||
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();
|
||||
|
||||
size_t getConnectedCount();
|
||||
NimBLEService* createService(const char* uuid);
|
||||
NimBLEService* createService(const NimBLEUUID &uuid, uint32_t numHandles=15,
|
||||
uint8_t inst_id=0);
|
||||
NimBLEAdvertising* getAdvertising();
|
||||
void setCallbacks(NimBLEServerCallbacks* pCallbacks);
|
||||
void startAdvertising();
|
||||
void stopAdvertising();
|
||||
void start();
|
||||
NimBLEService* getServiceByUUID(const char* uuid);
|
||||
NimBLEService* getServiceByUUID(const NimBLEUUID &uuid);
|
||||
int disconnect(uint16_t connID,
|
||||
uint8_t reason = BLE_ERR_REM_USER_CONN_TERM);
|
||||
void updateConnParams(uint16_t conn_handle,
|
||||
uint16_t minInterval, uint16_t maxInterval,
|
||||
uint16_t latency, uint16_t timeout);
|
||||
uint16_t getPeerMTU(uint16_t conn_id);
|
||||
std::vector<uint16_t> getPeerDevices();
|
||||
void advertiseOnDisconnect(bool);
|
||||
|
||||
private:
|
||||
NimBLEServer();
|
||||
//friend class BLEService;
|
||||
friend class NimBLECharacteristic;
|
||||
friend class NimBLEDevice;
|
||||
friend class NimBLEAdvertising;
|
||||
// void onHostReset();
|
||||
// BLEAdvertising m_bleAdvertising;
|
||||
uint16_t m_connId;
|
||||
uint16_t m_svcChgChrHdl;
|
||||
friend class NimBLECharacteristic;
|
||||
friend class NimBLEDevice;
|
||||
friend class NimBLEAdvertising;
|
||||
|
||||
bool m_gattsStarted;
|
||||
|
||||
std::map<uint16_t, conn_status_t> m_connectedServersMap;
|
||||
std::map<uint16_t, NimBLECharacteristic*> m_notifyChrMap;
|
||||
|
||||
NimBLEServiceMap m_serviceMap;
|
||||
bool m_advertiseOnDisconnect;
|
||||
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
|
||||
|
||||
|
||||
|
@ -149,7 +105,7 @@ public:
|
|||
virtual bool onSecurityRequest(); //{return true;}
|
||||
virtual void onAuthenticationComplete(ble_gap_conn_desc* desc);//{};
|
||||
virtual bool onConfirmPIN(uint32_t pin);//{return true;}
|
||||
}; // BLEServerCallbacks
|
||||
}; // NimBLEServerCallbacks
|
||||
|
||||
|
||||
#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] 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(NimBLEUUID(uuid), numHandles, pServer) {
|
||||
|
@ -45,11 +46,12 @@ NimBLEService::NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer
|
|||
* @brief Construct an instance of the BLEService
|
||||
* @param [in] uuid The UUID of 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) {
|
||||
m_uuid = uuid;
|
||||
m_handle = NULL_HANDLE;
|
||||
m_pServer = pServer;
|
||||
m_uuid = uuid;
|
||||
m_handle = NULL_HANDLE;
|
||||
m_pServer = pServer;
|
||||
m_numHandles = numHandles;
|
||||
} // NimBLEService
|
||||
|
||||
|
@ -59,10 +61,22 @@ NimBLEService::NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLE
|
|||
* @return N/A.
|
||||
*/
|
||||
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_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
|
||||
|
||||
|
||||
|
@ -76,10 +90,9 @@ NimBLEUUID NimBLEService::getUUID() {
|
|||
|
||||
|
||||
/**
|
||||
* @brief Start the service.
|
||||
* Here we wish to start the service which means that we will respond to partner requests about it.
|
||||
* Starting a service also means that we can create the corresponding characteristics.
|
||||
* @return Start the service.
|
||||
* @brief Builds the database of characteristics/descriptors for the service
|
||||
* and registers it with the NimBLE stack.
|
||||
* @return bool success/failure .
|
||||
*/
|
||||
|
||||
bool NimBLEService::start() {
|
||||
|
@ -96,7 +109,7 @@ bool NimBLEService::start() {
|
|||
svc[0].uuid = &m_uuid.getNative()->u;
|
||||
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());
|
||||
|
||||
|
@ -107,16 +120,17 @@ bool NimBLEService::start() {
|
|||
// of the characteristics for the service. We create 1 extra and set it to null
|
||||
// for this purpose.
|
||||
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++) {
|
||||
uint8_t numDscs = pCharacteristic->m_descriptorMap.getSize();
|
||||
for(uint8_t i=0; i < numChrs;) {
|
||||
uint8_t numDscs = pCharacteristic->m_dscVec.size();
|
||||
if(numDscs) {
|
||||
// skip 2902 as it's automatically created by NimBLE
|
||||
// if Indicate or Notify flags are set
|
||||
if(((pCharacteristic->m_properties & BLE_GATT_CHR_F_INDICATE) ||
|
||||
(pCharacteristic->m_properties & BLE_GATT_CHR_F_NOTIFY)) &&
|
||||
pCharacteristic->getDescriptorByUUID("2902") != nullptr) {
|
||||
pCharacteristic->getDescriptorByUUID("2902") != nullptr)
|
||||
{
|
||||
numDscs--;
|
||||
}
|
||||
}
|
||||
|
@ -127,12 +141,12 @@ bool NimBLEService::start() {
|
|||
// Must have last descriptor uuid = 0 so we have to create 1 extra
|
||||
//NIMBLE_LOGD(LOG_TAG, "Adding %d descriptors", numDscs);
|
||||
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;) {
|
||||
// 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");
|
||||
pDescriptor = pCharacteristic->m_descriptorMap.getNext();
|
||||
pDescriptor = *(pCharacteristic->m_dscVec.begin()+d+1);
|
||||
continue;
|
||||
}
|
||||
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].access_cb = NimBLEDescriptor::handleGapEvent;
|
||||
pDsc_a[d].arg = pDescriptor;
|
||||
pDescriptor = pCharacteristic->m_descriptorMap.getNext();
|
||||
d++;
|
||||
pDescriptor = *(pCharacteristic->m_dscVec.begin() + d);
|
||||
}
|
||||
|
||||
pDsc_a[numDscs].uuid = NULL;
|
||||
|
@ -154,7 +168,8 @@ bool NimBLEService::start() {
|
|||
pChr_a[i].flags = pCharacteristic->m_properties;
|
||||
pChr_a[i].min_key_size = 0;
|
||||
pChr_a[i].val_handle = &pCharacteristic->m_handle;
|
||||
pCharacteristic = m_characteristicMap.getNext();
|
||||
i++;
|
||||
pCharacteristic = *(m_chrVec.begin() + i);
|
||||
}
|
||||
|
||||
pChr_a[numChrs].uuid = NULL;
|
||||
|
@ -182,21 +197,6 @@ bool NimBLEService::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.
|
||||
* @return The handle associated with this service.
|
||||
|
@ -206,34 +206,6 @@ uint16_t NimBLEService::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.
|
||||
* @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* pCharacteristic = new NimBLECharacteristic(uuid, properties, this);
|
||||
addCharacteristic(pCharacteristic);
|
||||
//pCharacteristic->executeCreate(this);
|
||||
// Check that we don't add the same characteristic twice.
|
||||
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;
|
||||
} // createCharacteristic
|
||||
|
||||
|
@ -265,7 +244,13 @@ NimBLECharacteristic* NimBLEService::getCharacteristic(const char* 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 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.
|
||||
|
@ -59,40 +37,39 @@ private:
|
|||
class NimBLEService {
|
||||
public:
|
||||
NimBLECharacteristic* createCharacteristic(const char* uuid,
|
||||
uint32_t properties = NIMBLE_PROPERTY::READ |
|
||||
uint32_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE);
|
||||
|
||||
NimBLECharacteristic* createCharacteristic(const NimBLEUUID &uuid,
|
||||
uint32_t properties = NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE);
|
||||
uint32_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE);
|
||||
|
||||
void dump();
|
||||
void dump();
|
||||
NimBLECharacteristic* getCharacteristic(const char* uuid);
|
||||
NimBLECharacteristic* getCharacteristic(const NimBLEUUID &uuid);
|
||||
NimBLEUUID getUUID();
|
||||
NimBLEServer* getServer();
|
||||
bool start();
|
||||
// void stop();
|
||||
std::string toString();
|
||||
uint16_t getHandle();
|
||||
uint8_t m_instId = 0;
|
||||
bool start();
|
||||
std::string toString();
|
||||
uint16_t getHandle();
|
||||
|
||||
private:
|
||||
NimBLEService(const char* 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;
|
||||
NimBLEServer* m_pServer = nullptr;
|
||||
NimBLEUUID m_uuid;
|
||||
uint16_t m_handle;
|
||||
NimBLEServer* m_pServer;
|
||||
NimBLEUUID m_uuid;
|
||||
uint16_t m_numHandles;
|
||||
|
||||
uint16_t m_numHandles;
|
||||
void setHandle(uint16_t handle);
|
||||
}; // BLEService
|
||||
std::vector<NimBLECharacteristic*> m_chrVec;
|
||||
|
||||
}; // NimBLEService
|
||||
|
||||
|
||||
#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