update NimBLE-Arduino

This commit is contained in:
Staars
2020-07-06 20:09:32 +02:00
parent d612d2b62e
commit f12468e2c4
84 changed files with 1547 additions and 3721 deletions

View File

@@ -19,8 +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 +30,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 +82,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 +92,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 +107,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 +131,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 +145,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
/**
@@ -202,17 +181,26 @@ int NimBLEServer::disconnect(uint16_t connId, uint8_t reason) {
NimBLEUtils::returnCodeToString(rc));
}
return rc;
NIMBLE_LOGD(LOG_TAG, "<< disconnect()");
}
return rc;
} // 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 +215,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,15 +224,12 @@ 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);
assert(rc == 0);
@@ -271,10 +256,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 +273,23 @@ 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) {
if((it->getProperties() & BLE_GATT_CHR_F_READ_AUTHEN) ||
(it->getProperties() & BLE_GATT_CHR_F_READ_AUTHOR) ||
(it->getProperties() & BLE_GATT_CHR_F_READ_ENC))
{
rc = ble_gap_conn_find(event->subscribe.conn_handle, &desc);
assert(rc == 0);
if(!desc.sec_state.encrypted) {
NimBLEDevice::startSecurity(event->subscribe.conn_handle);
}
}
it->setSubscribe(event);
break;
}
}
return 0;
@@ -295,15 +299,19 @@ 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_pTaskData != nullptr) {
it->m_pTaskData->rc = event->notify_tx.status;
xTaskNotifyGive(it->m_pTaskData->task);
}
break;
}
}
}
@@ -333,7 +341,7 @@ uint32_t NimBLEServer::getConnectedCount() {
} // BLE_GAP_EVENT_REPEAT_PAIRING
case BLE_GAP_EVENT_ENC_CHANGE: {
rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc);
rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc);
if(rc != 0) {
return BLE_ATT_ERR_INVALID_HANDLE;
}
@@ -349,7 +357,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 +424,7 @@ uint32_t NimBLEServer::getConnectedCount() {
NIMBLE_LOGD(LOG_TAG, "<< handleGATTServerEvent");
return 0;
} // handleGATTServerEvent
} // handleGapEvent
/**
@@ -437,18 +445,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 +452,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 +460,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, &params);
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 +533,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, &params);
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