update NimBLE-Arduino

This commit is contained in:
Staars 2020-05-26 20:43:55 +02:00
parent 9a7f252d88
commit 7064a82fbf
89 changed files with 3612 additions and 3015 deletions

View File

@ -100,7 +100,7 @@ The `BLEAdvertisedDeviceCallbacks` class `onResult()` method now receives a poin
Defined as: Defined as:
``` ```
bool connect(NimBLEAdvertisedDevice* device, bool refreshServices = true); bool connect(NimBLEAdvertisedDevice* device, bool refreshServices = true);
bool connect(NimBLEAddress address, uint8_t type = BLE_ADDR_TYPE_PUBLIC, bool refreshServices = true); bool connect(NimBLEAddress address, uint8_t type = BLE_ADDR_PUBLIC, bool refreshServices = true);
``` ```
If set to false the client will use the services database it retrieved from the peripheral last time it connected. If set to false the client will use the services database it retrieved from the peripheral last time it connected.
This allows for faster connections and power saving if the devices just dropped connection and want to reconnect. This allows for faster connections and power saving if the devices just dropped connection and want to reconnect.
@ -111,6 +111,46 @@ NimBLERemoteCharacteristic::registerForNotify();
``` ```
Now return true or false to indicate success or failure so you can choose to disconnect or try again. Now return true or false to indicate success or failure so you can choose to disconnect or try again.
```
NimBLEClient::getServices()
NimBLERemoteService::getCharacteristics()
```
Now return a pointer to a `std::vector` of the respective object database instead of `std::map`.
`NimBLERemoteService::getCharacteristicsByHandle()`
Has been removed from the API as it is no longer maintained in the library.
The last two above changes reduce the heap usage significantly with minimal application code adjustments.
**NEW** on May 23, 2020
> ```
> NimBLEClient::getServices(bool refresh = false)
> NimBLERemoteService::getCharacteristics(bool refresh = false)
> NimBLERemoteCharacteristic::getDecriptors(bool refresh = false)
>```
> These methods now take an optional (bool) parameter.
If true it will clear the respective vector and retrieve all the respective attributes from the peripheral.
If false it will retrieve the attributes only if the vector is empty, otherwise the vector is returned
with the currently stored attributes.
> Removed the automatic discovery of all peripheral attributes as they consumed time and resources for data
the user may not be interested in.
> Added `NimBLEClient::discoverAtrributes()` for the user to discover all the peripheral attributes
to replace the the former functionality.
> ```
>getService(NimBLEUUID)
>getCharacteristic(NimBLEUUID)
>getDescriptor(NimBLEUUID)
>```
>These methods will now check the respective vectors for the attribute object and, if not found, will retrieve (only)
the specified attribute from the peripheral.
> These changes allow more control for the user to manage the resources used for the attributes.
#### Client Security: #### Client Security:
The client will automatically initiate security when the peripheral responds that it's required. The client will automatically initiate security when the peripheral responds that it's required.
The default configuration will use "just-works" pairing with no bonding, if you wish to enable bonding see below. The default configuration will use "just-works" pairing with no bonding, if you wish to enable bonding see below.

View File

@ -1,11 +1,14 @@
# *** UPDATE *** # *** UPDATE ***
Server now handles long reads and writes, still work to do on client. **Breaking change:** Client and scan now use `std::vector` instead of `std::map` for storing the remote attribute database.
NEW Client callback created - ```bool onConnParamsUpdateRequest(NimBLEClient* pClient, const ble_gap_upd_params* params)``` This change will affect your application code if you use `NimBLEClient::getServices()` or `NimBLERemoteService::getCharacteristics()`
Called when the server wants to change the connection parameters, return true to accept them or false if not. in your application as they now return a pointer to `std::vector` of the respective attributes.
Check NimBLE_Client.ino example for a demonstration.
In addition `NimBLERemoteService::getCharacteristicsByHandle()` has been removed as it is no longer maintained in the library.
These changes were necessary due to the amount of resources required to use `std::map`, it was not justifed by any benfit it provided.
It is expected that there will be minimal impact on most applications, if you need help adjusting your code please create an issue.
# NimBLE-Arduino # NimBLE-Arduino
A fork of the NimBLE stack restructured for compilation in the Ardruino IDE with a CPP library for use with ESP32. A fork of the NimBLE stack restructured for compilation in the Ardruino IDE with a CPP library for use with ESP32.
@ -59,10 +62,9 @@ Change the settings in the `nimconfig.h` file to customize NimBLE to your projec
# Continuing development: # Continuing development:
This Library is tracking the esp-nimble repo, nimble-1.2.0-idf master branch, currently [@0a1604a.](https://github.com/espressif/esp-nimble) This Library is tracking the esp-nimble repo, nimble-1.2.0-idf master branch, currently [@fead24e.](https://github.com/espressif/esp-nimble)
Also tracking the NimBLE related changes in esp-idf, master branch, currently [@48bd2d7.](https://github.com/espressif/esp-idf/tree/master/components/bt/host/nimble)
Also tracking the NimBLE related changes in esp-idf, master branch, currently [@2bc28bb.](https://github.com/espressif/esp-idf/tree/master/components/bt/host/nimble)
# Acknowledgments: # Acknowledgments:

View File

@ -61,8 +61,7 @@ class ServerCallbacks: public NimBLEServerCallbacks {
void onAuthenticationComplete(ble_gap_conn_desc* desc){ void onAuthenticationComplete(ble_gap_conn_desc* desc){
/** Check that encryption was successful, if not we disconnect the client */ /** Check that encryption was successful, if not we disconnect the client */
if(!desc->sec_state.encrypted) { if(!desc->sec_state.encrypted) {
/** NOTE: createServer returns the current server reference unless one is not already created */ NimBLEDevice::getServer()->disconnect(desc->conn_handle);
NimBLEDevice::createServer()->disconnect(desc->conn_handle);
Serial.println("Encrypt connection failed - disconnecting client"); Serial.println("Encrypt connection failed - disconnecting client");
return; return;
} }

View File

@ -20,6 +20,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#include "NimBLE2902.h" #include "NimBLE2902.h"
NimBLE2902::NimBLE2902(NimBLECharacteristic* pCharacterisitic) NimBLE2902::NimBLE2902(NimBLECharacteristic* pCharacterisitic)
@ -72,4 +75,5 @@ void NimBLE2902::setNotifications(bool flag) {
else pValue[0] &= ~(1 << 0); else pValue[0] &= ~(1 << 0);
} // setNotifications } // setNotifications
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#endif #endif

View File

@ -17,6 +17,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#include "NimBLEDescriptor.h" #include "NimBLEDescriptor.h"
#include <map> #include <map>
@ -46,5 +49,6 @@ private:
}; // NimBLE2902 }; // NimBLE2902
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */
#endif /* MAIN_NIMBLE2902_H_ */ #endif /* MAIN_NIMBLE2902_H_ */

View File

@ -19,6 +19,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#include "NimBLE2904.h" #include "NimBLE2904.h"
@ -83,4 +86,5 @@ void NimBLE2904::setUnit(uint16_t unit) {
setValue((uint8_t*) &m_data, sizeof(m_data)); setValue((uint8_t*) &m_data, sizeof(m_data));
} // setUnit } // setUnit
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#endif #endif

View File

@ -17,6 +17,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#include "NimBLEDescriptor.h" #include "NimBLEDescriptor.h"
struct BLE2904_Data { struct BLE2904_Data {
@ -78,5 +81,6 @@ private:
BLE2904_Data m_data; BLE2904_Data m_data;
}; // BLE2904 }; // BLE2904
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */
#endif /* MAIN_NIMBLE2904_H_ */ #endif /* MAIN_NIMBLE2904_H_ */

View File

@ -14,9 +14,13 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include <algorithm>
#include "NimBLEAddress.h" #include "NimBLEAddress.h"
#include "NimBLEUtils.h" #include "NimBLEUtils.h"
#include "NimBLELog.h"
static const char* LOG_TAG = "NimBLEAddress";
/************************************************* /*************************************************
NOTE: NimBLE addresses are in INVERSE ORDER! NOTE: NimBLE addresses are in INVERSE ORDER!
@ -43,26 +47,49 @@ NimBLEAddress::NimBLEAddress(ble_addr_t address) {
* *
* @param [in] stringAddress The hex representation of the address. * @param [in] stringAddress The hex representation of the address.
*/ */
NimBLEAddress::NimBLEAddress(std::string stringAddress) { NimBLEAddress::NimBLEAddress(const std::string &stringAddress) {
if (stringAddress.length() != 17) return; if (stringAddress.length() == 0) {
memset(m_address, 0, 6);
return;
}
if (stringAddress.length() == 6) {
std::reverse_copy(stringAddress.data(), stringAddress.data() + 6, m_address);
return;
}
if (stringAddress.length() != 17) {
memset(m_address, 0, sizeof m_address); // "00:00:00:00:00:00" represents an invalid address
NIMBLE_LOGD(LOG_TAG, "Invalid address '%s'", stringAddress.c_str());
return;
}
int data[6]; int data[6];
sscanf(stringAddress.c_str(), "%x:%x:%x:%x:%x:%x", &data[5], &data[4], &data[3], &data[2], &data[1], &data[0]); if(sscanf(stringAddress.c_str(), "%x:%x:%x:%x:%x:%x", &data[5], &data[4], &data[3], &data[2], &data[1], &data[0]) != 6) {
m_address[0] = (uint8_t) data[0]; memset(m_address, 0, sizeof m_address); // "00:00:00:00:00:00" represents an invalid address
m_address[1] = (uint8_t) data[1]; NIMBLE_LOGD(LOG_TAG, "Invalid address '%s'", stringAddress.c_str());
m_address[2] = (uint8_t) data[2]; }
m_address[3] = (uint8_t) data[3]; for(size_t index = 0; index < sizeof m_address; index++) {
m_address[4] = (uint8_t) data[4]; m_address[index] = data[index];
m_address[5] = (uint8_t) data[5]; }
} // BLEAddress } // BLEAddress
/** /**
* @brief Constructor for compatibility with bluedrioid esp library. * @brief Constructor for compatibility with bluedroid esp library.
* @param [in] esp_bd_addr_t struct containing the address. * @param [in] uint8_t[6] or esp_bd_addr_t struct containing the address.
*/ */
NimBLEAddress::NimBLEAddress(esp_bd_addr_t address) { NimBLEAddress::NimBLEAddress(uint8_t address[6]) {
NimBLEUtils::memrcpy(m_address, address, 6); std::reverse_copy(address, address + sizeof m_address, m_address);
} // NimBLEAddress
/**
* @brief Constructor for address using a hex value. Use the same byte order, so use 0xa4c1385def16 for "a4:c1:38:5d:ef:16"
* @param [in] uint64_t containing the address.
*/
NimBLEAddress::NimBLEAddress(const uint64_t &address) {
memcpy(m_address, &address, sizeof m_address);
} // NimBLEAddress } // NimBLEAddress
@ -71,8 +98,8 @@ NimBLEAddress::NimBLEAddress(esp_bd_addr_t address) {
* @param [in] otherAddress The other address to compare against. * @param [in] otherAddress The other address to compare against.
* @return True if the addresses are equal. * @return True if the addresses are equal.
*/ */
bool NimBLEAddress::equals(NimBLEAddress otherAddress) { bool NimBLEAddress::equals(const NimBLEAddress &otherAddress) const {
return memcmp(otherAddress.getNative(), m_address, 6) == 0; return *this == otherAddress;
} // equals } // equals
@ -80,7 +107,7 @@ bool NimBLEAddress::equals(NimBLEAddress otherAddress) {
* @brief Return the native representation of the address. * @brief Return the native representation of the address.
* @return The native representation of the address. * @return The native representation of the address.
*/ */
uint8_t *NimBLEAddress::getNative() { const uint8_t *NimBLEAddress::getNative() const {
return m_address; return m_address;
} // getNative } // getNative
@ -96,13 +123,23 @@ uint8_t *NimBLEAddress::getNative() {
* *
* @return The string representation of the address. * @return The string representation of the address.
*/ */
std::string NimBLEAddress::toString() { std::string NimBLEAddress::toString() const {
auto size = 18; return std::string(*this);
char *res = (char*)malloc(size);
snprintf(res, size, "%02x:%02x:%02x:%02x:%02x:%02x", m_address[5], m_address[4], m_address[3], m_address[2], m_address[1], m_address[0]);
std::string ret(res);
free(res);
return ret;
} // toString } // toString
bool NimBLEAddress::operator ==(const NimBLEAddress & rhs) const {
return memcmp(rhs.m_address, m_address, sizeof m_address) == 0;
}
bool NimBLEAddress::operator !=(const NimBLEAddress & rhs) const {
return !this->operator==(rhs);
}
NimBLEAddress::operator std::string() const {
char buffer[18];
sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x", m_address[5], m_address[4], m_address[3], m_address[2], m_address[1], m_address[0]);
return std::string(buffer);
}
#endif #endif

View File

@ -24,22 +24,7 @@
/**************************/ /**************************/
#include <string> #include <string>
#include <algorithm>
typedef enum {
BLE_ADDR_TYPE_PUBLIC = 0x00,
BLE_ADDR_TYPE_RANDOM = 0x01,
BLE_ADDR_TYPE_RPA_PUBLIC = 0x02,
BLE_ADDR_TYPE_RPA_RANDOM = 0x03,
} esp_nimble_addr_type_t;
typedef uint8_t esp_ble_addr_type_t ;
/// Bluetooth address length
#define ESP_BD_ADDR_LEN 6
/// Bluetooth device address
typedef uint8_t esp_bd_addr_t[ESP_BD_ADDR_LEN];
/** /**
* @brief A %BLE device address. * @brief A %BLE device address.
@ -49,11 +34,16 @@ typedef uint8_t esp_bd_addr_t[ESP_BD_ADDR_LEN];
class NimBLEAddress { class NimBLEAddress {
public: public:
NimBLEAddress(ble_addr_t address); NimBLEAddress(ble_addr_t address);
NimBLEAddress(esp_bd_addr_t address); NimBLEAddress(uint8_t address[6]);
NimBLEAddress(std::string stringAddress); NimBLEAddress(const std::string &stringAddress);
bool equals(NimBLEAddress otherAddress); NimBLEAddress(const uint64_t &address);
uint8_t* getNative(); bool equals(const NimBLEAddress &otherAddress) const;
std::string toString(); const uint8_t* getNative() const;
std::string toString() const;
bool operator ==(const NimBLEAddress & rhs) const;
bool operator !=(const NimBLEAddress & rhs) const;
operator std::string() const;
private: private:
uint8_t m_address[6]; uint8_t m_address[6];

View File

@ -14,6 +14,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
#include "NimBLEAdvertisedDevice.h" #include "NimBLEAdvertisedDevice.h"
#include "NimBLEUtils.h" #include "NimBLEUtils.h"
#include "NimBLELog.h" #include "NimBLELog.h"
@ -141,7 +144,7 @@ NimBLEUUID NimBLEAdvertisedDevice::getServiceUUID() { //TODO Remove it eventual
* @brief Check advertised serviced for existence required UUID * @brief Check advertised serviced for existence required UUID
* @return Return true if service is advertised * @return Return true if service is advertised
*/ */
bool NimBLEAdvertisedDevice::isAdvertisingService(NimBLEUUID uuid){ bool NimBLEAdvertisedDevice::isAdvertisingService(const NimBLEUUID &uuid){
for (int i = 0; i < m_serviceUUIDs.size(); i++) { for (int i = 0; i < m_serviceUUIDs.size(); i++) {
NIMBLE_LOGI(LOG_TAG, "Comparing UUIDS: %s %s", m_serviceUUIDs[i].toString().c_str(), uuid.toString().c_str()); NIMBLE_LOGI(LOG_TAG, "Comparing UUIDS: %s %s", m_serviceUUIDs[i].toString().c_str(), uuid.toString().c_str());
if (m_serviceUUIDs[i].equals(uuid)) return true; if (m_serviceUUIDs[i].equals(uuid)) return true;
@ -441,6 +444,12 @@ void NimBLEAdvertisedDevice::setServiceUUID(const char* serviceUUID) {
* @param [in] serviceUUID The discovered serviceUUID * @param [in] serviceUUID The discovered serviceUUID
*/ */
void NimBLEAdvertisedDevice::setServiceUUID(NimBLEUUID serviceUUID) { void NimBLEAdvertisedDevice::setServiceUUID(NimBLEUUID serviceUUID) {
// Don't add duplicates
for (int i = 0; i < m_serviceUUIDs.size(); i++) {
if (m_serviceUUIDs[i].equals(serviceUUID)) {
return;
}
}
m_serviceUUIDs.push_back(serviceUUID); m_serviceUUIDs.push_back(serviceUUID);
m_haveServiceUUID = true; m_haveServiceUUID = true;
NIMBLE_LOGD(LOG_TAG,"- addServiceUUID(): serviceUUID: %s", serviceUUID.toString().c_str()); NIMBLE_LOGD(LOG_TAG,"- addServiceUUID(): serviceUUID: %s", serviceUUID.toString().c_str());
@ -542,5 +551,6 @@ void NimBLEAdvertisedDevice::setAdvertisementResult(uint8_t* payload, uint8_t le
m_payloadLength = length; m_payloadLength = length;
} }
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */

View File

@ -17,6 +17,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
#include "NimBLEAddress.h" #include "NimBLEAddress.h"
#include "NimBLEScan.h" #include "NimBLEScan.h"
#include "NimBLEUUID.h" #include "NimBLEUUID.h"
@ -54,7 +57,7 @@ public:
void setAddressType(uint8_t type); void setAddressType(uint8_t type);
bool isAdvertisingService(NimBLEUUID uuid); bool isAdvertisingService(const NimBLEUUID &uuid);
bool haveAppearance(); bool haveAppearance();
bool haveManufacturerData(); bool haveManufacturerData();
bool haveName(); bool haveName();
@ -92,7 +95,7 @@ private:
bool m_haveTXPower; bool m_haveTXPower;
NimBLEAddress m_address = NimBLEAddress("\0\0\0\0\0\0"); NimBLEAddress m_address = NimBLEAddress("");
uint8_t m_advType; uint8_t m_advType;
uint16_t m_appearance; uint16_t m_appearance;
int m_deviceType; int m_deviceType;
@ -129,5 +132,6 @@ public:
virtual void onResult(NimBLEAdvertisedDevice* advertisedDevice) = 0; virtual void onResult(NimBLEAdvertisedDevice* advertisedDevice) = 0;
}; };
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */
#endif /* COMPONENTS_NIMBLEADVERTISEDDEVICE_H_ */ #endif /* COMPONENTS_NIMBLEADVERTISEDDEVICE_H_ */

View File

@ -15,6 +15,10 @@
*/ */
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
#include "services/gap/ble_svc_gap.h" #include "services/gap/ble_svc_gap.h"
#include "NimBLEAdvertising.h" #include "NimBLEAdvertising.h"
#include "NimBLEDevice.h" #include "NimBLEDevice.h"
@ -58,7 +62,7 @@ NimBLEAdvertising::NimBLEAdvertising() {
* @brief Add a service uuid to exposed list of services. * @brief Add a service uuid to exposed list of services.
* @param [in] serviceUUID The UUID of the service to expose. * @param [in] serviceUUID The UUID of the service to expose.
*/ */
void NimBLEAdvertising::addServiceUUID(NimBLEUUID serviceUUID) { void NimBLEAdvertising::addServiceUUID(const NimBLEUUID &serviceUUID) {
m_serviceUUIDs.push_back(serviceUUID); m_serviceUUIDs.push_back(serviceUUID);
} // addServiceUUID } // addServiceUUID
@ -188,10 +192,17 @@ void NimBLEAdvertising::start() {
return; return;
} }
if(NimBLEDevice::createServer()->getConnectedCount() >= NIMBLE_MAX_CONNECTIONS) { #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
NimBLEServer* pServer = NimBLEDevice::getServer();
if(pServer != nullptr) {
if(!pServer->m_gattsStarted){
pServer->start();
} else if(pServer->getConnectedCount() >= NIMBLE_MAX_CONNECTIONS) {
NIMBLE_LOGW(LOG_TAG, "Max connections reached - not advertising"); NIMBLE_LOGW(LOG_TAG, "Max connections reached - not advertising");
return; return;
} }
}
#endif
int numServices = m_serviceUUIDs.size(); int numServices = m_serviceUUIDs.size();
int rc = 0; int rc = 0;
@ -203,11 +214,6 @@ void NimBLEAdvertising::start() {
return; return;
} }
NimBLEServer* pServer = NimBLEDevice::createServer();
if(!pServer->m_gattsStarted){
pServer->start();
}
if (!m_customAdvData && !m_advSvcsSet && numServices > 0) { if (!m_customAdvData && !m_advSvcsSet && numServices > 0) {
for (int i = 0; i < numServices; i++) { for (int i = 0; i < numServices; i++) {
if(m_serviceUUIDs[i].getNative()->u.type == BLE_UUID_TYPE_16) { if(m_serviceUUIDs[i].getNative()->u.type == BLE_UUID_TYPE_16) {
@ -352,8 +358,15 @@ void NimBLEAdvertising::start() {
abort(); abort();
} }
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
rc = ble_gap_adv_start(addressType, NULL, BLE_HS_FOREVER, rc = ble_gap_adv_start(addressType, NULL, BLE_HS_FOREVER,
&m_advParams, NimBLEServer::handleGapEvent, NimBLEDevice::createServer()); //get a reference to the server (does not create a new one) &m_advParams,
(pServer != nullptr) ? NimBLEServer::handleGapEvent : NULL,
pServer);
#else
rc = ble_gap_adv_start(addressType, NULL, BLE_HS_FOREVER,
&m_advParams, NULL,NULL);
#endif
if (rc != 0) { if (rc != 0) {
NIMBLE_LOGC(LOG_TAG, "Error enabling advertising; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc)); NIMBLE_LOGC(LOG_TAG, "Error enabling advertising; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
abort(); abort();
@ -393,7 +406,7 @@ void NimBLEAdvertising::onHostReset() {
* @brief Add data to the payload to be advertised. * @brief Add data to the payload to be advertised.
* @param [in] data The data to be added to the payload. * @param [in] data The data to be added to the payload.
*/ */
void NimBLEAdvertisementData::addData(std::string data) { void NimBLEAdvertisementData::addData(const std::string &data) {
if ((m_payload.length() + data.length()) > BLE_HS_ADV_MAX_SZ) { if ((m_payload.length() + data.length()) > BLE_HS_ADV_MAX_SZ) {
return; return;
} }
@ -420,7 +433,7 @@ void NimBLEAdvertisementData::setAppearance(uint16_t appearance) {
* @brief Set the complete services. * @brief Set the complete services.
* @param [in] uuid The single service to advertise. * @param [in] uuid The single service to advertise.
*/ */
void NimBLEAdvertisementData::setCompleteServices(NimBLEUUID uuid) { void NimBLEAdvertisementData::setCompleteServices(const NimBLEUUID &uuid) {
char cdata[2]; char cdata[2];
switch (uuid.bitSize()) { switch (uuid.bitSize()) {
case 16: { case 16: {
@ -482,7 +495,7 @@ void NimBLEAdvertisementData::setFlags(uint8_t flag) {
* @brief Set manufacturer specific data. * @brief Set manufacturer specific data.
* @param [in] data Manufacturer data. * @param [in] data Manufacturer data.
*/ */
void NimBLEAdvertisementData::setManufacturerData(std::string data) { void NimBLEAdvertisementData::setManufacturerData(const std::string &data) {
NIMBLE_LOGD("NimBLEAdvertisementData", ">> setManufacturerData"); NIMBLE_LOGD("NimBLEAdvertisementData", ">> setManufacturerData");
char cdata[2]; char cdata[2];
cdata[0] = data.length() + 1; cdata[0] = data.length() + 1;
@ -496,7 +509,7 @@ void NimBLEAdvertisementData::setManufacturerData(std::string data) {
* @brief Set the name. * @brief Set the name.
* @param [in] The complete name of the device. * @param [in] The complete name of the device.
*/ */
void NimBLEAdvertisementData::setName(std::string name) { void NimBLEAdvertisementData::setName(const std::string &name) {
NIMBLE_LOGD("NimBLEAdvertisementData", ">> setName: %s", name.c_str()); NIMBLE_LOGD("NimBLEAdvertisementData", ">> setName: %s", name.c_str());
char cdata[2]; char cdata[2];
cdata[0] = name.length() + 1; cdata[0] = name.length() + 1;
@ -510,7 +523,7 @@ void NimBLEAdvertisementData::setName(std::string name) {
* @brief Set the partial services. * @brief Set the partial services.
* @param [in] uuid The single service to advertise. * @param [in] uuid The single service to advertise.
*/ */
void NimBLEAdvertisementData::setPartialServices(NimBLEUUID uuid) { void NimBLEAdvertisementData::setPartialServices(const NimBLEUUID &uuid) {
char cdata[2]; char cdata[2];
switch (uuid.bitSize()) { switch (uuid.bitSize()) {
case 16: { case 16: {
@ -548,7 +561,7 @@ void NimBLEAdvertisementData::setPartialServices(NimBLEUUID uuid) {
* @param [in] uuid The UUID to set with the service data. Size of UUID will be used. * @param [in] uuid The UUID to set with the service data. Size of UUID will be used.
* @param [in] data The data to be associated with the service data advert. * @param [in] data The data to be associated with the service data advert.
*/ */
void NimBLEAdvertisementData::setServiceData(NimBLEUUID uuid, std::string data) { void NimBLEAdvertisementData::setServiceData(const NimBLEUUID &uuid, const std::string &data) {
char cdata[2]; char cdata[2];
switch (uuid.bitSize()) { switch (uuid.bitSize()) {
case 16: { case 16: {
@ -585,7 +598,7 @@ void NimBLEAdvertisementData::setServiceData(NimBLEUUID uuid, std::string data)
* @brief Set the short name. * @brief Set the short name.
* @param [in] The short name of the device. * @param [in] The short name of the device.
*/ */
void NimBLEAdvertisementData::setShortName(std::string name) { void NimBLEAdvertisementData::setShortName(const std::string &name) {
NIMBLE_LOGD("NimBLEAdvertisementData", ">> setShortName: %s", name.c_str()); NIMBLE_LOGD("NimBLEAdvertisementData", ">> setShortName: %s", name.c_str());
char cdata[2]; char cdata[2];
cdata[0] = name.length() + 1; cdata[0] = name.length() + 1;
@ -603,4 +616,5 @@ std::string NimBLEAdvertisementData::getPayload() {
return m_payload; return m_payload;
} // getPayload } // getPayload
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */

View File

@ -17,6 +17,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
#include "host/ble_gap.h" #include "host/ble_gap.h"
/**** FIX COMPILATION ****/ /**** FIX COMPILATION ****/
#undef min #undef min
@ -47,14 +50,14 @@ class NimBLEAdvertisementData {
// //
public: public:
void setAppearance(uint16_t appearance); void setAppearance(uint16_t appearance);
void setCompleteServices(NimBLEUUID uuid); void setCompleteServices(const NimBLEUUID &uuid);
void setFlags(uint8_t); void setFlags(uint8_t);
void setManufacturerData(std::string data); void setManufacturerData(const std::string &data);
void setName(std::string name); void setName(const std::string &name);
void setPartialServices(NimBLEUUID uuid); void setPartialServices(const NimBLEUUID &uuid);
void setServiceData(NimBLEUUID uuid, std::string data); void setServiceData(const NimBLEUUID &uuid, const std::string &data);
void setShortName(std::string name); void setShortName(const std::string &name);
void addData(std::string data); // Add data to the payload. void addData(const std::string &data); // Add data to the payload.
std::string getPayload(); // Retrieve the current advert payload. std::string getPayload(); // Retrieve the current advert payload.
private: private:
@ -71,7 +74,7 @@ private:
class NimBLEAdvertising { class NimBLEAdvertising {
public: public:
NimBLEAdvertising(); NimBLEAdvertising();
void addServiceUUID(NimBLEUUID serviceUUID); void addServiceUUID(const NimBLEUUID &serviceUUID);
void addServiceUUID(const char* serviceUUID); void addServiceUUID(const char* serviceUUID);
void start(); void start();
void stop(); void stop();
@ -90,7 +93,9 @@ public:
private: private:
friend class NimBLEDevice; friend class NimBLEDevice;
void onHostReset(); void onHostReset();
ble_hs_adv_fields m_advData; ble_hs_adv_fields m_advData;
ble_hs_adv_fields m_scanData; ble_hs_adv_fields m_scanData;
ble_gap_adv_params m_advParams; ble_gap_adv_params m_advParams;
@ -101,5 +106,7 @@ private:
bool m_advSvcsSet = false; bool m_advSvcsSet = false;
}; };
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */
#endif /* MAIN_BLEADVERTISING_H_ */ #endif /* MAIN_BLEADVERTISING_H_ */

View File

@ -13,6 +13,7 @@
*/ */
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include <string.h> #include <string.h>
#include "NimBLEBeacon.h" #include "NimBLEBeacon.h"
#include "NimBLELog.h" #include "NimBLELog.h"
@ -58,7 +59,7 @@ int8_t NimBLEBeacon::getSignalPower() {
/** /**
* Set the raw data for the beacon record. * Set the raw data for the beacon record.
*/ */
void NimBLEBeacon::setData(std::string data) { void NimBLEBeacon::setData(const std::string &data) {
if (data.length() != sizeof(m_beaconData)) { if (data.length() != sizeof(m_beaconData)) {
NIMBLE_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and expected %d", NIMBLE_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and expected %d",
data.length(), sizeof(m_beaconData)); data.length(), sizeof(m_beaconData));
@ -79,14 +80,14 @@ void NimBLEBeacon::setMinor(uint16_t minor) {
m_beaconData.minor = ENDIAN_CHANGE_U16(minor); m_beaconData.minor = ENDIAN_CHANGE_U16(minor);
} // setMinior } // setMinior
void NimBLEBeacon::setProximityUUID(NimBLEUUID uuid) { void NimBLEBeacon::setProximityUUID(const NimBLEUUID &uuid) {
uuid = uuid.to128(); NimBLEUUID temp_uuid = uuid;
memcpy(m_beaconData.proximityUUID, uuid.getNative()->u128.value, 16); temp_uuid.to128();
memcpy(m_beaconData.proximityUUID, temp_uuid.getNative()->u128.value, 16);
} // setProximityUUID } // setProximityUUID
void NimBLEBeacon::setSignalPower(int8_t signalPower) { void NimBLEBeacon::setSignalPower(int8_t signalPower) {
m_beaconData.signalPower = signalPower; m_beaconData.signalPower = signalPower;
} // setSignalPower } // setSignalPower
#endif #endif

View File

@ -14,6 +14,7 @@
#ifndef MAIN_NIMBLEBEACON_H_ #ifndef MAIN_NIMBLEBEACON_H_
#define MAIN_NIMBLEBEACON_H_ #define MAIN_NIMBLEBEACON_H_
#include "NimBLEUUID.h" #include "NimBLEUUID.h"
/** /**
* @brief Representation of a beacon. * @brief Representation of a beacon.
@ -39,11 +40,11 @@ public:
uint16_t getManufacturerId(); uint16_t getManufacturerId();
NimBLEUUID getProximityUUID(); NimBLEUUID getProximityUUID();
int8_t getSignalPower(); int8_t getSignalPower();
void setData(std::string data); void setData(const std::string &data);
void setMajor(uint16_t major); void setMajor(uint16_t major);
void setMinor(uint16_t minor); void setMinor(uint16_t minor);
void setManufacturerId(uint16_t manufacturerId); void setManufacturerId(uint16_t manufacturerId);
void setProximityUUID(NimBLEUUID uuid); void setProximityUUID(const NimBLEUUID &uuid);
void setSignalPower(int8_t signalPower); void setSignalPower(int8_t signalPower);
}; // NimBLEBeacon }; // NimBLEBeacon

View File

@ -12,6 +12,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#include "NimBLECharacteristic.h" #include "NimBLECharacteristic.h"
#include "NimBLE2902.h" #include "NimBLE2902.h"
#include "NimBLE2904.h" #include "NimBLE2904.h"
@ -41,7 +44,7 @@ NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties
* @param [in] uuid - UUID for the characteristic. * @param [in] uuid - UUID for the characteristic.
* @param [in] properties - Properties for the characteristic. * @param [in] properties - Properties for the characteristic.
*/ */
NimBLECharacteristic::NimBLECharacteristic(NimBLEUUID uuid, uint16_t properties, NimBLEService* pService) { NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t properties, NimBLEService* pService) {
m_uuid = uuid; m_uuid = uuid;
m_handle = NULL_HANDLE; m_handle = NULL_HANDLE;
m_properties = properties; m_properties = properties;
@ -99,7 +102,7 @@ NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const char* uuid, uint3
* @param [in] properties - The properties of the descriptor. * @param [in] properties - The properties of the descriptor.
* @return The new BLE descriptor. * @return The new BLE descriptor.
*/ */
NimBLEDescriptor* NimBLECharacteristic::createDescriptor(NimBLEUUID uuid, uint32_t properties, uint16_t max_len) { NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID &uuid, uint32_t properties, uint16_t max_len) {
NimBLEDescriptor* pDescriptor = nullptr; NimBLEDescriptor* pDescriptor = nullptr;
if(uuid.equals(NimBLEUUID((uint16_t)0x2902))) { if(uuid.equals(NimBLEUUID((uint16_t)0x2902))) {
if(!(m_properties & BLE_GATT_CHR_F_NOTIFY) && !(m_properties & BLE_GATT_CHR_F_INDICATE)) { if(!(m_properties & BLE_GATT_CHR_F_NOTIFY) && !(m_properties & BLE_GATT_CHR_F_INDICATE)) {
@ -139,7 +142,7 @@ NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* descript
* @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve. * @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve.
* @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned. * @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned.
*/ */
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(NimBLEUUID descriptorUUID) { NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &descriptorUUID) {
return m_descriptorMap.getByUUID(descriptorUUID); return m_descriptorMap.getByUUID(descriptorUUID);
} // getDescriptorByUUID } // getDescriptorByUUID
@ -198,6 +201,15 @@ uint8_t* NimBLECharacteristic::getData() {
} // 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();
}
int NimBLECharacteristic::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle, int NimBLECharacteristic::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, struct ble_gatt_access_ctxt *ctxt,
void *arg) void *arg)
@ -509,7 +521,7 @@ void NimBLECharacteristic::setWriteProperty(bool value) {
* @param [in] data The data to set for the characteristic. * @param [in] data The data to set for the characteristic.
* @param [in] length The length of the data in bytes. * @param [in] length The length of the data in bytes.
*/ */
void NimBLECharacteristic::setValue(uint8_t* data, size_t length) { void NimBLECharacteristic::setValue(const uint8_t* data, size_t length) {
char* pHex = NimBLEUtils::buildHexData(nullptr, data, length); char* pHex = NimBLEUtils::buildHexData(nullptr, data, length);
NIMBLE_LOGD(LOG_TAG, ">> setValue: length=%d, data=%s, characteristic UUID=%s", length, pHex, getUUID().toString().c_str()); NIMBLE_LOGD(LOG_TAG, ">> setValue: length=%d, data=%s, characteristic UUID=%s", length, pHex, getUUID().toString().c_str());
free(pHex); free(pHex);
@ -537,7 +549,7 @@ void NimBLECharacteristic::setValue(uint8_t* data, size_t length) {
* @param [in] Set the value of the characteristic. * @param [in] Set the value of the characteristic.
* @return N/A. * @return N/A.
*/ */
void NimBLECharacteristic::setValue(std::string value) { void NimBLECharacteristic::setValue(const std::string &value) {
setValue((uint8_t*)(value.data()), value.length()); setValue((uint8_t*)(value.data()), value.length());
} // setValue } // setValue
@ -637,4 +649,5 @@ void NimBLECharacteristicCallbacks::onStatus(NimBLECharacteristic* pCharacterist
NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onStatus: default"); NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onStatus: default");
} // onStatus } // onStatus
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */

View File

@ -16,6 +16,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#include "host/ble_hs.h" #include "host/ble_hs.h"
/**** FIX COMPILATION ****/ /**** FIX COMPILATION ****/
#undef min #undef min
@ -58,10 +61,10 @@ class NimBLECharacteristicCallbacks;
class NimBLEDescriptorMap { class NimBLEDescriptorMap {
public: public:
void setByUUID(const char* uuid, NimBLEDescriptor* pDescriptor); void setByUUID(const char* uuid, NimBLEDescriptor* pDescriptor);
void setByUUID(NimBLEUUID uuid, NimBLEDescriptor* pDescriptor); void setByUUID(const NimBLEUUID &uuid, NimBLEDescriptor* pDescriptor);
// void setByHandle(uint16_t handle, NimBLEDescriptor* pDescriptor); // void setByHandle(uint16_t handle, NimBLEDescriptor* pDescriptor);
NimBLEDescriptor* getByUUID(const char* uuid); NimBLEDescriptor* getByUUID(const char* uuid);
NimBLEDescriptor* getByUUID(NimBLEUUID uuid); NimBLEDescriptor* getByUUID(const NimBLEUUID &uuid);
// NimBLEDescriptor* getByHandle(uint16_t handle); // NimBLEDescriptor* getByHandle(uint16_t handle);
std::string toString(); std::string toString();
NimBLEDescriptor* getFirst(); NimBLEDescriptor* getFirst();
@ -87,16 +90,17 @@ public:
uint32_t properties = NIMBLE_PROPERTY::READ | uint32_t properties = NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE, NIMBLE_PROPERTY::WRITE,
uint16_t max_len = 100); uint16_t max_len = 100);
NimBLEDescriptor* createDescriptor(NimBLEUUID uuid, NimBLEDescriptor* createDescriptor(const NimBLEUUID &uuid,
uint32_t properties = NIMBLE_PROPERTY::READ | uint32_t properties = NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE, NIMBLE_PROPERTY::WRITE,
uint16_t max_len = 100); uint16_t max_len = 100);
NimBLEDescriptor* getDescriptorByUUID(const char* descriptorUUID); NimBLEDescriptor* getDescriptorByUUID(const char* descriptorUUID);
NimBLEDescriptor* getDescriptorByUUID(NimBLEUUID descriptorUUID); NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &descriptorUUID);
NimBLEUUID getUUID(); NimBLEUUID getUUID();
std::string getValue(); std::string getValue();
uint8_t* getData(); uint8_t* getData();
size_t getDataLength();
void indicate(); void indicate();
void notify(bool is_notification = true); void notify(bool is_notification = true);
@ -109,8 +113,8 @@ public:
void setWriteProperty(bool value); void setWriteProperty(bool value);
void setWriteNoResponseProperty(bool value); void setWriteNoResponseProperty(bool value);
////////////////////////////////////////////////////// //////////////////////////////////////////////////////
void setValue(uint8_t* data, size_t size); void setValue(const uint8_t* data, size_t size);
void setValue(std::string value); void setValue(const std::string &value);
void setValue(uint16_t& data16); void setValue(uint16_t& data16);
void setValue(uint32_t& data32); void setValue(uint32_t& data32);
void setValue(int& data32); void setValue(int& data32);
@ -140,7 +144,7 @@ private:
NimBLECharacteristic(const char* uuid, uint16_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE, NimBLECharacteristic(const char* uuid, uint16_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
NimBLEService* pService = nullptr); NimBLEService* pService = nullptr);
NimBLECharacteristic(NimBLEUUID uuid, uint16_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE, NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
NimBLEService* pService = nullptr); NimBLEService* pService = nullptr);
virtual ~NimBLECharacteristic(); virtual ~NimBLECharacteristic();
@ -190,5 +194,7 @@ public:
virtual void onNotify(NimBLECharacteristic* pCharacteristic); virtual void onNotify(NimBLECharacteristic* pCharacteristic);
virtual void onStatus(NimBLECharacteristic* pCharacteristic, Status s, int code); virtual void onStatus(NimBLECharacteristic* pCharacteristic, Status s, int code);
}; };
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */
#endif /*MAIN_NIMBLECHARACTERISTIC_H_*/ #endif /*MAIN_NIMBLECHARACTERISTIC_H_*/

View File

@ -12,6 +12,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#include "NimBLEService.h" #include "NimBLEService.h"
#include "NimBLELog.h" #include "NimBLELog.h"
@ -41,7 +44,7 @@ NimBLECharacteristic* NimBLECharacteristicMap::getByUUID(const char* uuid) {
* @param [in] UUID The UUID to look up the characteristic. * @param [in] UUID The UUID to look up the characteristic.
* @return The characteristic. * @return The characteristic.
*/ */
NimBLECharacteristic* NimBLECharacteristicMap::getByUUID(NimBLEUUID uuid) { NimBLECharacteristic* NimBLECharacteristicMap::getByUUID(const NimBLEUUID &uuid) {
for (auto &myPair : m_uuidMap) { for (auto &myPair : m_uuidMap) {
if (myPair.first->getUUID().equals(uuid)) { if (myPair.first->getUUID().equals(uuid)) {
return myPair.first; return myPair.first;
@ -100,7 +103,7 @@ void NimBLECharacteristicMap::setByHandle(uint16_t handle, NimBLECharacteristic*
* @param [in] characteristic The characteristic to cache. * @param [in] characteristic The characteristic to cache.
* @return N/A. * @return N/A.
*/ */
void NimBLECharacteristicMap::setByUUID(NimBLECharacteristic* pCharacteristic, NimBLEUUID uuid) { void NimBLECharacteristicMap::setByUUID(NimBLECharacteristic* pCharacteristic, const NimBLEUUID &uuid) {
m_uuidMap.insert(std::pair<NimBLECharacteristic*, std::string>(pCharacteristic, uuid.toString())); m_uuidMap.insert(std::pair<NimBLECharacteristic*, std::string>(pCharacteristic, uuid.toString()));
} // setByUUID } // setByUUID
@ -125,4 +128,5 @@ std::string NimBLECharacteristicMap::toString() {
} // toString } // toString
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */

View File

@ -14,6 +14,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#include "NimBLEClient.h" #include "NimBLEClient.h"
#include "NimBLEUtils.h" #include "NimBLEUtils.h"
#include "NimBLEDevice.h" #include "NimBLEDevice.h"
@ -40,8 +43,8 @@ static NimBLEClientCallbacks defaultCallbacks;
* Since there is a hierarchical relationship here, we will have the idea that from a NimBLERemoteService will own * Since there is a hierarchical relationship here, we will have the idea that from a NimBLERemoteService will own
* zero or more remote characteristics and a NimBLERemoteCharacteristic will own zero or more remote NimBLEDescriptors. * zero or more remote characteristics and a NimBLERemoteCharacteristic will own zero or more remote NimBLEDescriptors.
* *
* We will assume that a NimBLERemoteService contains a map that maps NimBLEUUIDs to the set of owned characteristics * We will assume that a NimBLERemoteService contains a vector of owned characteristics
* and that a NimBLECharacteristic contains a map that maps NimBLEUUIDs to the set of owned descriptors. * and that a NimBLECharacteristic contains a vector of owned descriptors.
* *
* *
*/ */
@ -50,7 +53,6 @@ NimBLEClient::NimBLEClient()
{ {
m_pClientCallbacks = &defaultCallbacks; m_pClientCallbacks = &defaultCallbacks;
m_conn_id = BLE_HS_CONN_HANDLE_NONE; m_conn_id = BLE_HS_CONN_HANDLE_NONE;
m_haveServices = false;
m_isConnected = false; m_isConnected = false;
m_connectTimeout = 30000; m_connectTimeout = 30000;
@ -74,7 +76,7 @@ NimBLEClient::~NimBLEClient() {
// Before we are finished with the client, we must release resources. // Before we are finished with the client, we must release resources.
clearServices(); clearServices();
if(m_deleteCallbacks) { if(m_deleteCallbacks && m_pClientCallbacks != &defaultCallbacks) {
delete m_pClientCallbacks; delete m_pClientCallbacks;
} }
@ -87,11 +89,11 @@ NimBLEClient::~NimBLEClient() {
void NimBLEClient::clearServices() { void NimBLEClient::clearServices() {
NIMBLE_LOGD(LOG_TAG, ">> clearServices"); NIMBLE_LOGD(LOG_TAG, ">> clearServices");
// Delete all the services. // Delete all the services.
for (auto &myPair : m_servicesMap) { for(auto &it: m_servicesVector) {
delete myPair.second; delete it;
} }
m_servicesMap.clear(); m_servicesVector.clear();
m_haveServices = false;
NIMBLE_LOGD(LOG_TAG, "<< clearServices"); NIMBLE_LOGD(LOG_TAG, "<< clearServices");
} // clearServices } // clearServices
@ -120,7 +122,7 @@ bool NimBLEClient::connect(NimBLEAdvertisedDevice* device, bool refreshServices)
* @param [in] address The address of the partner. * @param [in] address The address of the partner.
* @return True on success. * @return True on success.
*/ */
bool NimBLEClient::connect(NimBLEAddress address, uint8_t type, bool refreshServices) { bool NimBLEClient::connect(const NimBLEAddress &address, uint8_t type, bool refreshServices) {
NIMBLE_LOGD(LOG_TAG, ">> connect(%s)", address.toString().c_str()); NIMBLE_LOGD(LOG_TAG, ">> connect(%s)", address.toString().c_str());
if(!NimBLEDevice::m_synced) { if(!NimBLEDevice::m_synced) {
@ -179,18 +181,6 @@ bool NimBLEClient::connect(NimBLEAddress address, uint8_t type, bool refreshServ
clearServices(); clearServices();
} }
if (!m_haveServices) {
if (!retrieveServices()) {
// error getting services, make sure we disconnect and release any resources before returning
disconnect();
clearServices();
return false;
}
else{
NIMBLE_LOGD(LOG_TAG, "Found %d services", getServices()->size());
}
}
m_pClientCallbacks->onConnect(this); m_pClientCallbacks->onConnect(this);
NIMBLE_LOGD(LOG_TAG, "<< connect()"); NIMBLE_LOGD(LOG_TAG, "<< connect()");
@ -344,6 +334,24 @@ int NimBLEClient::getRssi() {
} // getRssi } // getRssi
/**
* @brief Get iterator to the beginning of the vector of remote service pointers.
* @return An iterator to the beginning of the vector of remote service pointers.
*/
std::vector<NimBLERemoteService*>::iterator NimBLEClient::begin() {
return m_servicesVector.begin();
}
/**
* @brief Get iterator to the end of the vector of remote service pointers.
* @return An iterator to the end of the vector of remote service pointers.
*/
std::vector<NimBLERemoteService*>::iterator NimBLEClient::end() {
return m_servicesVector.end();
}
/** /**
* @brief Get the service BLE Remote Service instance corresponding to the uuid. * @brief Get the service BLE Remote Service instance corresponding to the uuid.
* @param [in] uuid The UUID of the service being sought. * @param [in] uuid The UUID of the service being sought.
@ -359,29 +367,62 @@ NimBLERemoteService* NimBLEClient::getService(const char* uuid) {
* @param [in] uuid The UUID of the service being sought. * @param [in] uuid The UUID of the service being sought.
* @return A reference to the Service or nullptr if don't know about it. * @return A reference to the Service or nullptr if don't know about it.
*/ */
NimBLERemoteService* NimBLEClient::getService(NimBLEUUID uuid) { NimBLERemoteService* NimBLEClient::getService(const NimBLEUUID &uuid) {
NIMBLE_LOGD(LOG_TAG, ">> getService: uuid: %s", uuid.toString().c_str()); NIMBLE_LOGD(LOG_TAG, ">> getService: uuid: %s", uuid.toString().c_str());
if (!m_haveServices) { for(auto &it: m_servicesVector) {
return nullptr; if(it->getUUID() == uuid) {
}
std::string uuidStr = uuid.toString();
for (auto &myPair : m_servicesMap) {
if (myPair.first == uuidStr) {
NIMBLE_LOGD(LOG_TAG, "<< getService: found the service with uuid: %s", uuid.toString().c_str()); NIMBLE_LOGD(LOG_TAG, "<< getService: found the service with uuid: %s", uuid.toString().c_str());
return myPair.second; return it;
} }
} }
size_t prev_size = m_servicesVector.size();
if(retrieveServices(&uuid)) {
if(m_servicesVector.size() > prev_size) {
return m_servicesVector.back();
}
}
NIMBLE_LOGD(LOG_TAG, "<< getService: not found"); NIMBLE_LOGD(LOG_TAG, "<< getService: not found");
return nullptr; return nullptr;
} // getService } // getService
/** /**
* @Get a pointer to the map of found services. * @Get a pointer to the vector of found services.
* @param [in] bool value to indicate if the current vector should be cleared and
* subsequently all services retrieved from the peripheral.
* If false the vector will be returned with the currently stored services,
* if vector is empty it will retrieve all services from the peripheral.
* @return a pointer to the vector of available services.
*/ */
std::map<std::string, NimBLERemoteService*>* NimBLEClient::getServices() { std::vector<NimBLERemoteService*>* NimBLEClient::getServices(bool refresh) {
return &m_servicesMap; if(refresh) {
clearServices();
}
if(m_servicesVector.empty()) {
if (!retrieveServices()) {
NIMBLE_LOGE(LOG_TAG, "Error: Failed to get services");
}
else{
NIMBLE_LOGI(LOG_TAG, "Found %d services", m_servicesVector.size());
}
}
return &m_servicesVector;
}
/**
* @ Retrieves the full database of attributes that the peripheral has available.
*/
void NimBLEClient::discoverAttributes() {
for(auto svc: *getServices(true)) {
for(auto chr: *svc->getCharacteristics(true)) {
chr->getDescriptors(true);
}
}
} }
@ -392,7 +433,7 @@ std::map<std::string, NimBLERemoteService*>* NimBLEClient::getServices() {
* We then ask for the characteristics for each service found and their desciptors. * We then ask for the characteristics for each service found and their desciptors.
* @return true on success otherwise false if an error occurred * @return true on success otherwise false if an error occurred
*/ */
bool NimBLEClient::retrieveServices() { bool NimBLEClient::retrieveServices(const NimBLEUUID *uuid_filter) {
/** /**
* Design * Design
* ------ * ------
@ -401,6 +442,7 @@ bool NimBLEClient::retrieveServices() {
*/ */
NIMBLE_LOGD(LOG_TAG, ">> retrieveServices"); NIMBLE_LOGD(LOG_TAG, ">> retrieveServices");
int rc = 0;
if(!m_isConnected){ if(!m_isConnected){
NIMBLE_LOGE(LOG_TAG, "Disconnected, could not retrieve services -aborting"); NIMBLE_LOGE(LOG_TAG, "Disconnected, could not retrieve services -aborting");
@ -409,26 +451,21 @@ bool NimBLEClient::retrieveServices() {
m_semaphoreSearchCmplEvt.take("retrieveServices"); m_semaphoreSearchCmplEvt.take("retrieveServices");
int rc = ble_gattc_disc_all_svcs(m_conn_id, NimBLEClient::serviceDiscoveredCB, this); if(uuid_filter == nullptr) {
rc = ble_gattc_disc_all_svcs(m_conn_id, NimBLEClient::serviceDiscoveredCB, this);
} else {
rc = ble_gattc_disc_svc_by_uuid(m_conn_id, &uuid_filter->getNative()->u,
NimBLEClient::serviceDiscoveredCB, this);
}
if (rc != 0) { if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_svcs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_svcs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
m_haveServices = false;
m_semaphoreSearchCmplEvt.give(); m_semaphoreSearchCmplEvt.give();
return false; return false;
} }
// wait until we have all the services // wait until we have all the services
// If sucessful, remember that we now have services. if(m_semaphoreSearchCmplEvt.wait("retrieveServices") == 0){
m_haveServices = (m_semaphoreSearchCmplEvt.wait("retrieveServices") == 0);
if(m_haveServices){
for (auto &myPair : m_servicesMap) {
if(!m_isConnected || !myPair.second->retrieveCharacteristics()) {
NIMBLE_LOGE(LOG_TAG, "Disconnected, could not retrieve characteristics -aborting");
return false;
}
}
NIMBLE_LOGD(LOG_TAG, "<< retrieveServices"); NIMBLE_LOGD(LOG_TAG, "<< retrieveServices");
return true; return true;
} }
@ -449,7 +486,9 @@ int NimBLEClient::serviceDiscoveredCB(
const struct ble_gatt_error *error, const struct ble_gatt_error *error,
const struct ble_gatt_svc *service, void *arg) const struct ble_gatt_svc *service, void *arg)
{ {
NIMBLE_LOGD(LOG_TAG,"Service Discovered >> status: %d handle: %d", error->status, conn_handle); NIMBLE_LOGD(LOG_TAG,"Service Discovered >> status: %d handle: %d",
error->status, (error->status == 0) ? service->start_handle : -1);
NimBLEClient *peer = (NimBLEClient*)arg; NimBLEClient *peer = (NimBLEClient*)arg;
int rc=0; int rc=0;
@ -460,9 +499,9 @@ int NimBLEClient::serviceDiscoveredCB(
switch (error->status) { switch (error->status) {
case 0: { case 0: {
// Found a service - add it to the map // Found a service - add it to the vector
NimBLERemoteService* pRemoteService = new NimBLERemoteService(peer, service); NimBLERemoteService* pRemoteService = new NimBLERemoteService(peer, service);
peer->m_servicesMap.insert(std::pair<std::string, NimBLERemoteService*>(pRemoteService->getUUID().toString(), pRemoteService)); peer->m_servicesVector.push_back(pRemoteService);
break; break;
} }
case BLE_HS_EDONE:{ case BLE_HS_EDONE:{
@ -494,8 +533,9 @@ int NimBLEClient::serviceDiscoveredCB(
* @param [in] characteristicUUID The characteristic whose value we wish to read. * @param [in] characteristicUUID The characteristic whose value we wish to read.
* @returns characteristic value or an empty string if not found * @returns characteristic value or an empty string if not found
*/ */
std::string NimBLEClient::getValue(NimBLEUUID serviceUUID, NimBLEUUID characteristicUUID) { std::string NimBLEClient::getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID) {
NIMBLE_LOGD(LOG_TAG, ">> getValue: serviceUUID: %s, characteristicUUID: %s", serviceUUID.toString().c_str(), characteristicUUID.toString().c_str()); NIMBLE_LOGD(LOG_TAG, ">> getValue: serviceUUID: %s, characteristicUUID: %s",
serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
std::string ret = ""; std::string ret = "";
NimBLERemoteService* pService = getService(serviceUUID); NimBLERemoteService* pService = getService(serviceUUID);
@ -518,8 +558,11 @@ std::string NimBLEClient::getValue(NimBLEUUID serviceUUID, NimBLEUUID characteri
* @param [in] characteristicUUID The characteristic whose value we wish to write. * @param [in] characteristicUUID The characteristic whose value we wish to write.
* @returns true if successful otherwise false * @returns true if successful otherwise false
*/ */
bool NimBLEClient::setValue(NimBLEUUID serviceUUID, NimBLEUUID characteristicUUID, std::string value) { bool NimBLEClient::setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID,
NIMBLE_LOGD(LOG_TAG, ">> setValue: serviceUUID: %s, characteristicUUID: %s", serviceUUID.toString().c_str(), characteristicUUID.toString().c_str()); const std::string &value)
{
NIMBLE_LOGD(LOG_TAG, ">> setValue: serviceUUID: %s, characteristicUUID: %s",
serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
bool ret = false; bool ret = false;
NimBLERemoteService* pService = getService(serviceUUID); NimBLERemoteService* pService = getService(serviceUUID);
@ -656,23 +699,33 @@ uint16_t NimBLEClient::getMTU() {
return 0; return 0;
NIMBLE_LOGD(LOG_TAG, "Notify Recieved for handle: %d",event->notify_rx.attr_handle); NIMBLE_LOGD(LOG_TAG, "Notify Recieved for handle: %d",event->notify_rx.attr_handle);
if(!client->m_haveServices)
return 0;
for(auto &sPair : client->m_servicesMap){ for(auto &it: client->m_servicesVector) {
// Dont waste cycles searching services without this handle in their range // Dont waste cycles searching services without this handle in their range
if(sPair.second->getEndHandle() < event->notify_rx.attr_handle) { if(it->getEndHandle() < event->notify_rx.attr_handle) {
continue; continue;
} }
auto cMap = sPair.second->getCharacteristicsByHandle();
NIMBLE_LOGD(LOG_TAG, "checking service %s for handle: %d", sPair.second->getUUID().toString().c_str(),event->notify_rx.attr_handle);
auto characteristic = cMap->find(event->notify_rx.attr_handle);
if(characteristic != cMap->end()) {
NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", characteristic->second->toString().c_str());
if (characteristic->second->m_notifyCallback != nullptr) { auto cVector = &it->m_characteristicVector;
NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s", characteristic->second->toString().c_str()); NIMBLE_LOGD(LOG_TAG, "checking service %s for handle: %d",
characteristic->second->m_notifyCallback(characteristic->second, event->notify_rx.om->om_data, event->notify_rx.om->om_len, !event->notify_rx.indication); it->getUUID().toString().c_str(),
event->notify_rx.attr_handle);
auto characteristic = cVector->cbegin();
for(; characteristic != cVector->cend(); ++characteristic) {
if((*characteristic)->m_handle == event->notify_rx.attr_handle)
break;
}
if(characteristic != cVector->cend()) {
NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", (*characteristic)->toString().c_str());
if ((*characteristic)->m_notifyCallback != nullptr) {
NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s",
(*characteristic)->toString().c_str());
(*characteristic)->m_notifyCallback(*characteristic, event->notify_rx.om->om_data,
event->notify_rx.om->om_len,
!event->notify_rx.indication);
} }
break; break;
@ -750,7 +803,6 @@ uint16_t NimBLEClient::getMTU() {
event->mtu.conn_handle, event->mtu.conn_handle,
event->mtu.value); event->mtu.value);
client->m_semaphoreOpenEvt.give(0); client->m_semaphoreOpenEvt.give(0);
//client->m_mtu = event->mtu.value;
return 0; return 0;
} // BLE_GAP_EVENT_MTU } // BLE_GAP_EVENT_MTU
@ -848,8 +900,9 @@ void NimBLEClient::setClientCallbacks(NimBLEClientCallbacks* pClientCallbacks, b
std::string NimBLEClient::toString() { std::string NimBLEClient::toString() {
std::string res = "peer address: " + m_peerAddress.toString(); std::string res = "peer address: " + m_peerAddress.toString();
res += "\nServices:\n"; res += "\nServices:\n";
for (auto &myPair : m_servicesMap) {
res += myPair.second->toString() + "\n"; for(auto &it: m_servicesVector) {
res += it->toString() + "\n";
} }
return res; return res;
@ -890,4 +943,5 @@ bool NimBLEClientCallbacks::onConfirmPIN(uint32_t pin){
return true; return true;
} }
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#endif // CONFIG_BT_ENABLED #endif // CONFIG_BT_ENABLED

View File

@ -14,16 +14,24 @@
#ifndef MAIN_NIMBLECLIENT_H_ #ifndef MAIN_NIMBLECLIENT_H_
#define MAIN_NIMBLECLIENT_H_ #define MAIN_NIMBLECLIENT_H_
#if defined(CONFIG_BT_ENABLED)
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#include "NimBLEAddress.h" #include "NimBLEAddress.h"
#include "NimBLEAdvertisedDevice.h" #include "NimBLEAdvertisedDevice.h"
#include "NimBLERemoteService.h" #include "NimBLERemoteService.h"
#include <map> #include <vector>
#include <string> #include <string>
typedef struct {
const NimBLEUUID *uuid;
const void *attribute;
} disc_filter_t;
class NimBLERemoteService; class NimBLERemoteService;
class NimBLEClientCallbacks; class NimBLEClientCallbacks;
class NimBLEAdvertisedDevice; class NimBLEAdvertisedDevice;
@ -34,57 +42,61 @@ class NimBLEAdvertisedDevice;
class NimBLEClient { class NimBLEClient {
public: public:
bool connect(NimBLEAdvertisedDevice* device, bool refreshServices = true); bool connect(NimBLEAdvertisedDevice* device, bool refreshServices = true);
bool connect(NimBLEAddress address, uint8_t type = BLE_ADDR_TYPE_PUBLIC, bool refreshServices = true); // Connect to the remote BLE Server bool connect(const NimBLEAddress &address, uint8_t type = BLE_ADDR_PUBLIC,
int disconnect(uint8_t reason = BLE_ERR_REM_USER_CONN_TERM); // Disconnect from the remote BLE Server bool refreshServices = true);
NimBLEAddress getPeerAddress(); // Get the address of the remote BLE Server int disconnect(uint8_t reason = BLE_ERR_REM_USER_CONN_TERM);
int getRssi(); // Get the RSSI of the remote BLE Server NimBLEAddress getPeerAddress();
std::map<std::string, NimBLERemoteService*>* getServices(); // Get a map of the services offered by the remote BLE Server int getRssi();
NimBLERemoteService* getService(const char* uuid); // Get a reference to a specified service offered by the remote BLE server. std::vector<NimBLERemoteService*>* getServices(bool refresh = false);
NimBLERemoteService* getService(NimBLEUUID uuid); // Get a reference to a specified service offered by the remote BLE server. std::vector<NimBLERemoteService*>::iterator begin();
std::string getValue(NimBLEUUID serviceUUID, NimBLEUUID characteristicUUID); // Get the value of a given characteristic at a given service. std::vector<NimBLERemoteService*>::iterator end();
bool setValue(NimBLEUUID serviceUUID, NimBLEUUID characteristicUUID, std::string value); // Set the value of a given characteristic at a given service. NimBLERemoteService* getService(const char* uuid);
bool isConnected(); // Return true if we are connected. NimBLERemoteService* getService(const NimBLEUUID &uuid);
void setClientCallbacks(NimBLEClientCallbacks *pClientCallbacks, bool deleteCallbacks = true); std::string getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID);
std::string toString(); // Return a string representation of this client. bool setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID,
const std::string &value);
bool isConnected();
void setClientCallbacks(NimBLEClientCallbacks *pClientCallbacks,
bool deleteCallbacks = true);
std::string toString();
uint16_t getConnId(); uint16_t getConnId();
uint16_t getMTU(); uint16_t getMTU();
bool secureConnection(); bool secureConnection();
void setConnectTimeout(uint8_t timeout); void setConnectTimeout(uint8_t timeout);
void setConnectionParams(uint16_t minInterval, uint16_t maxInterval, void setConnectionParams(uint16_t minInterval, uint16_t maxInterval,
uint16_t latency, uint16_t timeout, uint16_t latency, uint16_t timeout,
uint16_t scanInterval=16, uint16_t scanWindow=16); // NimBLE default scan settings uint16_t scanInterval=16, uint16_t scanWindow=16);
void updateConnParams(uint16_t minInterval, uint16_t maxInterval, void updateConnParams(uint16_t minInterval, uint16_t maxInterval,
uint16_t latency, uint16_t timeout); uint16_t latency, uint16_t timeout);
void discoverAttributes();
private: private:
NimBLEClient(); NimBLEClient();
~NimBLEClient(); ~NimBLEClient();
friend class NimBLEDevice; friend class NimBLEDevice;
friend class NimBLERemoteService; friend class NimBLERemoteService;
static int handleGapEvent(struct ble_gap_event *event, void *arg); static int handleGapEvent(struct ble_gap_event *event, void *arg);
static int serviceDiscoveredCB(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, void *arg); static int serviceDiscoveredCB(uint16_t conn_handle,
void clearServices(); // Clear any existing services. const struct ble_gatt_error *error,
bool retrieveServices(); //Retrieve services from the server const struct ble_gatt_svc *service,
// void onHostReset(); void *arg);
void clearServices();
bool retrieveServices(const NimBLEUUID *uuid_filter = nullptr);
NimBLEAddress m_peerAddress = NimBLEAddress("\0\0\0\0\0\0"); // The BD address of the remote server. NimBLEAddress m_peerAddress = NimBLEAddress("");
uint16_t m_conn_id; uint16_t m_conn_id;
bool m_haveServices = false; // Have we previously obtain the set of services from the remote server. bool m_isConnected = false;
bool m_isConnected = false; // Are we currently connected.
bool m_waitingToConnect =false; bool m_waitingToConnect =false;
bool m_deleteCallbacks = true; bool m_deleteCallbacks = true;
int32_t m_connectTimeout; int32_t m_connectTimeout;
//uint16_t m_mtu = 23;
NimBLEClientCallbacks* m_pClientCallbacks = nullptr; NimBLEClientCallbacks* m_pClientCallbacks = nullptr;
FreeRTOS::Semaphore m_semaphoreOpenEvt = FreeRTOS::Semaphore("OpenEvt"); FreeRTOS::Semaphore m_semaphoreOpenEvt = FreeRTOS::Semaphore("OpenEvt");
FreeRTOS::Semaphore m_semaphoreSearchCmplEvt = FreeRTOS::Semaphore("SearchCmplEvt"); FreeRTOS::Semaphore m_semaphoreSearchCmplEvt = FreeRTOS::Semaphore("SearchCmplEvt");
FreeRTOS::Semaphore m_semeaphoreSecEvt = FreeRTOS::Semaphore("Security"); FreeRTOS::Semaphore m_semeaphoreSecEvt = FreeRTOS::Semaphore("Security");
std::map<std::string, NimBLERemoteService*> m_servicesMap; std::vector<NimBLERemoteService*> m_servicesVector;
private: private:
friend class NimBLEClientCallbacks; friend class NimBLEClientCallbacks;
@ -109,5 +121,6 @@ public:
virtual bool onConfirmPIN(uint32_t pin); virtual bool onConfirmPIN(uint32_t pin);
}; };
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#endif // CONFIG_BT_ENABLED #endif // CONFIG_BT_ENABLED
#endif /* MAIN_NIMBLECLIENT_H_ */ #endif /* MAIN_NIMBLECLIENT_H_ */

View File

@ -14,6 +14,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#include "NimBLEService.h" #include "NimBLEService.h"
#include "NimBLEDescriptor.h" #include "NimBLEDescriptor.h"
#include "NimBLELog.h" #include "NimBLELog.h"
@ -187,7 +190,7 @@ void NimBLEDescriptor::setHandle(uint16_t handle) {
* @param [in] data The data to set for the descriptor. * @param [in] data The data to set for the descriptor.
* @param [in] length The length of the data in bytes. * @param [in] length The length of the data in bytes.
*/ */
void NimBLEDescriptor::setValue(uint8_t* data, size_t length) { void NimBLEDescriptor::setValue(const uint8_t* data, size_t length) {
if (length > BLE_ATT_ATTR_MAX_LEN) { if (length > BLE_ATT_ATTR_MAX_LEN) {
NIMBLE_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, BLE_ATT_ATTR_MAX_LEN); NIMBLE_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, BLE_ATT_ATTR_MAX_LEN);
return; return;
@ -201,7 +204,7 @@ void NimBLEDescriptor::setValue(uint8_t* data, size_t length) {
* @brief Set the value of the descriptor. * @brief Set the value of the descriptor.
* @param [in] value The value of the descriptor in string form. * @param [in] value The value of the descriptor in string form.
*/ */
void NimBLEDescriptor::setValue(std::string value) { void NimBLEDescriptor::setValue(const std::string &value) {
setValue((uint8_t*) value.data(), value.length()); setValue((uint8_t*) value.data(), value.length());
} // setValue } // setValue
@ -244,5 +247,5 @@ void NimBLEDescriptorCallbacks::onWrite(NimBLEDescriptor* pDescriptor) {
NIMBLE_LOGD("NimBLEDescriptorCallbacks", "onWrite: default"); NIMBLE_LOGD("NimBLEDescriptorCallbacks", "onWrite: default");
} // onWrite } // onWrite
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */

View File

@ -17,6 +17,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#include "NimBLECharacteristic.h" #include "NimBLECharacteristic.h"
#include "NimBLEUUID.h" #include "NimBLEUUID.h"
#include "FreeRTOS.h" #include "FreeRTOS.h"
@ -50,8 +53,8 @@ public:
uint8_t* getValue(); // Get a pointer to the value 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 setAccessPermissions(uint8_t perm); // Set the permissions of the descriptor.
void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks); // Set callbacks to be invoked for the descriptor. void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks); // Set callbacks to be invoked for the descriptor.
void setValue(uint8_t* data, size_t size); // Set the value of the descriptor as a pointer to data. void setValue(const uint8_t* data, size_t size); // Set the value of the descriptor as a pointer to data.
void setValue(std::string value); // Set the value of the descriptor as a data buffer. 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. std::string toString(); // Convert the descriptor to a string representation.
@ -97,5 +100,7 @@ public:
virtual void onRead(NimBLEDescriptor* pDescriptor); virtual void onRead(NimBLEDescriptor* pDescriptor);
virtual void onWrite(NimBLEDescriptor* pDescriptor); virtual void onWrite(NimBLEDescriptor* pDescriptor);
}; };
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */
#endif /* MAIN_NIMBLEDESCRIPTOR_H_ */ #endif /* MAIN_NIMBLEDESCRIPTOR_H_ */

View File

@ -13,6 +13,10 @@
*/ */
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#include "NimBLECharacteristic.h" #include "NimBLECharacteristic.h"
#include "NimBLEDescriptor.h" #include "NimBLEDescriptor.h"
@ -32,7 +36,7 @@ NimBLEDescriptor* NimBLEDescriptorMap::getByUUID(const char* uuid) {
* @param [in] UUID The UUID to look up the descriptor. * @param [in] UUID The UUID to look up the descriptor.
* @return The descriptor. If not present, then nullptr is returned. * @return The descriptor. If not present, then nullptr is returned.
*/ */
NimBLEDescriptor* NimBLEDescriptorMap::getByUUID(NimBLEUUID uuid) { NimBLEDescriptor* NimBLEDescriptorMap::getByUUID(const NimBLEUUID &uuid) {
for (auto &myPair : m_uuidMap) { for (auto &myPair : m_uuidMap) {
if (myPair.first->getUUID().equals(uuid)) { if (myPair.first->getUUID().equals(uuid)) {
return myPair.first; return myPair.first;
@ -71,7 +75,7 @@ void NimBLEDescriptorMap::setByUUID(const char* uuid, NimBLEDescriptor* pDescrip
* @param [in] characteristic The descriptor to cache. * @param [in] characteristic The descriptor to cache.
* @return N/A. * @return N/A.
*/ */
void NimBLEDescriptorMap::setByUUID(NimBLEUUID uuid, NimBLEDescriptor* pDescriptor) { void NimBLEDescriptorMap::setByUUID(const NimBLEUUID &uuid, NimBLEDescriptor* pDescriptor) {
m_uuidMap.insert(std::pair<NimBLEDescriptor*, std::string>(pDescriptor, uuid.toString())); m_uuidMap.insert(std::pair<NimBLEDescriptor*, std::string>(pDescriptor, uuid.toString()));
} // setByUUID } // setByUUID
@ -140,4 +144,6 @@ NimBLEDescriptor* NimBLEDescriptorMap::getNext() {
m_iterator++; m_iterator++;
return pRet; return pRet;
} // getNext } // getNext
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */

View File

@ -14,6 +14,7 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#include "NimBLEDevice.h" #include "NimBLEDevice.h"
#include "NimBLEUtils.h" #include "NimBLEUtils.h"
@ -39,35 +40,34 @@ static const char* LOG_TAG = "NimBLEDevice";
/** /**
* Singletons for the NimBLEDevice. * Singletons for the NimBLEDevice.
*/ */
bool NimBLEDevice_initialized = false; bool initialized = false;
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
NimBLEScan* NimBLEDevice::m_pScan = nullptr; NimBLEScan* NimBLEDevice::m_pScan = nullptr;
#endif
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
NimBLEServer* NimBLEDevice::m_pServer = nullptr; NimBLEServer* NimBLEDevice::m_pServer = nullptr;
#endif
uint32_t NimBLEDevice::m_passkey = 123456; uint32_t NimBLEDevice::m_passkey = 123456;
bool NimBLEDevice::m_synced = false; bool NimBLEDevice::m_synced = false;
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
NimBLEAdvertising* NimBLEDevice::m_bleAdvertising = nullptr; NimBLEAdvertising* NimBLEDevice::m_bleAdvertising = nullptr;
#endif
gap_event_handler NimBLEDevice::m_customGapHandler = nullptr; gap_event_handler NimBLEDevice::m_customGapHandler = nullptr;
ble_gap_event_listener NimBLEDevice::m_listener; ble_gap_event_listener NimBLEDevice::m_listener;
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
std::list <NimBLEClient*> NimBLEDevice::m_cList; std::list <NimBLEClient*> NimBLEDevice::m_cList;
#endif
std::list <NimBLEAddress> NimBLEDevice::m_ignoreList; std::list <NimBLEAddress> NimBLEDevice::m_ignoreList;
NimBLESecurityCallbacks* NimBLEDevice::m_securityCallbacks = nullptr; NimBLESecurityCallbacks* NimBLEDevice::m_securityCallbacks = nullptr;
//std::map<uint16_t, conn_status_t> BLEDevice::m_connectedClientsMap;
//gattc_event_handler BLEDevice::m_customGattcHandler = nullptr;
//gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
/** /**
* @brief Create a new instance of a server. * @brief Create a new instance of a server.
* @return A new instance of the server. * @return A new instance of the server.
*/ */
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
/* STATIC */ NimBLEServer* NimBLEDevice::createServer() { /* STATIC */ NimBLEServer* NimBLEDevice::createServer() {
/*#ifndef CONFIG_GATTS_ENABLE // Check that BLE GATTS is enabled in make menuconfig
NIMBLE_LOGE(LOG_TAG, "BLE GATTS is not enabled - CONFIG_GATTS_ENABLE not defined");
abort();
#endif // CONFIG_GATTS_ENABLE
*/
if(NimBLEDevice::m_pServer == nullptr) { if(NimBLEDevice::m_pServer == nullptr) {
NimBLEDevice::m_pServer = new NimBLEServer(); NimBLEDevice::m_pServer = new NimBLEServer();
ble_gatts_reset(); ble_gatts_reset();
@ -79,6 +79,17 @@ NimBLESecurityCallbacks* NimBLEDevice::m_securityCallbacks = nullptr;
} // createServer } // createServer
/**
* @brief Get the instance of the server.
* @return A pointer to the server instance.
*/
/* STATIC */ NimBLEServer* NimBLEDevice::getServer() {
return m_pServer;
} // getServer
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
NimBLEAdvertising* NimBLEDevice::getAdvertising() { NimBLEAdvertising* NimBLEDevice::getAdvertising() {
if(m_bleAdvertising == nullptr) { if(m_bleAdvertising == nullptr) {
m_bleAdvertising = new NimBLEAdvertising(); m_bleAdvertising = new NimBLEAdvertising();
@ -95,6 +106,7 @@ void NimBLEDevice::startAdvertising() {
void NimBLEDevice::stopAdvertising() { void NimBLEDevice::stopAdvertising() {
getAdvertising()->stop(); getAdvertising()->stop();
} // stopAdvertising } // stopAdvertising
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
/** /**
@ -102,19 +114,21 @@ void NimBLEDevice::stopAdvertising() {
* @return The scanning object reference. This is a singleton object. The caller should not * @return The scanning object reference. This is a singleton object. The caller should not
* try and release/delete it. * try and release/delete it.
*/ */
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
/* STATIC */ NimBLEScan* NimBLEDevice::getScan() { /* STATIC */ NimBLEScan* NimBLEDevice::getScan() {
if (m_pScan == nullptr) { if (m_pScan == nullptr) {
m_pScan = new NimBLEScan(); m_pScan = new NimBLEScan();
} }
return m_pScan; return m_pScan;
} // getScan } // getScan
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
/** /**
* @brief Creates a new client object and maintains a list of all client objects * @brief Creates a new client object and maintains a list of all client objects
* each client can connect to 1 peripheral device. * each client can connect to 1 peripheral device.
* @return A reference to the new client object. * @return A reference to the new client object.
*/ */
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
/* STATIC */ NimBLEClient* NimBLEDevice::createClient() { /* STATIC */ NimBLEClient* NimBLEDevice::createClient() {
if(m_cList.size() >= NIMBLE_MAX_CONNECTIONS) { if(m_cList.size() >= NIMBLE_MAX_CONNECTIONS) {
NIMBLE_LOGW("Number of clients exceeds Max connections. Max=(%d)", NIMBLE_LOGW("Number of clients exceeds Max connections. Max=(%d)",
@ -202,7 +216,7 @@ void NimBLEDevice::stopAdvertising() {
* @param [in] a NimBLEAddress of the peer to search for. * @param [in] a NimBLEAddress of the peer to search for.
* @return A reference pointer to the client with the peer address. * @return A reference pointer to the client with the peer address.
*/ */
/* STATIC */NimBLEClient* NimBLEDevice::getClientByPeerAddress(NimBLEAddress peer_addr) { /* STATIC */NimBLEClient* NimBLEDevice::getClientByPeerAddress(const NimBLEAddress &peer_addr) {
for(auto it = m_cList.cbegin(); it != m_cList.cend(); ++it) { for(auto it = m_cList.cbegin(); it != m_cList.cend(); ++it) {
if((*it)->getPeerAddress().equals(peer_addr)) { if((*it)->getPeerAddress().equals(peer_addr)) {
return (*it); return (*it);
@ -225,6 +239,8 @@ void NimBLEDevice::stopAdvertising() {
return nullptr; return nullptr;
} // getDisconnectedClient } // getDisconnectedClient
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
/** /**
* @brief Set the transmission power. * @brief Set the transmission power.
@ -340,9 +356,12 @@ void NimBLEDevice::stopAdvertising() {
m_synced = false; m_synced = false;
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
if(m_pScan != nullptr) { if(m_pScan != nullptr) {
m_pScan->onHostReset(); m_pScan->onHostReset();
} }
#endif
/* Not needed /* Not needed
if(m_pServer != nullptr) { if(m_pServer != nullptr) {
m_pServer->onHostReset(); m_pServer->onHostReset();
@ -352,9 +371,12 @@ void NimBLEDevice::stopAdvertising() {
(*it)->onHostReset(); (*it)->onHostReset();
} }
*/ */
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
if(m_bleAdvertising != nullptr) { if(m_bleAdvertising != nullptr) {
m_bleAdvertising->onHostReset(); m_bleAdvertising->onHostReset();
} }
#endif
NIMBLE_LOGC(LOG_TAG, "Resetting state; reason=%d, %s", reason, NIMBLE_LOGC(LOG_TAG, "Resetting state; reason=%d, %s", reason,
NimBLEUtils::returnCodeToString(reason)); NimBLEUtils::returnCodeToString(reason));
@ -379,15 +401,21 @@ void NimBLEDevice::stopAdvertising() {
m_synced = true; m_synced = true;
if(initialized) {
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
if(m_pScan != nullptr) { if(m_pScan != nullptr) {
// Restart scanning with the last values sent, allow to clear results. // Restart scanning with the last values sent, allow to clear results.
m_pScan->start(m_pScan->m_duration, m_pScan->m_scanCompleteCB); m_pScan->start(m_pScan->m_duration, m_pScan->m_scanCompleteCB);
} }
#endif
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
if(m_bleAdvertising != nullptr) { if(m_bleAdvertising != nullptr) {
// Restart advertisng, parameters should already be set. // Restart advertisng, parameters should already be set.
m_bleAdvertising->start(); m_bleAdvertising->start();
} }
#endif
}
} // onSync } // onSync
@ -408,10 +436,8 @@ void NimBLEDevice::stopAdvertising() {
* @brief Initialize the %BLE environment. * @brief Initialize the %BLE environment.
* @param deviceName The device name of the device. * @param deviceName The device name of the device.
*/ */
/* STATIC */ void NimBLEDevice::init(std::string deviceName) { /* STATIC */ void NimBLEDevice::init(const std::string &deviceName) {
if(!NimBLEDevice_initialized){ if(!initialized){
NimBLEDevice_initialized = true; // Set the initialization flag to ensure we are only initialized once.
int rc=0; int rc=0;
esp_err_t errRc = ESP_OK; esp_err_t errRc = ESP_OK;
@ -459,7 +485,8 @@ void NimBLEDevice::stopAdvertising() {
while(!m_synced){ while(!m_synced){
vTaskDelay(1 / portTICK_PERIOD_MS); vTaskDelay(1 / portTICK_PERIOD_MS);
} }
//vTaskDelay(200 / portTICK_PERIOD_MS); // Delay for 200 msecs as a workaround to an apparent Arduino environment issue.
initialized = true; // Set the initialization flag to ensure we are only initialized once.
} // init } // init
@ -476,7 +503,8 @@ void NimBLEDevice::stopAdvertising() {
NIMBLE_LOGE(LOG_TAG, "esp_nimble_hci_and_controller_deinit() failed with error: %d", ret); NIMBLE_LOGE(LOG_TAG, "esp_nimble_hci_and_controller_deinit() failed with error: %d", ret);
} }
NimBLEDevice_initialized = false; initialized = false;
m_synced = false;
} }
} // deinit } // deinit
@ -485,7 +513,7 @@ void NimBLEDevice::stopAdvertising() {
* @brief Check if the initialization is complete. * @brief Check if the initialization is complete.
*/ */
bool NimBLEDevice::getInitialized() { bool NimBLEDevice::getInitialized() {
return NimBLEDevice_initialized; return initialized;
} // getInitialized } // getInitialized
@ -610,7 +638,7 @@ void NimBLEDevice::setSecurityCallbacks(NimBLESecurityCallbacks* callbacks) {
* @brief Check if the device address is on our ignore list. * @brief Check if the device address is on our ignore list.
* @return True if ignoring. * @return True if ignoring.
*/ */
/*STATIC*/ bool NimBLEDevice::isIgnored(NimBLEAddress address) { /*STATIC*/ bool NimBLEDevice::isIgnored(const NimBLEAddress &address) {
for(auto &it : m_ignoreList) { for(auto &it : m_ignoreList) {
if(it.equals(address)){ if(it.equals(address)){
return true; return true;
@ -625,7 +653,7 @@ void NimBLEDevice::setSecurityCallbacks(NimBLESecurityCallbacks* callbacks) {
* @brief Add a device to the ignore list. * @brief Add a device to the ignore list.
* @param Address of the device we want to ignore. * @param Address of the device we want to ignore.
*/ */
/*STATIC*/ void NimBLEDevice::addIgnored(NimBLEAddress address) { /*STATIC*/ void NimBLEDevice::addIgnored(const NimBLEAddress &address) {
m_ignoreList.push_back(address); m_ignoreList.push_back(address);
} }
@ -634,7 +662,7 @@ void NimBLEDevice::setSecurityCallbacks(NimBLESecurityCallbacks* callbacks) {
* @brief Remove a device from the ignore list. * @brief Remove a device from the ignore list.
* @param Address of the device we want to remove from the list. * @param Address of the device we want to remove from the list.
*/ */
/*STATIC*/void NimBLEDevice::removeIgnored(NimBLEAddress address) { /*STATIC*/void NimBLEDevice::removeIgnored(const NimBLEAddress &address) {
for(auto it = m_ignoreList.begin(); it != m_ignoreList.end(); ++it) { for(auto it = m_ignoreList.begin(); it != m_ignoreList.end(); ++it) {
if((*it).equals(address)){ if((*it).equals(address)){
m_ignoreList.erase(it); m_ignoreList.erase(it);
@ -659,20 +687,4 @@ void NimBLEDevice::setCustomGapHandler(gap_event_handler handler) {
} // setCustomGapHandler } // setCustomGapHandler
/**
* @brief Backward compatibility for bluedroid gatt events.
* NimBLe does not send GATT events
*/
/*
void BLEDevice::setCustomGattcHandler(gattc_event_handler handler) {
setCustomGapHandler(handler);
}
void BLEDevice::setCustomGattsHandler(gatts_event_handler handler) {
setCustomGapHandler(handler);
}
*/
/**********************************************************/
#endif // CONFIG_BT_ENABLED #endif // CONFIG_BT_ENABLED

View File

@ -17,11 +17,27 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
#include "NimBLEScan.h" #include "NimBLEScan.h"
#include "NimBLEUtils.h" #endif
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
#include "NimBLEAdvertising.h"
#endif
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#include "NimBLEClient.h" #include "NimBLEClient.h"
#endif
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#include "NimBLEServer.h" #include "NimBLEServer.h"
#endif
#include "NimBLEUtils.h"
#include "NimBLESecurity.h" #include "NimBLESecurity.h"
#include "NimBLEAddress.h"
#include "esp_bt.h" #include "esp_bt.h"
@ -69,22 +85,26 @@
* @brief BLE functions. * @brief BLE functions.
*/ */
typedef int (*gap_event_handler)(ble_gap_event *event, void *arg); typedef int (*gap_event_handler)(ble_gap_event *event, void *arg);
//typedef void (*gattc_event_handler)(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t* param);
//typedef void (*gatts_event_handler)(esp_gatts_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gatts_cb_param_t* param);
extern "C" void ble_store_config_init(void); extern "C" void ble_store_config_init(void);
class NimBLEDevice { class NimBLEDevice {
public: public:
static void init(std::string deviceName); // Initialize the local BLE environment. static void init(const std::string &deviceName);
static void deinit(); static void deinit();
static bool getInitialized(); static bool getInitialized();
static NimBLEAddress getAddress(); static NimBLEAddress getAddress();
static std::string toString(); static std::string toString();
static NimBLEScan* getScan(); // Get the scan object
static NimBLEClient* createClient(); #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
static NimBLEScan* getScan();
#endif
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
static NimBLEServer* createServer(); static NimBLEServer* createServer();
static bool deleteClient(NimBLEClient* pClient); static NimBLEServer* getServer();
#endif
static void setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT); static void setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT);
static int getPower(esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT); static int getPower(esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT);
static void setCustomGapHandler(gap_event_handler handler); static void setCustomGapHandler(gap_event_handler handler);
@ -98,39 +118,69 @@ public:
static void setSecurityCallbacks(NimBLESecurityCallbacks* pCallbacks); static void setSecurityCallbacks(NimBLESecurityCallbacks* pCallbacks);
static int setMTU(uint16_t mtu); static int setMTU(uint16_t mtu);
static uint16_t getMTU(); static uint16_t getMTU();
static bool isIgnored(NimBLEAddress address); static bool isIgnored(const NimBLEAddress &address);
static void addIgnored(NimBLEAddress address); static void addIgnored(const NimBLEAddress &address);
static void removeIgnored(NimBLEAddress address); static void removeIgnored(const NimBLEAddress &address);
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
static NimBLEAdvertising* getAdvertising(); static NimBLEAdvertising* getAdvertising();
static void startAdvertising(); static void startAdvertising();
static void stopAdvertising(); static void stopAdvertising();
#endif
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
static NimBLEClient* createClient();
static bool deleteClient(NimBLEClient* pClient);
static NimBLEClient* getClientByID(uint16_t conn_id); static NimBLEClient* getClientByID(uint16_t conn_id);
static NimBLEClient* getClientByPeerAddress(NimBLEAddress peer_addr); static NimBLEClient* getClientByPeerAddress(const NimBLEAddress &peer_addr);
static NimBLEClient* getDisconnectedClient(); static NimBLEClient* getDisconnectedClient();
static size_t getClientListSize(); static size_t getClientListSize();
static std::list<NimBLEClient*>* getClientList(); static std::list<NimBLEClient*>* getClientList();
#endif
private: private:
friend class NimBLEServer; #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
friend class NimBLEClient; friend class NimBLEClient;
#endif
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
friend class NimBLEScan; friend class NimBLEScan;
friend class NimBLEAdvertising; #endif
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
friend class NimBLEServer;
friend class NimBLECharacteristic; friend class NimBLECharacteristic;
#endif
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
friend class NimBLEAdvertising;
#endif
static void onReset(int reason); static void onReset(int reason);
static void onSync(void); static void onSync(void);
static void host_task(void *param); static void host_task(void *param);
static int startSecurity(uint16_t conn_id); static int startSecurity(uint16_t conn_id);
static bool m_synced; static bool m_synced;
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
static NimBLEScan* m_pScan; static NimBLEScan* m_pScan;
#endif
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
static NimBLEServer* m_pServer; static NimBLEServer* m_pServer;
#endif
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
static NimBLEAdvertising* m_bleAdvertising; static NimBLEAdvertising* m_bleAdvertising;
static ble_gap_event_listener m_listener; #endif
static uint32_t m_passkey;
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
static std::list <NimBLEClient*> m_cList; static std::list <NimBLEClient*> m_cList;
#endif
static std::list <NimBLEAddress> m_ignoreList; static std::list <NimBLEAddress> m_ignoreList;
static NimBLESecurityCallbacks* m_securityCallbacks; static NimBLESecurityCallbacks* m_securityCallbacks;
static uint32_t m_passkey;
static ble_gap_event_listener m_listener;
public: public:
static gap_event_handler m_customGapHandler; static gap_event_handler m_customGapHandler;

View File

@ -116,7 +116,7 @@ std::string NimBLEEddystoneTLM::toString() {
/** /**
* Set the raw data for the beacon record. * Set the raw data for the beacon record.
*/ */
void NimBLEEddystoneTLM::setData(std::string data) { void NimBLEEddystoneTLM::setData(const std::string &data) {
if (data.length() != sizeof(m_eddystoneData)) { if (data.length() != sizeof(m_eddystoneData)) {
NIMBLE_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and expected %d", NIMBLE_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and expected %d",
data.length(), sizeof(m_eddystoneData)); data.length(), sizeof(m_eddystoneData));
@ -125,7 +125,7 @@ void NimBLEEddystoneTLM::setData(std::string data) {
memcpy(&m_eddystoneData, data.data(), data.length()); memcpy(&m_eddystoneData, data.data(), data.length());
} // setData } // setData
void NimBLEEddystoneTLM::setUUID(NimBLEUUID l_uuid) { void NimBLEEddystoneTLM::setUUID(const NimBLEUUID &l_uuid) {
beaconUUID = l_uuid.getNative()->u16.value; beaconUUID = l_uuid.getNative()->u16.value;
} // setUUID } // setUUID

View File

@ -36,8 +36,8 @@ public:
uint32_t getCount(); uint32_t getCount();
uint32_t getTime(); uint32_t getTime();
std::string toString(); std::string toString();
void setData(std::string data); void setData(const std::string &data);
void setUUID(NimBLEUUID l_uuid); void setUUID(const NimBLEUUID &l_uuid);
void setVersion(uint8_t version); void setVersion(uint8_t version);
void setVolt(uint16_t volt); void setVolt(uint16_t volt);
void setTemp(float temp); void setTemp(float temp);

View File

@ -125,7 +125,7 @@ std::string NimBLEEddystoneURL::getDecodedURL() {
/** /**
* Set the raw data for the beacon record. * Set the raw data for the beacon record.
*/ */
void NimBLEEddystoneURL::setData(std::string data) { void NimBLEEddystoneURL::setData(const std::string &data) {
if (data.length() > sizeof(m_eddystoneData)) { if (data.length() > sizeof(m_eddystoneData)) {
NIMBLE_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and max expected %d", NIMBLE_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and max expected %d",
data.length(), sizeof(m_eddystoneData)); data.length(), sizeof(m_eddystoneData));
@ -136,7 +136,7 @@ void NimBLEEddystoneURL::setData(std::string data) {
lengthURL = data.length() - (sizeof(m_eddystoneData) - sizeof(m_eddystoneData.url)); lengthURL = data.length() - (sizeof(m_eddystoneData) - sizeof(m_eddystoneData.url));
} // setData } // setData
void NimBLEEddystoneURL::setUUID(NimBLEUUID l_uuid) { void NimBLEEddystoneURL::setUUID(const NimBLEUUID &l_uuid) {
beaconUUID = l_uuid.getNative()->u16.value; beaconUUID = l_uuid.getNative()->u16.value;
} // setUUID } // setUUID
@ -144,7 +144,7 @@ void NimBLEEddystoneURL::setPower(int8_t advertisedTxPower) {
m_eddystoneData.advertisedTxPower = advertisedTxPower; m_eddystoneData.advertisedTxPower = advertisedTxPower;
} // setPower } // setPower
void NimBLEEddystoneURL::setURL(std::string url) { void NimBLEEddystoneURL::setURL(const std::string &url) {
if (url.length() > sizeof(m_eddystoneData.url)) { if (url.length() > sizeof(m_eddystoneData.url)) {
NIMBLE_LOGE(LOG_TAG, "Unable to set the url ... length passed in was %d and max expected %d", NIMBLE_LOGE(LOG_TAG, "Unable to set the url ... length passed in was %d and max expected %d",
url.length(), sizeof(m_eddystoneData.url)); url.length(), sizeof(m_eddystoneData.url));

View File

@ -33,10 +33,10 @@ public:
int8_t getPower(); int8_t getPower();
std::string getURL(); std::string getURL();
std::string getDecodedURL(); std::string getDecodedURL();
void setData(std::string data); void setData(const std::string &data);
void setUUID(NimBLEUUID l_uuid); void setUUID(const NimBLEUUID &l_uuid);
void setPower(int8_t advertisedTxPower); void setPower(int8_t advertisedTxPower);
void setURL(std::string url); void setURL(const std::string &url);
private: private:
uint16_t beaconUUID; uint16_t beaconUUID;

View File

@ -15,6 +15,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#include "NimBLERemoteCharacteristic.h" #include "NimBLERemoteCharacteristic.h"
#include "NimBLEUtils.h" #include "NimBLEUtils.h"
#include "NimBLELog.h" #include "NimBLELog.h"
@ -32,7 +35,9 @@ static const char* LOG_TAG = "NimBLERemoteCharacteristic";
* ble_uuid_any_t uuid; * ble_uuid_any_t uuid;
* }; * };
*/ */
NimBLERemoteCharacteristic::NimBLERemoteCharacteristic(NimBLERemoteService *pRemoteService, const struct ble_gatt_chr *chr) { NimBLERemoteCharacteristic::NimBLERemoteCharacteristic(NimBLERemoteService *pRemoteService,
const struct ble_gatt_chr *chr)
{
switch (chr->uuid.u.type) { switch (chr->uuid.u.type) {
case BLE_UUID_TYPE_16: case BLE_UUID_TYPE_16:
@ -53,6 +58,8 @@ static const char* LOG_TAG = "NimBLERemoteCharacteristic";
m_charProp = chr->properties; m_charProp = chr->properties;
m_pRemoteService = pRemoteService; m_pRemoteService = pRemoteService;
m_notifyCallback = nullptr; m_notifyCallback = nullptr;
m_rawData = nullptr;
m_dataLen = 0;
} // NimBLERemoteCharacteristic } // NimBLERemoteCharacteristic
@ -61,7 +68,9 @@ static const char* LOG_TAG = "NimBLERemoteCharacteristic";
*/ */
NimBLERemoteCharacteristic::~NimBLERemoteCharacteristic() { NimBLERemoteCharacteristic::~NimBLERemoteCharacteristic() {
removeDescriptors(); // Release resources for any descriptor information we may have allocated. removeDescriptors(); // Release resources for any descriptor information we may have allocated.
if(m_rawData != nullptr) free(m_rawData); if(m_rawData != nullptr) {
free(m_rawData);
}
} // ~NimBLERemoteCharacteristic } // ~NimBLERemoteCharacteristic
/* /*
@ -138,9 +147,12 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
const struct ble_gatt_dsc *dsc, const struct ble_gatt_dsc *dsc,
void *arg) void *arg)
{ {
NIMBLE_LOGD(LOG_TAG,"Descriptor Discovered >> status: %d handle: %d", error->status, conn_handle); NIMBLE_LOGD(LOG_TAG,"Descriptor Discovered >> status: %d handle: %d",
error->status, (error->status == 0) ? dsc->handle : -1);
NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)arg; disc_filter_t *filter = (disc_filter_t*)arg;
NimBLEUUID *uuid_filter = (NimBLEUUID*)filter->uuid;
NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)filter->attribute;
int rc=0; int rc=0;
// Make sure the discovery is for this device // Make sure the discovery is for this device
@ -150,73 +162,149 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
switch (error->status) { switch (error->status) {
case 0: { case 0: {
// Found a descriptor - add it to the map if(dsc->uuid.u.type == BLE_UUID_TYPE_16 && dsc->uuid.u16.value == uint16_t(0x2803)) {
NimBLERemoteDescriptor* pNewRemoteDescriptor = new NimBLERemoteDescriptor(characteristic, dsc); NIMBLE_LOGD(LOG_TAG,"Descriptor NOT found - end of Characteristic definintion");
characteristic->m_descriptorMap.insert(std::pair<std::string, NimBLERemoteDescriptor*>(pNewRemoteDescriptor->getUUID().toString(), pNewRemoteDescriptor)); rc = BLE_HS_EDONE;
break; break;
} }
case BLE_HS_EDONE:{ if(uuid_filter != nullptr) {
/* All descriptors in this characteristic discovered; */ if(ble_uuid_cmp(&uuid_filter->getNative()->u, &dsc->uuid.u) != 0) {
characteristic->m_semaphoreGetDescEvt.give(0); return 0;
rc = 0; } else {
NIMBLE_LOGD(LOG_TAG,"Descriptor Found");
rc = BLE_HS_EDONE;
}
}
// Found a descriptor - add it to the vector
NimBLERemoteDescriptor* pNewRemoteDescriptor = new NimBLERemoteDescriptor(characteristic, dsc);
characteristic->m_descriptorVector.push_back(pNewRemoteDescriptor);
break; break;
} }
default: default:
rc = error->status; rc = error->status;
break; break;
} }
if (rc != 0) {
/** If rc == BLE_HS_EDONE, release the semaphore with a success error code and stop the discovery process.
* Else if rc == 0, just return 0 to continue the discovery until we get BLE_HS_EDONE.
* If we get any other error code tell the application to abort by returning non-zero in the semaphore rc.
*/
if (rc == BLE_HS_EDONE) {
characteristic->m_semaphoreGetDescEvt.give(0);
} else if(rc != 0) {
/* Error; abort discovery. */ /* Error; abort discovery. */
// pass non-zero to semaphore on error to indicate an error finding descriptors // pass error code to semaphore waiting
characteristic->m_semaphoreGetDescEvt.give(1); characteristic->m_semaphoreGetDescEvt.give(rc);
} }
NIMBLE_LOGD(LOG_TAG,"<< Descriptor Discovered. status: %d", rc); NIMBLE_LOGD(LOG_TAG,"<< Descriptor Discovered. status: %d", rc);
return rc; return rc;
} }
/** /**
* @brief Populate the descriptors (if any) for this characteristic. * @brief Populate the descriptors (if any) for this characteristic.
* @param [in] the end handle of the characteristic, or the service, whichever comes first. * @param [in] the end handle of the characteristic, or the service, whichever comes first.
*/ */
bool NimBLERemoteCharacteristic::retrieveDescriptors(uint16_t endHdl) { bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filter) {
NIMBLE_LOGD(LOG_TAG, ">> retrieveDescriptors() for characteristic: %s", getUUID().toString().c_str()); NIMBLE_LOGD(LOG_TAG, ">> retrieveDescriptors() for characteristic: %s", getUUID().toString().c_str());
int rc = 0; int rc = 0;
//removeDescriptors(); // Remove any existing descriptors. disc_filter_t filter;
filter.uuid = uuid_filter;
filter.attribute = this;
m_semaphoreGetDescEvt.take("retrieveDescriptors"); m_semaphoreGetDescEvt.take("retrieveDescriptors");
rc = ble_gattc_disc_all_dscs(getRemoteService()->getClient()->getConnId(), rc = ble_gattc_disc_all_dscs(getRemoteService()->getClient()->getConnId(),
m_handle, m_handle,
endHdl, getRemoteService()->getEndHandle(),
NimBLERemoteCharacteristic::descriptorDiscCB, NimBLERemoteCharacteristic::descriptorDiscCB,
this); &filter);
if (rc != 0) { if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_chrs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_chrs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
m_semaphoreGetDescEvt.give(); m_semaphoreGetDescEvt.give();
return false; return false;
} }
if(m_semaphoreGetDescEvt.wait("retrieveCharacteristics") != 0) { if(m_semaphoreGetDescEvt.wait("retrieveDescriptors") != 0) {
// if there was an error release the resources
//removeDescriptors();
return false; return false;
} }
return true; return true;
NIMBLE_LOGD(LOG_TAG, "<< retrieveDescriptors(): Found %d descriptors.", m_descriptorMap.size()); NIMBLE_LOGD(LOG_TAG, "<< retrieveDescriptors(): Found %d descriptors.", m_descriptorVector.size());
} // getDescriptors } // getDescriptors
/** /**
* @brief Retrieve the map of descriptors keyed by UUID. * @brief Get the descriptor instance with the given UUID that belongs to this characteristic.
* @param [in] uuid The UUID of the descriptor to find.
* @return The Remote descriptor (if present) or null if not present.
*/ */
std::map<std::string, NimBLERemoteDescriptor*>* NimBLERemoteCharacteristic::getDescriptors() { NimBLERemoteDescriptor* NimBLERemoteCharacteristic::getDescriptor(const NimBLEUUID &uuid) {
return &m_descriptorMap; NIMBLE_LOGD(LOG_TAG, ">> getDescriptor: uuid: %s", uuid.toString().c_str());
for(auto &it: m_descriptorVector) {
if(it->getUUID() == uuid) {
NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: found");
return it;
}
}
size_t prev_size = m_descriptorVector.size();
if(retrieveDescriptors(&uuid)) {
if(m_descriptorVector.size() > prev_size) {
return m_descriptorVector.back();
}
}
NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: Not found");
return nullptr;
} // getDescriptor
/**
* @Get a pointer to the vector of found descriptors.
* @param [in] bool value to indicate if the current vector should be cleared and
* subsequently all descriptors for this characteristic retrieved from the peripheral.
* If false the vector will be returned with the currently stored descriptors,
* if the vector is empty it will retrieve all descriptors for this characteristic
* from the peripheral.
* @return a pointer to the vector of descriptors for this characteristic.
*/
std::vector<NimBLERemoteDescriptor*>* NimBLERemoteCharacteristic::getDescriptors(bool refresh) {
if(refresh) {
removeDescriptors();
}
if(m_descriptorVector.empty()) {
if (!retrieveDescriptors()) {
NIMBLE_LOGE(LOG_TAG, "Error: Failed to get descriptors");
}
else{
NIMBLE_LOGI(LOG_TAG, "Found %d descriptor(s)", m_descriptorVector.size());
}
}
return &m_descriptorVector;
} // getDescriptors } // getDescriptors
/**
* @brief Get iterator to the beginning of the vector of remote descriptor pointers.
* @return An iterator to the beginning of the vector of remote descriptor pointers.
*/
std::vector<NimBLERemoteDescriptor*>::iterator NimBLERemoteCharacteristic::begin() {
return m_descriptorVector.begin();
}
/**
* @brief Get iterator to the end of the vector of remote descriptor pointers.
* @return An iterator to the end of the vector of remote descriptor pointers.
*/
std::vector<NimBLERemoteDescriptor*>::iterator NimBLERemoteCharacteristic::end() {
return m_descriptorVector.end();
}
/** /**
* @brief Get the handle for this characteristic. * @brief Get the handle for this characteristic.
* @return The handle for this characteristic. * @return The handle for this characteristic.
@ -234,25 +322,6 @@ uint16_t NimBLERemoteCharacteristic::getDefHandle() {
} // getDefHandle } // getDefHandle
/**
* @brief Get the descriptor instance with the given UUID that belongs to this characteristic.
* @param [in] uuid The UUID of the descriptor to find.
* @return The Remote descriptor (if present) or null if not present.
*/
NimBLERemoteDescriptor* NimBLERemoteCharacteristic::getDescriptor(NimBLEUUID uuid) {
NIMBLE_LOGD(LOG_TAG, ">> getDescriptor: uuid: %s", uuid.toString().c_str());
std::string v = uuid.toString();
for (auto &myPair : m_descriptorMap) {
if (myPair.first == v) {
NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: found");
return myPair.second;
}
}
NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: Not found");
return nullptr;
} // getDescriptor
/** /**
* @brief Get the remote service associated with this characteristic. * @brief Get the remote service associated with this characteristic.
* @return The remote service associated with this characteristic. * @return The remote service associated with this characteristic.
@ -315,10 +384,13 @@ uint8_t NimBLERemoteCharacteristic::readUInt8() {
* @return The value of the remote characteristic. * @return The value of the remote characteristic.
*/ */
std::string NimBLERemoteCharacteristic::readValue() { std::string NimBLERemoteCharacteristic::readValue() {
NIMBLE_LOGD(LOG_TAG, ">> readValue(): uuid: %s, handle: %d 0x%.2x", getUUID().toString().c_str(), getHandle(), getHandle()); NIMBLE_LOGD(LOG_TAG, ">> readValue(): uuid: %s, handle: %d 0x%.2x",
getUUID().toString().c_str(), getHandle(), getHandle());
int rc = 0; int rc = 0;
int retryCount = 1; int retryCount = 1;
// Clear the value before reading.
m_value = "";
NimBLEClient* pClient = getRemoteService()->getClient(); NimBLEClient* pClient = getRemoteService()->getClient();
@ -331,24 +403,27 @@ std::string NimBLERemoteCharacteristic::readValue() {
do { do {
m_semaphoreReadCharEvt.take("readValue"); m_semaphoreReadCharEvt.take("readValue");
rc = ble_gattc_read(pClient->getConnId(), m_handle, rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
NimBLERemoteCharacteristic::onReadCB, this); NimBLERemoteCharacteristic::onReadCB,
this);
// long read experiment
/* rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
NimBLERemoteCharacteristic::onReadCB, this);
*/
if (rc != 0) { if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Error: Failed to read characteristic; rc=%d", rc); NIMBLE_LOGE(LOG_TAG, "Error: Failed to read characteristic; rc=%d, %s",
m_semaphoreReadCharEvt.give(); rc, NimBLEUtils::returnCodeToString(rc));
m_semaphoreReadCharEvt.give(0);
return ""; return "";
} }
rc = m_semaphoreReadCharEvt.wait("readValue"); rc = m_semaphoreReadCharEvt.wait("readValue");
switch(rc){ switch(rc){
case 0: case 0:
case BLE_HS_EDONE:
rc = 0;
break;
// Characteristic is not long-readable, return with what we have.
case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
NIMBLE_LOGI(LOG_TAG, "Attribute not long");
rc = 0;
break; break;
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN): case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR): case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR):
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC): case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC):
@ -361,7 +436,7 @@ std::string NimBLERemoteCharacteristic::readValue() {
} while(rc != 0 && retryCount--); } while(rc != 0 && retryCount--);
NIMBLE_LOGD(LOG_TAG, "<< readValue(): length: %d", m_value.length()); NIMBLE_LOGD(LOG_TAG, "<< readValue(): length: %d", m_value.length());
return (rc == 0) ? m_value : ""; return m_value;
} // readValue } // readValue
@ -374,36 +449,25 @@ int NimBLERemoteCharacteristic::onReadCB(uint16_t conn_handle,
struct ble_gatt_attr *attr, void *arg) struct ble_gatt_attr *attr, void *arg)
{ {
NimBLERemoteCharacteristic* characteristic = (NimBLERemoteCharacteristic*)arg; NimBLERemoteCharacteristic* characteristic = (NimBLERemoteCharacteristic*)arg;
uint16_t conn_id = characteristic->getRemoteService()->getClient()->getConnId();
// Make sure the discovery is for this device // Make sure the read is for this client
if(characteristic->getRemoteService()->getClient()->getConnId() != conn_handle){ if(conn_id != conn_handle) {
return 0; return 0;
} }
NIMBLE_LOGI(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle); NIMBLE_LOGI(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
// long read experiment
/* if(attr && (attr->om->om_len >= (ble_att_mtu(characteristic->getRemoteService()->getClient()->getConnId()) - 1))){
return 0;
}
*/
if(characteristic->m_rawData != nullptr) {
free(characteristic->m_rawData);
}
if(error->status == 0) { if(error->status == 0) {
characteristic->m_value = std::string((char*) attr->om->om_data, attr->om->om_len); if(attr) {
characteristic->m_rawData = (uint8_t*) calloc(attr->om->om_len, sizeof(uint8_t)); NIMBLE_LOGD(LOG_TAG, "Got %d bytes", attr->om->om_len);
memcpy(characteristic->m_rawData, attr->om->om_data, attr->om->om_len);
characteristic->m_semaphoreReadCharEvt.give(0);
} else {
characteristic->m_rawData = nullptr;
characteristic->m_value = "";
characteristic->m_semaphoreReadCharEvt.give(error->status);
}
// characteristic->m_semaphoreReadCharEvt.give(error->status); characteristic->m_value += std::string((char*) attr->om->om_data, attr->om->om_len);
return 0; //1 return 0;
}
}
// Read complete release semaphore and let the app can continue.
characteristic->m_semaphoreReadCharEvt.give(error->status);
return 0;
} }
@ -443,19 +507,18 @@ bool NimBLERemoteCharacteristic::registerForNotify(notify_callback notifyCallbac
/** /**
* @brief Delete the descriptors in the descriptor map. * @brief Delete the descriptors in the descriptor vector.
* We maintain a map called m_descriptorMap that contains pointers to BLERemoteDescriptors * We maintain a vector called m_descriptorVector that contains pointers to BLERemoteDescriptors
* object references. Since we allocated these in this class, we are also responsible for deleteing * object references. Since we allocated these in this class, we are also responsible for deleteing
* them. This method does just that. * them. This method does just that.
* @return N/A. * @return N/A.
*/ */
void NimBLERemoteCharacteristic::removeDescriptors() { void NimBLERemoteCharacteristic::removeDescriptors() {
// Iterate through all the descriptors releasing their storage and erasing them from the map. // Iterate through all the descriptors releasing their storage and erasing them from the vector.
for (auto &myPair : m_descriptorMap) { for(auto &it: m_descriptorVector) {
m_descriptorMap.erase(myPair.first); delete it;
delete myPair.second;
} }
m_descriptorMap.clear(); // Technically not neeeded, but just to be sure. m_descriptorVector.clear();
} // removeCharacteristics } // removeCharacteristics
@ -477,8 +540,8 @@ std::string NimBLERemoteCharacteristic::toString() {
snprintf(val, sizeof(val), "%02x", m_charProp); snprintf(val, sizeof(val), "%02x", m_charProp);
res += val; res += val;
for (auto &myPair : m_descriptorMap) { for(auto &it: m_descriptorVector) {
res += "\n" + myPair.second->toString(); res += "\n" + it->toString();
} }
return res; return res;
@ -491,7 +554,7 @@ std::string NimBLERemoteCharacteristic::toString() {
* @param [in] response Do we expect a response? * @param [in] response Do we expect a response?
* @return false if not connected or cant perform write for some reason. * @return false if not connected or cant perform write for some reason.
*/ */
bool NimBLERemoteCharacteristic::writeValue(std::string newValue, bool response) { bool NimBLERemoteCharacteristic::writeValue(const std::string &newValue, bool response) {
return writeValue((uint8_t*)newValue.c_str(), strlen(newValue.c_str()), response); return writeValue((uint8_t*)newValue.c_str(), strlen(newValue.c_str()), response);
} // writeValue } // writeValue
@ -516,14 +579,14 @@ bool NimBLERemoteCharacteristic::writeValue(uint8_t newValue, bool response) {
* @param [in] response Whether we require a response from the write. * @param [in] response Whether we require a response from the write.
* @return false if not connected or cant perform write for some reason. * @return false if not connected or cant perform write for some reason.
*/ */
bool NimBLERemoteCharacteristic::writeValue(uint8_t* data, size_t length, bool response) { bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length, bool response) {
NIMBLE_LOGD(LOG_TAG, ">> writeValue(), length: %d", length); NIMBLE_LOGD(LOG_TAG, ">> writeValue(), length: %d", length);
NimBLEClient* pClient = getRemoteService()->getClient(); NimBLEClient* pClient = getRemoteService()->getClient();
int rc = 0; int rc = 0;
int retryCount = 1; int retryCount = 1;
// uint16_t mtu; uint16_t mtu;
// Check to see that we are connected. // Check to see that we are connected.
if (!pClient->isConnected()) { if (!pClient->isConnected()) {
@ -531,29 +594,30 @@ bool NimBLERemoteCharacteristic::writeValue(uint8_t* data, size_t length, bool r
return false; return false;
} }
// mtu = ble_att_mtu(pClient->getConnId()) - 3; mtu = ble_att_mtu(pClient->getConnId()) - 3;
if(/*!length > mtu &&*/ !response) { // Check if the data length is longer than we can write in 1 connection event.
// If so we must do a long write which requires a response.
if(length <= mtu && !response) {
rc = ble_gattc_write_no_rsp_flat(pClient->getConnId(), m_handle, data, length); rc = ble_gattc_write_no_rsp_flat(pClient->getConnId(), m_handle, data, length);
return (rc==0); return (rc==0);
} }
do { do {
m_semaphoreWriteCharEvt.take("writeValue"); m_semaphoreWriteCharEvt.take("writeValue");
// long write experiment
/* if(length > mtu) { if(length > mtu) {
NIMBLE_LOGD(LOG_TAG,"long write"); NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length);
os_mbuf *om = ble_hs_mbuf_from_flat(data, length); os_mbuf *om = ble_hs_mbuf_from_flat(data, length);
rc = ble_gattc_write_long(pClient->getConnId(), m_handle, 0, om, rc = ble_gattc_write_long(pClient->getConnId(), m_handle, 0, om,
NimBLERemoteCharacteristic::onWriteCB, NimBLERemoteCharacteristic::onWriteCB,
this); this);
} else { } else {
*/
rc = ble_gattc_write_flat(pClient->getConnId(), m_handle, rc = ble_gattc_write_flat(pClient->getConnId(), m_handle,
data, length, data, length,
NimBLERemoteCharacteristic::onWriteCB, NimBLERemoteCharacteristic::onWriteCB,
this); this);
// } }
if (rc != 0) { if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Error: Failed to write characteristic; rc=%d", rc); NIMBLE_LOGE(LOG_TAG, "Error: Failed to write characteristic; rc=%d", rc);
m_semaphoreWriteCharEvt.give(); m_semaphoreWriteCharEvt.give();
@ -564,6 +628,13 @@ bool NimBLERemoteCharacteristic::writeValue(uint8_t* data, size_t length, bool r
switch(rc){ switch(rc){
case 0: case 0:
case BLE_HS_EDONE:
rc = 0;
break;
case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
NIMBLE_LOGE(LOG_TAG, "Long write not supported by peer; Truncating length to %d", mtu);
retryCount++;
length = mtu;
break; break;
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN): case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
@ -599,13 +670,7 @@ int NimBLERemoteCharacteristic::onWriteCB(uint16_t conn_handle,
NIMBLE_LOGI(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle); NIMBLE_LOGI(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle);
if (error->status == 0) {
characteristic->m_semaphoreWriteCharEvt.give(0);
} else {
characteristic->m_semaphoreWriteCharEvt.give(error->status); characteristic->m_semaphoreWriteCharEvt.give(error->status);
}
return 0; return 0;
} }
@ -613,19 +678,42 @@ int NimBLERemoteCharacteristic::onWriteCB(uint16_t conn_handle,
/** /**
* @brief Read raw data from remote characteristic as hex bytes * @brief Read raw data from remote characteristic as hex bytes
* @return return pointer data read * @return uint8_t pointer to the data read.
*/ */
uint8_t* NimBLERemoteCharacteristic::readRawData() { uint8_t* NimBLERemoteCharacteristic::readRawData() {
if(m_rawData != nullptr) {
free(m_rawData);
m_rawData = nullptr;
}
m_dataLen = m_value.length();
// If we have data copy it to rawData
if(m_dataLen) {
m_rawData = (uint8_t*) calloc(m_dataLen, sizeof(uint8_t));
memcpy(m_rawData, m_value.data(), m_dataLen);
}
return m_rawData; return m_rawData;
} }
/**
* @brief Get the length of the data read from the remote characteristic.
* @return size_t length of the data in bytes.
*/
size_t NimBLERemoteCharacteristic::getDataLength() {
return m_value.length();
}
void NimBLERemoteCharacteristic::releaseSemaphores() { void NimBLERemoteCharacteristic::releaseSemaphores() {
for (auto &dPair : m_descriptorMap) { for (auto &it: m_descriptorVector) {
dPair.second->releaseSemaphores(); it->releaseSemaphores();
} }
m_semaphoreWriteCharEvt.give(1); m_semaphoreWriteCharEvt.give(1);
m_semaphoreGetDescEvt.give(1); m_semaphoreGetDescEvt.give(1);
m_semaphoreReadCharEvt.give(1); m_semaphoreReadCharEvt.give(1);
} }
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */

View File

@ -17,19 +17,20 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
//#include "NimBLEUUID.h" #include "nimconfig.h"
//#include "FreeRTOS.h" #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#include "NimBLERemoteService.h" #include "NimBLERemoteService.h"
#include "NimBLERemoteDescriptor.h" #include "NimBLERemoteDescriptor.h"
//#include <string> #include <vector>
#include <map>
class NimBLERemoteService; class NimBLERemoteService;
class NimBLERemoteDescriptor; class NimBLERemoteDescriptor;
typedef void (*notify_callback)(NimBLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify); typedef void (*notify_callback)(NimBLERemoteCharacteristic* pBLERemoteCharacteristic,
uint8_t* pData, size_t length, bool isNotify);
/** /**
* @brief A model of a remote %BLE characteristic. * @brief A model of a remote %BLE characteristic.
@ -45,8 +46,10 @@ public:
bool canRead(); bool canRead();
bool canWrite(); bool canWrite();
bool canWriteNoResponse(); bool canWriteNoResponse();
NimBLERemoteDescriptor* getDescriptor(NimBLEUUID uuid); std::vector<NimBLERemoteDescriptor*>::iterator begin();
std::map<std::string, NimBLERemoteDescriptor*>* getDescriptors(); std::vector<NimBLERemoteDescriptor*>::iterator end();
NimBLERemoteDescriptor* getDescriptor(const NimBLEUUID &uuid);
std::vector<NimBLERemoteDescriptor*>* getDescriptors(bool refresh = false);
uint16_t getHandle(); uint16_t getHandle();
uint16_t getDefHandle(); uint16_t getDefHandle();
NimBLEUUID getUUID(); NimBLEUUID getUUID();
@ -54,12 +57,19 @@ public:
uint8_t readUInt8(); uint8_t readUInt8();
uint16_t readUInt16(); uint16_t readUInt16();
uint32_t readUInt32(); uint32_t readUInt32();
bool registerForNotify(notify_callback _callback, bool notifications = true, bool response = true); bool registerForNotify(notify_callback _callback,
bool writeValue(uint8_t* data, size_t length, bool response = false); bool notifications = true,
bool writeValue(std::string newValue, bool response = false); bool response = true);
bool writeValue(uint8_t newValue, bool response = false); bool writeValue(const uint8_t* data,
size_t length,
bool response = false);
bool writeValue(const std::string &newValue,
bool response = false);
bool writeValue(uint8_t newValue,
bool response = false);
std::string toString(); std::string toString();
uint8_t* readRawData(); uint8_t* readRawData();
size_t getDataLength();
NimBLERemoteService* getRemoteService(); NimBLERemoteService* getRemoteService();
private: private:
@ -72,9 +82,11 @@ private:
// Private member functions // Private member functions
void removeDescriptors(); void removeDescriptors();
bool retrieveDescriptors(uint16_t endHdl); bool retrieveDescriptors(const NimBLEUUID *uuid_filter = nullptr);
static int onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg); static int onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error,
static int onWriteCB(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg); struct ble_gatt_attr *attr, void *arg);
static int onWriteCB(uint16_t conn_handle, const struct ble_gatt_error *error,
struct ble_gatt_attr *attr, void *arg);
void releaseSemaphores(); void releaseSemaphores();
static int descriptorDiscCB(uint16_t conn_handle, const struct ble_gatt_error *error, static int descriptorDiscCB(uint16_t conn_handle, const struct ble_gatt_error *error,
uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc, uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc,
@ -90,11 +102,14 @@ private:
FreeRTOS::Semaphore m_semaphoreReadCharEvt = FreeRTOS::Semaphore("ReadCharEvt"); FreeRTOS::Semaphore m_semaphoreReadCharEvt = FreeRTOS::Semaphore("ReadCharEvt");
FreeRTOS::Semaphore m_semaphoreWriteCharEvt = FreeRTOS::Semaphore("WriteCharEvt"); FreeRTOS::Semaphore m_semaphoreWriteCharEvt = FreeRTOS::Semaphore("WriteCharEvt");
std::string m_value; std::string m_value;
uint8_t* m_rawData = nullptr; uint8_t* m_rawData;
size_t m_dataLen;
notify_callback m_notifyCallback; notify_callback m_notifyCallback;
// We maintain a map of descriptors owned by this characteristic keyed by a string representation of the UUID. // We maintain a vector of descriptors owned by this characteristic.
std::map<std::string, NimBLERemoteDescriptor*> m_descriptorMap; std::vector<NimBLERemoteDescriptor*> m_descriptorVector;
}; // BLERemoteCharacteristic }; // NimBLERemoteCharacteristic
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */
#endif /* COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_ */ #endif /* COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_ */

View File

@ -14,7 +14,11 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#include "NimBLERemoteDescriptor.h" #include "NimBLERemoteDescriptor.h"
#include "NimBLEUtils.h"
#include "NimBLELog.h" #include "NimBLELog.h"
static const char* LOG_TAG = "NimBLERemoteDescriptor"; static const char* LOG_TAG = "NimBLERemoteDescriptor";
@ -83,22 +87,26 @@ int NimBLERemoteDescriptor::onReadCB(uint16_t conn_handle,
struct ble_gatt_attr *attr, void *arg) struct ble_gatt_attr *attr, void *arg)
{ {
NimBLERemoteDescriptor* desc = (NimBLERemoteDescriptor*)arg; NimBLERemoteDescriptor* desc = (NimBLERemoteDescriptor*)arg;
uint16_t conn_id = desc->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId();
// Make sure the discovery is for this device // Make sure the discovery is for this device
if(desc->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId() != conn_handle){ if(conn_id != conn_handle){
return 0; return 0;
} }
NIMBLE_LOGD(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle); NIMBLE_LOGD(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
if(error->status == 0){ if(error->status == 0){
desc->m_value = std::string((char*) attr->om->om_data, attr->om->om_len); if(attr){
desc->m_semaphoreReadDescrEvt.give(0); NIMBLE_LOGD(LOG_TAG, "Got %d bytes", attr->om->om_len);
} else {
desc->m_value = ""; desc->m_value += std::string((char*) attr->om->om_data, attr->om->om_len);
desc->m_semaphoreReadDescrEvt.give(error->status); return 0;
}
} }
// Read complete release semaphore and let the app can continue.
desc->m_semaphoreReadDescrEvt.give(error->status);
return 0; return 0;
} }
@ -106,10 +114,12 @@ int NimBLERemoteDescriptor::onReadCB(uint16_t conn_handle,
std::string NimBLERemoteDescriptor::readValue() { std::string NimBLERemoteDescriptor::readValue() {
NIMBLE_LOGD(LOG_TAG, ">> Descriptor readValue: %s", toString().c_str()); NIMBLE_LOGD(LOG_TAG, ">> Descriptor readValue: %s", toString().c_str());
NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
int rc = 0; int rc = 0;
int retryCount = 1; int retryCount = 1;
// Clear the value before reading.
m_value = "";
NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
// Check to see that we are connected. // Check to see that we are connected.
if (!pClient->isConnected()) { if (!pClient->isConnected()) {
@ -120,12 +130,13 @@ std::string NimBLERemoteDescriptor::readValue() {
do { do {
m_semaphoreReadDescrEvt.take("ReadDescriptor"); m_semaphoreReadDescrEvt.take("ReadDescriptor");
rc = ble_gattc_read(pClient->getConnId(), m_handle, rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
NimBLERemoteDescriptor::onReadCB, this); NimBLERemoteDescriptor::onReadCB,
this);
if (rc != 0) { if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Descriptor read failed, code: %d", rc); NIMBLE_LOGE(LOG_TAG, "Error: Failed to read descriptor; rc=%d, %s",
m_semaphoreReadDescrEvt.give(); rc, NimBLEUtils::returnCodeToString(rc));
m_semaphoreReadDescrEvt.give(0);
return ""; return "";
} }
@ -133,8 +144,14 @@ std::string NimBLERemoteDescriptor::readValue() {
switch(rc){ switch(rc){
case 0: case 0:
case BLE_HS_EDONE:
rc = 0;
break;
// Descriptor is not long-readable, return with what we have.
case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
NIMBLE_LOGI(LOG_TAG, "Attribute not long");
rc = 0;
break; break;
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN): case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR): case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR):
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC): case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC):
@ -146,9 +163,8 @@ std::string NimBLERemoteDescriptor::readValue() {
} }
} while(rc != 0 && retryCount--); } while(rc != 0 && retryCount--);
NIMBLE_LOGD(LOG_TAG, "<< Descriptor readValue(): length: %d, rc: %d", m_value.length(), rc); NIMBLE_LOGD(LOG_TAG, "<< Descriptor readValue(): length: %d", m_value.length());
return m_value;
return (rc == 0) ? m_value : "";
} // readValue } // readValue
@ -211,11 +227,7 @@ int NimBLERemoteDescriptor::onWriteCB(uint16_t conn_handle,
NIMBLE_LOGD(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle); NIMBLE_LOGD(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle);
if (error->status == 0) {
descriptor->m_semaphoreDescWrite.give(0);
} else {
descriptor->m_semaphoreDescWrite.give(error->status); descriptor->m_semaphoreDescWrite.give(error->status);
}
return 0; return 0;
} }
@ -227,7 +239,7 @@ int NimBLERemoteDescriptor::onWriteCB(uint16_t conn_handle,
* @param [in] length The length of the data to send. * @param [in] length The length of the data to send.
* @param [in] response True if we expect a response. * @param [in] response True if we expect a response.
*/ */
bool NimBLERemoteDescriptor::writeValue(uint8_t* data, size_t length, bool response) { bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool response) {
NIMBLE_LOGD(LOG_TAG, ">> Descriptor writeValue: %s", toString().c_str()); NIMBLE_LOGD(LOG_TAG, ">> Descriptor writeValue: %s", toString().c_str());
@ -235,6 +247,7 @@ bool NimBLERemoteDescriptor::writeValue(uint8_t* data, size_t length, bool respo
int rc = 0; int rc = 0;
int retryCount = 1; int retryCount = 1;
uint16_t mtu;
// Check to see that we are connected. // Check to see that we are connected.
if (!pClient->isConnected()) { if (!pClient->isConnected()) {
@ -242,7 +255,11 @@ bool NimBLERemoteDescriptor::writeValue(uint8_t* data, size_t length, bool respo
return false; return false;
} }
if(!response) { mtu = ble_att_mtu(pClient->getConnId()) - 3;
// Check if the data length is longer than we can write in 1 connection event.
// If so we must do a long write which requires a response.
if(length <= mtu && !response) {
rc = ble_gattc_write_no_rsp_flat(pClient->getConnId(), m_handle, data, length); rc = ble_gattc_write_no_rsp_flat(pClient->getConnId(), m_handle, data, length);
return (rc == 0); return (rc == 0);
} }
@ -250,10 +267,19 @@ bool NimBLERemoteDescriptor::writeValue(uint8_t* data, size_t length, bool respo
do { do {
m_semaphoreDescWrite.take("WriteDescriptor"); m_semaphoreDescWrite.take("WriteDescriptor");
if(length > mtu) {
NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length);
os_mbuf *om = ble_hs_mbuf_from_flat(data, length);
rc = ble_gattc_write_long(pClient->getConnId(), m_handle, 0, om,
NimBLERemoteDescriptor::onWriteCB,
this);
} else {
rc = ble_gattc_write_flat(pClient->getConnId(), m_handle, rc = ble_gattc_write_flat(pClient->getConnId(), m_handle,
data, length, data, length,
NimBLERemoteDescriptor::onWriteCB, NimBLERemoteDescriptor::onWriteCB,
this); this);
}
if (rc != 0) { if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Error: Failed to write descriptor; rc=%d", rc); NIMBLE_LOGE(LOG_TAG, "Error: Failed to write descriptor; rc=%d", rc);
m_semaphoreDescWrite.give(); m_semaphoreDescWrite.give();
@ -264,6 +290,13 @@ bool NimBLERemoteDescriptor::writeValue(uint8_t* data, size_t length, bool respo
switch(rc){ switch(rc){
case 0: case 0:
case BLE_HS_EDONE:
rc = 0;
break;
case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
NIMBLE_LOGE(LOG_TAG, "Long write not supported by peer; Truncating length to %d", mtu);
retryCount++;
length = mtu;
break; break;
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN): case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
@ -278,7 +311,7 @@ bool NimBLERemoteDescriptor::writeValue(uint8_t* data, size_t length, bool respo
} while(rc != 0 && retryCount--); } while(rc != 0 && retryCount--);
NIMBLE_LOGD(LOG_TAG, "<< Descriptor writeValue, rc: %d",rc); NIMBLE_LOGD(LOG_TAG, "<< Descriptor writeValue, rc: %d",rc);
return (rc == 0); //true; return (rc == 0);
} // writeValue } // writeValue
@ -287,7 +320,7 @@ bool NimBLERemoteDescriptor::writeValue(uint8_t* data, size_t length, bool respo
* @param [in] newValue The data to send to the remote descriptor. * @param [in] newValue The data to send to the remote descriptor.
* @param [in] response True if we expect a response. * @param [in] response True if we expect a response.
*/ */
bool NimBLERemoteDescriptor::writeValue(std::string newValue, bool response) { bool NimBLERemoteDescriptor::writeValue(const std::string &newValue, bool response) {
return writeValue((uint8_t*) newValue.data(), newValue.length(), response); return writeValue((uint8_t*) newValue.data(), newValue.length(), response);
} // writeValue } // writeValue
@ -309,4 +342,6 @@ void NimBLERemoteDescriptor::releaseSemaphores() {
m_semaphoreDescWrite.give(1); m_semaphoreDescWrite.give(1);
m_semaphoreReadDescrEvt.give(1); m_semaphoreReadDescrEvt.give(1);
} }
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */

View File

@ -17,6 +17,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#include "NimBLERemoteCharacteristic.h" #include "NimBLERemoteCharacteristic.h"
class NimBLERemoteCharacteristic; class NimBLERemoteCharacteristic;
@ -33,26 +36,32 @@ public:
uint16_t readUInt16(void); uint16_t readUInt16(void);
uint32_t readUInt32(void); uint32_t readUInt32(void);
std::string toString(void); std::string toString(void);
bool writeValue(uint8_t* data, size_t length, bool response = false); bool writeValue(const uint8_t* data, size_t length, bool response = false);
bool writeValue(std::string newValue, bool response = false); bool writeValue(const std::string &newValue, bool response = false);
bool writeValue(uint8_t newValue, bool response = false); bool writeValue(uint8_t newValue, bool response = false);
private: private:
friend class NimBLERemoteCharacteristic; friend class NimBLERemoteCharacteristic;
NimBLERemoteDescriptor(NimBLERemoteCharacteristic* pRemoteCharacteristic, const struct ble_gatt_dsc *dsc);
static int onWriteCB(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg); NimBLERemoteDescriptor (NimBLERemoteCharacteristic* pRemoteCharacteristic,
static int onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg); const struct ble_gatt_dsc *dsc);
static int onWriteCB(uint16_t conn_handle, const struct ble_gatt_error *error,
struct ble_gatt_attr *attr, void *arg);
static int onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error,
struct ble_gatt_attr *attr, void *arg);
void releaseSemaphores(); void releaseSemaphores();
uint16_t m_handle; // Server handle of this descriptor. uint16_t m_handle;
NimBLEUUID m_uuid; // UUID of this descriptor. NimBLEUUID m_uuid;
std::string m_value; // Last received value of the descriptor. std::string m_value;
NimBLERemoteCharacteristic* m_pRemoteCharacteristic; // Reference to the Remote characteristic of which this descriptor is associated. NimBLERemoteCharacteristic* m_pRemoteCharacteristic;
FreeRTOS::Semaphore m_semaphoreReadDescrEvt = FreeRTOS::Semaphore("ReadDescrEvt"); FreeRTOS::Semaphore m_semaphoreReadDescrEvt = FreeRTOS::Semaphore("ReadDescrEvt");
FreeRTOS::Semaphore m_semaphoreDescWrite = FreeRTOS::Semaphore("WriteDescEvt"); FreeRTOS::Semaphore m_semaphoreDescWrite = FreeRTOS::Semaphore("WriteDescEvt");
}; };
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */
#endif /* COMPONENTS_NIMBLEREMOTEDESCRIPTOR_H_ */ #endif /* COMPONENTS_NIMBLEREMOTEDESCRIPTOR_H_ */

View File

@ -14,6 +14,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#include "NimBLERemoteService.h" #include "NimBLERemoteService.h"
#include "NimBLEUtils.h" #include "NimBLEUtils.h"
#include "NimBLEDevice.h" #include "NimBLEDevice.h"
@ -28,7 +31,7 @@ static const char* LOG_TAG = "NimBLERemoteService";
*/ */
NimBLERemoteService::NimBLERemoteService(NimBLEClient* pClient, const struct ble_gatt_svc* service) { NimBLERemoteService::NimBLERemoteService(NimBLEClient* pClient, const struct ble_gatt_svc* service) {
NIMBLE_LOGD(LOG_TAG, ">> BLERemoteService()"); NIMBLE_LOGD(LOG_TAG, ">> NimBLERemoteService()");
m_pClient = pClient; m_pClient = pClient;
switch (service->uuid.u.type) { switch (service->uuid.u.type) {
case BLE_UUID_TYPE_16: case BLE_UUID_TYPE_16:
@ -46,9 +49,7 @@ NimBLERemoteService::NimBLERemoteService(NimBLEClient* pClient, const struct ble
} }
m_startHandle = service->start_handle; m_startHandle = service->start_handle;
m_endHandle = service->end_handle; m_endHandle = service->end_handle;
m_haveCharacteristics = false; NIMBLE_LOGD(LOG_TAG, "<< NimBLERemoteService()");
NIMBLE_LOGD(LOG_TAG, "<< BLERemoteService()");
} }
@ -61,6 +62,24 @@ NimBLERemoteService::~NimBLERemoteService() {
} }
/**
* @brief Get iterator to the beginning of the vector of remote characteristic pointers.
* @return An iterator to the beginning of the vector of remote characteristic pointers.
*/
std::vector<NimBLERemoteCharacteristic*>::iterator NimBLERemoteService::begin() {
return m_characteristicVector.begin();
}
/**
* @brief Get iterator to the end of the vector of remote characteristic pointers.
* @return An iterator to the end of the vector of remote characteristic pointers.
*/
std::vector<NimBLERemoteCharacteristic*>::iterator NimBLERemoteService::end() {
return m_characteristicVector.end();
}
/** /**
* @brief Get the remote characteristic object for the characteristic UUID. * @brief Get the remote characteristic object for the characteristic UUID.
* @param [in] uuid Remote characteristic uuid. * @param [in] uuid Remote characteristic uuid.
@ -76,20 +95,51 @@ NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const char* u
* @param [in] uuid Characteristic uuid. * @param [in] uuid Characteristic uuid.
* @return Reference to the characteristic object, or nullptr if not found. * @return Reference to the characteristic object, or nullptr if not found.
*/ */
NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(NimBLEUUID uuid) { NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const NimBLEUUID &uuid) {
if (m_haveCharacteristics) { for(auto &it: m_characteristicVector) {
std::string v = uuid.toString(); if(it->getUUID() == uuid) {
for (auto &myPair : m_characteristicMap) { return it;
if (myPair.first == v) {
return myPair.second;
} }
} }
size_t prev_size = m_characteristicVector.size();
if(retrieveCharacteristics(&uuid)) {
if(m_characteristicVector.size() > prev_size) {
return m_characteristicVector.back();
}
} }
return nullptr; return nullptr;
} // getCharacteristic } // getCharacteristic
/**
* @Get a pointer to the vector of found characteristics.
* @param [in] bool value to indicate if the current vector should be cleared and
* subsequently all characteristics for this service retrieved from the peripheral.
* If false the vector will be returned with the currently stored characteristics,
* if the vector is empty it will retrieve all characteristics of this service
* from the peripheral.
* @return a pointer to the vector of descriptors for this characteristic.
*/
std::vector<NimBLERemoteCharacteristic*>* NimBLERemoteService::getCharacteristics(bool refresh) {
if(refresh) {
removeCharacteristics();
}
if(m_characteristicVector.empty()) {
if (!retrieveCharacteristics()) {
NIMBLE_LOGE(LOG_TAG, "Error: Failed to get characteristics");
}
else{
NIMBLE_LOGI(LOG_TAG, "Found %d characteristics", m_characteristicVector.size());
}
}
return &m_characteristicVector;
} // getCharacteristics
/** /**
* @brief Callback for Characterisic discovery. * @brief Callback for Characterisic discovery.
*/ */
@ -97,7 +147,8 @@ int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle,
const struct ble_gatt_error *error, const struct ble_gatt_error *error,
const struct ble_gatt_chr *chr, void *arg) const struct ble_gatt_chr *chr, void *arg)
{ {
NIMBLE_LOGD(LOG_TAG,"Characteristic Discovered >> status: %d handle: %d", error->status, conn_handle); NIMBLE_LOGD(LOG_TAG,"Characteristic Discovered >> status: %d handle: %d",
error->status, (error->status == 0) ? chr->val_handle : -1);
NimBLERemoteService *service = (NimBLERemoteService*)arg; NimBLERemoteService *service = (NimBLERemoteService*)arg;
int rc=0; int rc=0;
@ -109,10 +160,9 @@ int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle,
switch (error->status) { switch (error->status) {
case 0: { case 0: {
// Found a service - add it to the map // Found a service - add it to the vector
NimBLERemoteCharacteristic* pRemoteCharacteristic = new NimBLERemoteCharacteristic(service, chr); NimBLERemoteCharacteristic* pRemoteCharacteristic = new NimBLERemoteCharacteristic(service, chr);
service->m_characteristicMap.insert(std::pair<std::string, NimBLERemoteCharacteristic*>(pRemoteCharacteristic->getUUID().toString(), pRemoteCharacteristic)); service->m_characteristicVector.push_back(pRemoteCharacteristic);
service->m_characteristicMapByHandle.insert(std::pair<uint16_t, NimBLERemoteCharacteristic*>(chr->val_handle, pRemoteCharacteristic));
break; break;
} }
case BLE_HS_EDONE:{ case BLE_HS_EDONE:{
@ -145,7 +195,7 @@ int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle,
* This function will not return until we have all the characteristics. * This function will not return until we have all the characteristics.
* @return N/A * @return N/A
*/ */
bool NimBLERemoteService::retrieveCharacteristics() { bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID *uuid_filter) {
NIMBLE_LOGD(LOG_TAG, ">> retrieveCharacteristics() for service: %s", getUUID().toString().c_str()); NIMBLE_LOGD(LOG_TAG, ">> retrieveCharacteristics() for service: %s", getUUID().toString().c_str());
int rc = 0; int rc = 0;
@ -153,48 +203,28 @@ bool NimBLERemoteService::retrieveCharacteristics() {
m_semaphoreGetCharEvt.take("retrieveCharacteristics"); m_semaphoreGetCharEvt.take("retrieveCharacteristics");
if(uuid_filter == nullptr) {
rc = ble_gattc_disc_all_chrs(m_pClient->getConnId(), rc = ble_gattc_disc_all_chrs(m_pClient->getConnId(),
m_startHandle, m_startHandle,
m_endHandle, m_endHandle,
NimBLERemoteService::characteristicDiscCB, NimBLERemoteService::characteristicDiscCB,
this); this);
} else {
rc = ble_gattc_disc_chrs_by_uuid(m_pClient->getConnId(),
m_startHandle,
m_endHandle,
&uuid_filter->getNative()->u,
NimBLERemoteService::characteristicDiscCB,
this);
}
if (rc != 0) { if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_chrs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_chrs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
m_haveCharacteristics = false;
m_semaphoreGetCharEvt.give(); m_semaphoreGetCharEvt.give();
return false; return false;
} }
m_haveCharacteristics = (m_semaphoreGetCharEvt.wait("retrieveCharacteristics") == 0); if(m_semaphoreGetCharEvt.wait("retrieveCharacteristics") == 0){
if(m_haveCharacteristics){
uint16_t endHdl = 0xFFFF;
NIMBLE_LOGD(LOG_TAG, "Found %d Characteristics", m_characteristicMapByHandle.size());
for (auto it = m_characteristicMapByHandle.cbegin(); it != m_characteristicMapByHandle.cend(); ++it) {
NIMBLE_LOGD(LOG_TAG, "Found UUID: %s Handle: %d Def Handle: %d", (*it).second->getUUID().toString().c_str(), (*it).second->getHandle(), (*it).second->getDefHandle());
// The descriptor handle is between this characteristic val_handle and the next ones def_handle
// so make the end of the scan at the handle before the next characteristic def_handle
// Make sure we don't go past the service end handle
if(++it != m_characteristicMapByHandle.cend()){
NIMBLE_LOGD(LOG_TAG, "Next UUID: %s Handle: %d Def Handle: %d", (*it).second->getUUID().toString().c_str(), (*it).second->getHandle(),(*it).second->getDefHandle());
endHdl = (*it).second->getDefHandle()-1;
}
else{
NIMBLE_LOGD(LOG_TAG, "END CHARS");
endHdl = m_endHandle;
}
--it;
//If there is no handles between this characteristic and the next there is no descriptor so skip to the next
if((*it).second->getHandle() != endHdl){
if(!m_pClient->m_isConnected || !(*it).second->retrieveDescriptors(endHdl)) {
return false;
}
}
//NIMBLE_LOGD(LOG_TAG, "Found %d Characteristics in service UUID: %s", chars->size(), myPair.first.c_str());
}
NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristics()"); NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristics()");
return true; return true;
} }
@ -205,24 +235,6 @@ bool NimBLERemoteService::retrieveCharacteristics() {
} // retrieveCharacteristics } // retrieveCharacteristics
/**
* @brief Retrieve a map of all the characteristics of this service.
* @return A map of all the characteristics of this service.
*/
std::map<std::string, NimBLERemoteCharacteristic*>* NimBLERemoteService::getCharacteristics() {
return &m_characteristicMap;
} // getCharacteristics
/**
* @brief Retrieve a map of all the characteristics of this service.
* @return A map of all the characteristics of this service.
*/
std::map<uint16_t, NimBLERemoteCharacteristic*>* NimBLERemoteService::getCharacteristicsByHandle() {
return &m_characteristicMapByHandle;
} // getCharacteristicsByHandle
/** /**
* @brief Get the client associated with this service. * @brief Get the client associated with this service.
* @return A reference to the client associated with this service. * @return A reference to the client associated with this service.
@ -261,7 +273,7 @@ NimBLEUUID NimBLERemoteService::getUUID() {
* @param [in] characteristicUuid The characteristic to read. * @param [in] characteristicUuid The characteristic to read.
* @returns a string containing the value or an empty string if not found or error. * @returns a string containing the value or an empty string if not found or error.
*/ */
std::string NimBLERemoteService::getValue(NimBLEUUID characteristicUuid) { std::string NimBLERemoteService::getValue(const NimBLEUUID &characteristicUuid) {
NIMBLE_LOGD(LOG_TAG, ">> readValue: uuid: %s", characteristicUuid.toString().c_str()); NIMBLE_LOGD(LOG_TAG, ">> readValue: uuid: %s", characteristicUuid.toString().c_str());
std::string ret = ""; std::string ret = "";
@ -282,7 +294,7 @@ std::string NimBLERemoteService::getValue(NimBLEUUID characteristicUuid) {
* @param [in] value The value to set. * @param [in] value The value to set.
* @returns true on success, false if not found or error * @returns true on success, false if not found or error
*/ */
bool NimBLERemoteService::setValue(NimBLEUUID characteristicUuid, std::string value) { bool NimBLERemoteService::setValue(const NimBLEUUID &characteristicUuid, const std::string &value) {
NIMBLE_LOGD(LOG_TAG, ">> setValue: uuid: %s", characteristicUuid.toString().c_str()); NIMBLE_LOGD(LOG_TAG, ">> setValue: uuid: %s", characteristicUuid.toString().c_str());
bool ret = false; bool ret = false;
@ -298,20 +310,17 @@ bool NimBLERemoteService::setValue(NimBLEUUID characteristicUuid, std::string va
/** /**
* @brief Delete the characteristics in the characteristics map. * @brief Delete the characteristics in the characteristics vector.
* We maintain a map called m_characteristicsMap that contains pointers to BLERemoteCharacteristic * We maintain a vector called m_characteristicsVector that contains pointers to BLERemoteCharacteristic
* object references. Since we allocated these in this class, we are also responsible for deleteing * object references. Since we allocated these in this class, we are also responsible for deleting
* them. This method does just that. * them. This method does just that.
* @return N/A. * @return N/A.
*/ */
void NimBLERemoteService::removeCharacteristics() { void NimBLERemoteService::removeCharacteristics() {
m_characteristicMap.clear(); // Clear the map for(auto &it: m_characteristicVector) {
delete it;
for (auto &myPair : m_characteristicMapByHandle) {
delete myPair.second;
} }
m_characteristicMapByHandle.clear(); // Clear the map m_characteristicVector.clear(); // Clear the vector
} // removeCharacteristics } // removeCharacteristics
@ -335,8 +344,8 @@ std::string NimBLERemoteService::toString() {
res += " 0x"; res += " 0x";
res += val; res += val;
for (auto &myPair : m_characteristicMap) { for (auto &it: m_characteristicVector) {
res += "\n" + myPair.second->toString(); res += "\n" + it->toString();
} }
return res; return res;
@ -348,10 +357,11 @@ std::string NimBLERemoteService::toString() {
* Will release all characteristic and subsequently all descriptor semaphores for this service. * Will release all characteristic and subsequently all descriptor semaphores for this service.
*/ */
void NimBLERemoteService::releaseSemaphores() { void NimBLERemoteService::releaseSemaphores() {
for (auto &cPair : m_characteristicMapByHandle) { for(auto &it: m_characteristicVector) {
cPair.second->releaseSemaphores(); it->releaseSemaphores();
} }
m_semaphoreGetCharEvt.give(1); m_semaphoreGetCharEvt.give(1);
} }
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */

View File

@ -17,12 +17,15 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#include "NimBLEClient.h" #include "NimBLEClient.h"
#include "NimBLEUUID.h" #include "NimBLEUUID.h"
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "NimBLERemoteCharacteristic.h" #include "NimBLERemoteCharacteristic.h"
#include <map> #include <vector>
class NimBLEClient; class NimBLEClient;
class NimBLERemoteCharacteristic; class NimBLERemoteCharacteristic;
@ -36,19 +39,18 @@ public:
virtual ~NimBLERemoteService(); virtual ~NimBLERemoteService();
// Public methods // Public methods
NimBLERemoteCharacteristic* getCharacteristic(const char* uuid); // Get the specified characteristic reference. std::vector<NimBLERemoteCharacteristic*>::iterator begin();
NimBLERemoteCharacteristic* getCharacteristic(NimBLEUUID uuid); // Get the specified characteristic reference. std::vector<NimBLERemoteCharacteristic*>::iterator end();
// BLERemoteCharacteristic* getCharacteristic(uint16_t uuid); // Get the specified characteristic reference. NimBLERemoteCharacteristic* getCharacteristic(const char* uuid);
std::map<std::string, NimBLERemoteCharacteristic*>* getCharacteristics(); NimBLERemoteCharacteristic* getCharacteristic(const NimBLEUUID &uuid);
std::map<uint16_t, NimBLERemoteCharacteristic*>* getCharacteristicsByHandle(); // Get the characteristics map. NimBLEClient* getClient(void);
// void getCharacteristics(std::map<uint16_t, BLERemoteCharacteristic*>* pCharacteristicMap); uint16_t getHandle();
NimBLEUUID getUUID(void);
NimBLEClient* getClient(void); // Get a reference to the client associated with this service. std::string getValue(const NimBLEUUID &characteristicUuid);
uint16_t getHandle(); // Get the handle of this service. bool setValue(const NimBLEUUID &characteristicUuid,
NimBLEUUID getUUID(void); // Get the UUID of this service. const std::string &value);
std::string getValue(NimBLEUUID characteristicUuid); // Get the value of a characteristic.
bool setValue(NimBLEUUID characteristicUuid, std::string value); // Set the value of a characteristic.
std::string toString(void); std::string toString(void);
std::vector<NimBLERemoteCharacteristic*>* getCharacteristics(bool refresh = false);
private: private:
// Private constructor ... never meant to be created by a user application. // Private constructor ... never meant to be created by a user application.
@ -59,31 +61,29 @@ private:
friend class NimBLERemoteCharacteristic; friend class NimBLERemoteCharacteristic;
// Private methods // Private methods
bool retrieveCharacteristics(void); // Retrieve the characteristics from the BLE Server. bool retrieveCharacteristics(const NimBLEUUID *uuid_filter = nullptr);
static int characteristicDiscCB(uint16_t conn_handle, static int characteristicDiscCB(uint16_t conn_handle,
const struct ble_gatt_error *error, const struct ble_gatt_error *error,
const struct ble_gatt_chr *chr, void *arg); const struct ble_gatt_chr *chr,
void *arg);
uint16_t getStartHandle(); // Get the start handle for this service. uint16_t getStartHandle();
uint16_t getEndHandle(); // Get the end handle for this service. uint16_t getEndHandle();
void releaseSemaphores(); void releaseSemaphores();
void removeCharacteristics(); void removeCharacteristics();
// Properties // Properties
// We maintain a map of characteristics owned by this service keyed by a string representation of the UUID. // We maintain a vector of characteristics owned by this service.
std::map<std::string, NimBLERemoteCharacteristic*> m_characteristicMap; std::vector<NimBLERemoteCharacteristic*> m_characteristicVector;
// We maintain a map of characteristics owned by this service keyed by a handle.
std::map<uint16_t, NimBLERemoteCharacteristic*> m_characteristicMapByHandle;
bool m_haveCharacteristics; // Have we previously obtained the characteristics.
NimBLEClient* m_pClient; NimBLEClient* m_pClient;
FreeRTOS::Semaphore m_semaphoreGetCharEvt = FreeRTOS::Semaphore("GetCharEvt"); FreeRTOS::Semaphore m_semaphoreGetCharEvt = FreeRTOS::Semaphore("GetCharEvt");
NimBLEUUID m_uuid; // The UUID of this service. NimBLEUUID m_uuid;
uint16_t m_startHandle; // The starting handle of this service. uint16_t m_startHandle;
uint16_t m_endHandle; // The ending handle of this service. uint16_t m_endHandle;
}; // BLERemoteService }; // NimBLERemoteService
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */
#endif /* COMPONENTS_NIMBLEREMOTESERVICE_H_ */ #endif /* COMPONENTS_NIMBLEREMOTESERVICE_H_ */

View File

@ -14,6 +14,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
#include "NimBLEScan.h" #include "NimBLEScan.h"
#include "NimBLEUtils.h" #include "NimBLEUtils.h"
#include "NimBLEDevice.h" #include "NimBLEDevice.h"
@ -63,7 +66,7 @@ NimBLEScan::NimBLEScan() {
m_scan_params.itvl = 0; // This is defined as the time interval from when the Controller started its last LE scan until it begins the subsequent LE scan. (units=0.625 msec) m_scan_params.itvl = 0; // This is defined as the time interval from when the Controller started its last LE scan until it begins the subsequent LE scan. (units=0.625 msec)
m_scan_params.window = 0; // The duration of the LE scan. LE_Scan_Window shall be less than or equal to LE_Scan_Interval (units=0.625 msec) m_scan_params.window = 0; // The duration of the LE scan. LE_Scan_Window shall be less than or equal to LE_Scan_Interval (units=0.625 msec)
m_scan_params.limited = 0; // If set, only discover devices in limited discoverable mode. m_scan_params.limited = 0; // If set, only discover devices in limited discoverable mode.
m_scan_params.filter_duplicates = 1; // If set, the controller ignores all but the first advertisement from each device. m_scan_params.filter_duplicates = 0; // If set, the controller ignores all but the first advertisement from each device.
m_pAdvertisedDeviceCallbacks = nullptr; m_pAdvertisedDeviceCallbacks = nullptr;
m_stopped = true; m_stopped = true;
m_wantDuplicates = false; m_wantDuplicates = false;
@ -114,13 +117,15 @@ NimBLEScan::NimBLEScan() {
NimBLEAdvertisedDevice* advertisedDevice = nullptr; NimBLEAdvertisedDevice* advertisedDevice = nullptr;
// If we've seen this device before get a pointer to it from the map // If we've seen this device before get a pointer to it from the vector
auto it = pScan->m_scanResults.m_advertisedDevicesMap.find(advertisedAddress.toString()); for(auto &it: pScan->m_scanResults.m_advertisedDevicesVector) {
if(it != pScan->m_scanResults.m_advertisedDevicesMap.cend()) { if(it->getAddress() == advertisedAddress) {
advertisedDevice = (*it).second; advertisedDevice = it;
break;
}
} }
// If we haven't seen this device before; create a new instance and insert it in the map. // If we haven't seen this device before; create a new instance and insert it in the vector.
// Otherwise just update the relevant parameters of the already known device. // Otherwise just update the relevant parameters of the already known device.
if(advertisedDevice == nullptr){ if(advertisedDevice == nullptr){
advertisedDevice = new NimBLEAdvertisedDevice(); advertisedDevice = new NimBLEAdvertisedDevice();
@ -128,7 +133,7 @@ NimBLEScan::NimBLEScan() {
advertisedDevice->setAddress(advertisedAddress); advertisedDevice->setAddress(advertisedAddress);
//NIMBLE_LOGE(LOG_TAG, "advertisement type: %d, %s",event->disc.event_type, NimBLEUtils::advTypeToString(event->disc.event_type)); //NIMBLE_LOGE(LOG_TAG, "advertisement type: %d, %s",event->disc.event_type, NimBLEUtils::advTypeToString(event->disc.event_type));
advertisedDevice->setAdvType(event->disc.event_type); advertisedDevice->setAdvType(event->disc.event_type);
pScan->m_scanResults.m_advertisedDevicesMap.insert(std::pair<std::string, NimBLEAdvertisedDevice*>(advertisedAddress.toString(), advertisedDevice)); pScan->m_scanResults.m_advertisedDevicesVector.push_back(advertisedDevice);
NIMBLE_LOGI(LOG_TAG, "NEW DEVICE FOUND: %s", advertisedAddress.toString().c_str()); NIMBLE_LOGI(LOG_TAG, "NEW DEVICE FOUND: %s", advertisedAddress.toString().c_str());
} }
else{ else{
@ -141,7 +146,7 @@ NimBLEScan::NimBLEScan() {
if (pScan->m_pAdvertisedDeviceCallbacks) { if (pScan->m_pAdvertisedDeviceCallbacks) {
// If not active scanning report the result to the listener. // If not active scanning report the result to the listener.
if(pScan->m_scan_params.passive) { if(pScan->m_scan_params.passive || event->disc.event_type == BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) {
pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice); pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
// Otherwise wait for the scan response so we can report all of the data at once. // Otherwise wait for the scan response so we can report all of the data at once.
} else if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) { } else if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
@ -259,7 +264,7 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul
} }
// if we are connecting to devices that are advertising even after being connected, multiconnecting peripherals // if we are connecting to devices that are advertising even after being connected, multiconnecting peripherals
// then we should not clear map or we will connect the same device few times // then we should not clear vector or we will connect the same device few times
if(!is_continue) { if(!is_continue) {
clearResults(); clearResults();
} }
@ -325,11 +330,16 @@ void NimBLEScan::stop() {
// delete peer device from cache after disconnecting, it is required in case we are connecting to devices with not public address // delete peer device from cache after disconnecting, it is required in case we are connecting to devices with not public address
void NimBLEScan::erase(NimBLEAddress address) { void NimBLEScan::erase(const NimBLEAddress &address) {
NIMBLE_LOGI(LOG_TAG, "erase device: %s", address.toString().c_str()); NIMBLE_LOGI(LOG_TAG, "erase device: %s", address.toString().c_str());
NimBLEAdvertisedDevice *advertisedDevice = m_scanResults.m_advertisedDevicesMap.find(address.toString())->second;
m_scanResults.m_advertisedDevicesMap.erase(address.toString()); for(auto it = m_scanResults.m_advertisedDevicesVector.begin(); it != m_scanResults.m_advertisedDevicesVector.end(); ++it) {
delete advertisedDevice; if((*it)->getAddress() == address) {
delete *it;
m_scanResults.m_advertisedDevicesVector.erase(it);
break;
}
}
} }
@ -356,10 +366,10 @@ NimBLEScanResults NimBLEScan::getResults() {
* @brief Clear the results of the scan. * @brief Clear the results of the scan.
*/ */
void NimBLEScan::clearResults() { void NimBLEScan::clearResults() {
for(auto _dev : m_scanResults.m_advertisedDevicesMap){ for(auto &it: m_scanResults.m_advertisedDevicesVector) {
delete _dev.second; delete it;
} }
m_scanResults.m_advertisedDevicesMap.clear(); m_scanResults.m_advertisedDevicesVector.clear();
} }
@ -379,7 +389,7 @@ void NimBLEScanResults::dump() {
* @return The number of devices found in the last scan. * @return The number of devices found in the last scan.
*/ */
int NimBLEScanResults::getCount() { int NimBLEScanResults::getCount() {
return m_advertisedDevicesMap.size(); return m_advertisedDevicesVector.size();
} // getCount } // getCount
@ -390,14 +400,43 @@ int NimBLEScanResults::getCount() {
* @return The device at the specified index. * @return The device at the specified index.
*/ */
NimBLEAdvertisedDevice NimBLEScanResults::getDevice(uint32_t i) { NimBLEAdvertisedDevice NimBLEScanResults::getDevice(uint32_t i) {
uint32_t x = 0; return *m_advertisedDevicesVector[i];
NimBLEAdvertisedDevice dev = *m_advertisedDevicesMap.begin()->second;
for (auto it = m_advertisedDevicesMap.begin(); it != m_advertisedDevicesMap.end(); it++) {
dev = *it->second;
if (x==i) break;
x++;
}
return dev;
} }
/**
* @brief Get iterator to the beginning of the vector of advertised device pointers.
* @return An iterator to the beginning of the vector of advertised device pointers.
*/
std::vector<NimBLEAdvertisedDevice*>::iterator NimBLEScanResults::begin() {
return m_advertisedDevicesVector.begin();
}
/**
* @brief Get iterator to the end of the vector of advertised device pointers.
* @return An iterator to the end of the vector of advertised device pointers.
*/
std::vector<NimBLEAdvertisedDevice*>::iterator NimBLEScanResults::end() {
return m_advertisedDevicesVector.end();
}
/**
* @brief Return a pointer to the specified device at the given address.
* If the address is not found a nullptr is returned.
* @param [in] address The address of the device.
* @return A pointer to the device at the specified address.
*/
NimBLEAdvertisedDevice *NimBLEScanResults::getDevice(const NimBLEAddress &address) {
for(size_t index = 0; index < m_advertisedDevicesVector.size(); index++) {
if(m_advertisedDevicesVector[index]->getAddress() == address) {
return m_advertisedDevicesVector[index];
}
}
return nullptr;
}
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */

View File

@ -16,17 +16,21 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
#include "NimBLEAdvertisedDevice.h" #include "NimBLEAdvertisedDevice.h"
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "host/ble_gap.h" #include "host/ble_gap.h"
#include <map> #include <vector>
class NimBLEDevice; class NimBLEDevice;
class NimBLEScan; class NimBLEScan;
class NimBLEAdvertisedDevice; class NimBLEAdvertisedDevice;
class NimBLEAdvertisedDeviceCallbacks; class NimBLEAdvertisedDeviceCallbacks;
class NimBLEAddress;
/** /**
* @brief The result of having performed a scan. * @brief The result of having performed a scan.
@ -40,10 +44,13 @@ public:
void dump(); void dump();
int getCount(); int getCount();
NimBLEAdvertisedDevice getDevice(uint32_t i); NimBLEAdvertisedDevice getDevice(uint32_t i);
std::vector<NimBLEAdvertisedDevice*>::iterator begin();
std::vector<NimBLEAdvertisedDevice*>::iterator end();
NimBLEAdvertisedDevice *getDevice(const NimBLEAddress &address);
private: private:
friend NimBLEScan; friend NimBLEScan;
std::map<std::string, NimBLEAdvertisedDevice*> m_advertisedDevicesMap; std::vector<NimBLEAdvertisedDevice*> m_advertisedDevicesVector;
}; };
/** /**
@ -62,7 +69,7 @@ public:
void stop(); void stop();
void clearResults(); void clearResults();
NimBLEScanResults getResults(); NimBLEScanResults getResults();
void erase(NimBLEAddress address); void erase(const NimBLEAddress &address);
private: private:
@ -82,6 +89,6 @@ private:
uint32_t m_duration; uint32_t m_duration;
}; };
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */
#endif /* COMPONENTS_NIMBLE_SCAN_H_ */ #endif /* COMPONENTS_NIMBLE_SCAN_H_ */

View File

@ -15,6 +15,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#include "NimBLEServer.h" #include "NimBLEServer.h"
#include "NimBLE2902.h" #include "NimBLE2902.h"
#include "NimBLEUtils.h" #include "NimBLEUtils.h"
@ -62,7 +65,7 @@ NimBLEService* NimBLEServer::createService(const char* uuid) {
* @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 With multiple services with the same UUID we need to provide inst_id value different for each service.
* @return A reference to the new service object. * @return A reference to the new service object.
*/ */
NimBLEService* NimBLEServer::createService(NimBLEUUID uuid, uint32_t numHandles, uint8_t inst_id) { NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid, uint32_t numHandles, uint8_t inst_id) {
NIMBLE_LOGD(LOG_TAG, ">> createService - %s", uuid.toString().c_str()); NIMBLE_LOGD(LOG_TAG, ">> createService - %s", uuid.toString().c_str());
// Check that a service with the supplied UUID does not already exist. // Check that a service with the supplied UUID does not already exist.
@ -95,7 +98,7 @@ NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid) {
* @param [in] uuid The UUID of the new service. * @param [in] uuid The UUID of the new service.
* @return A reference to the service object. * @return A reference to the service object.
*/ */
NimBLEService* NimBLEServer::getServiceByUUID(NimBLEUUID uuid) { NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID &uuid) {
return m_serviceMap.getByUUID(uuid); return m_serviceMap.getByUUID(uuid);
} }
@ -605,4 +608,6 @@ void NimBLEServer::onHostReset() {
} }
*/ */
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#endif // CONFIG_BT_ENABLED #endif // CONFIG_BT_ENABLED

View File

@ -17,6 +17,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#include "NimBLEAddress.h" #include "NimBLEAddress.h"
#include "NimBLEUUID.h" #include "NimBLEUUID.h"
#include "NimBLEAdvertising.h" #include "NimBLEAdvertising.h"
@ -24,7 +27,6 @@
#include "NimBLESecurity.h" #include "NimBLESecurity.h"
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include <map> #include <map>
class NimBLEService; class NimBLEService;
@ -46,10 +48,10 @@ class NimBLEServiceMap {
public: public:
// NimBLEService* getByHandle(uint16_t handle); // NimBLEService* getByHandle(uint16_t handle);
NimBLEService* getByUUID(const char* uuid); NimBLEService* getByUUID(const char* uuid);
NimBLEService* getByUUID(NimBLEUUID uuid, uint8_t inst_id = 0); NimBLEService* getByUUID(const NimBLEUUID &uuid, uint8_t inst_id = 0);
// void setByHandle(uint16_t handle, NimBLEService* service); // void setByHandle(uint16_t handle, NimBLEService* service);
void setByUUID(const char* uuid, NimBLEService* service); void setByUUID(const char* uuid, NimBLEService* service);
void setByUUID(NimBLEUUID uuid, NimBLEService* service); void setByUUID(const NimBLEUUID &uuid, NimBLEService* service);
std::string toString(); std::string toString();
NimBLEService* getFirst(); NimBLEService* getFirst();
NimBLEService* getNext(); NimBLEService* getNext();
@ -70,7 +72,7 @@ class NimBLEServer {
public: public:
uint32_t getConnectedCount(); uint32_t getConnectedCount();
NimBLEService* createService(const char* uuid); NimBLEService* createService(const char* uuid);
NimBLEService* createService(NimBLEUUID uuid, uint32_t numHandles=15, uint8_t inst_id=0); NimBLEService* createService(const NimBLEUUID &uuid, uint32_t numHandles=15, uint8_t inst_id=0);
NimBLEAdvertising* getAdvertising(); NimBLEAdvertising* getAdvertising();
void setCallbacks(NimBLEServerCallbacks* pCallbacks); void setCallbacks(NimBLEServerCallbacks* pCallbacks);
void startAdvertising(); void startAdvertising();
@ -78,7 +80,7 @@ public:
void start(); void start();
// void removeService(BLEService* service); // void removeService(BLEService* service);
NimBLEService* getServiceByUUID(const char* uuid); NimBLEService* getServiceByUUID(const char* uuid);
NimBLEService* getServiceByUUID(NimBLEUUID uuid); NimBLEService* getServiceByUUID(const NimBLEUUID &uuid);
int disconnect(uint16_t connID, uint8_t reason = BLE_ERR_REM_USER_CONN_TERM); int disconnect(uint16_t connID, uint8_t reason = BLE_ERR_REM_USER_CONN_TERM);
// bool connect(BLEAddress address); // bool connect(BLEAddress address);
void updateConnParams(uint16_t conn_handle, void updateConnParams(uint16_t conn_handle,
@ -150,5 +152,6 @@ public:
}; // BLEServerCallbacks }; // BLEServerCallbacks
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */
#endif /* MAIN_NIMBLESERVER_H_ */ #endif /* MAIN_NIMBLESERVER_H_ */

View File

@ -17,6 +17,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#include "NimBLEService.h" #include "NimBLEService.h"
#include "NimBLEUtils.h" #include "NimBLEUtils.h"
#include "NimBLELog.h" #include "NimBLELog.h"
@ -43,7 +46,7 @@ NimBLEService::NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer
* @param [in] uuid The UUID of the service. * @param [in] uuid The UUID of the service.
* @param [in] numHandles The maximum number of handles associated with the service. * @param [in] numHandles The maximum number of handles associated with the service.
*/ */
NimBLEService::NimBLEService(NimBLEUUID uuid, uint16_t numHandles, NimBLEServer* pServer) { NimBLEService::NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLEServer* pServer) {
m_uuid = uuid; m_uuid = uuid;
m_handle = NULL_HANDLE; m_handle = NULL_HANDLE;
m_pServer = pServer; m_pServer = pServer;
@ -111,8 +114,9 @@ bool NimBLEService::start() {
if(numDscs) { if(numDscs) {
// skip 2902 as it's automatically created by NimBLE // skip 2902 as it's automatically created by NimBLE
// if Indicate or Notify flags are set // if Indicate or Notify flags are set
if((pCharacteristic->m_properties & BLE_GATT_CHR_F_INDICATE) || if(((pCharacteristic->m_properties & BLE_GATT_CHR_F_INDICATE) ||
(pCharacteristic->m_properties & BLE_GATT_CHR_F_NOTIFY)) { (pCharacteristic->m_properties & BLE_GATT_CHR_F_NOTIFY)) &&
pCharacteristic->getDescriptorByUUID("2902") != nullptr) {
numDscs--; numDscs--;
} }
} }
@ -247,7 +251,7 @@ NimBLECharacteristic* NimBLEService::createCharacteristic(const char* uuid, uint
* @param [in] properties - The properties of the characteristic. * @param [in] properties - The properties of the characteristic.
* @return The new BLE characteristic. * @return The new BLE characteristic.
*/ */
NimBLECharacteristic* NimBLEService::createCharacteristic(NimBLEUUID uuid, uint32_t properties) { NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid, uint32_t properties) {
NimBLECharacteristic* pCharacteristic = new NimBLECharacteristic(uuid, properties, this); NimBLECharacteristic* pCharacteristic = new NimBLECharacteristic(uuid, properties, this);
addCharacteristic(pCharacteristic); addCharacteristic(pCharacteristic);
//pCharacteristic->executeCreate(this); //pCharacteristic->executeCreate(this);
@ -260,7 +264,7 @@ NimBLECharacteristic* NimBLEService::getCharacteristic(const char* uuid) {
} }
NimBLECharacteristic* NimBLEService::getCharacteristic(NimBLEUUID uuid) { NimBLECharacteristic* NimBLEService::getCharacteristic(const NimBLEUUID &uuid) {
return m_characteristicMap.getByUUID(uuid); return m_characteristicMap.getByUUID(uuid);
} }
@ -290,4 +294,5 @@ NimBLEServer* NimBLEService::getServer() {
return m_pServer; return m_pServer;
} // getServer } // getServer
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#endif // CONFIG_BT_ENABLED #endif // CONFIG_BT_ENABLED

View File

@ -17,6 +17,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#include "NimBLECharacteristic.h" #include "NimBLECharacteristic.h"
#include "NimBLEServer.h" #include "NimBLEServer.h"
#include "NimBLEUUID.h" #include "NimBLEUUID.h"
@ -32,10 +35,10 @@ class NimBLECharacteristic;
class NimBLECharacteristicMap { class NimBLECharacteristicMap {
public: public:
void setByUUID(NimBLECharacteristic* pCharacteristic, const char* uuid); void setByUUID(NimBLECharacteristic* pCharacteristic, const char* uuid);
void setByUUID(NimBLECharacteristic* pCharacteristic, NimBLEUUID uuid); void setByUUID(NimBLECharacteristic* pCharacteristic, const NimBLEUUID &uuid);
void setByHandle(uint16_t handle, NimBLECharacteristic* pCharacteristic); void setByHandle(uint16_t handle, NimBLECharacteristic* pCharacteristic);
NimBLECharacteristic* getByUUID(const char* uuid); NimBLECharacteristic* getByUUID(const char* uuid);
NimBLECharacteristic* getByUUID(NimBLEUUID uuid); NimBLECharacteristic* getByUUID(const NimBLEUUID &uuid);
NimBLECharacteristic* getByHandle(uint16_t handle); NimBLECharacteristic* getByHandle(uint16_t handle);
NimBLECharacteristic* getFirst(); NimBLECharacteristic* getFirst();
NimBLECharacteristic* getNext(); NimBLECharacteristic* getNext();
@ -59,13 +62,13 @@ public:
uint32_t properties = NIMBLE_PROPERTY::READ | uint32_t properties = NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE); NIMBLE_PROPERTY::WRITE);
NimBLECharacteristic* createCharacteristic(NimBLEUUID uuid, NimBLECharacteristic* createCharacteristic(const NimBLEUUID &uuid,
uint32_t properties = NIMBLE_PROPERTY::READ | uint32_t properties = NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE); NIMBLE_PROPERTY::WRITE);
void dump(); void dump();
NimBLECharacteristic* getCharacteristic(const char* uuid); NimBLECharacteristic* getCharacteristic(const char* uuid);
NimBLECharacteristic* getCharacteristic(NimBLEUUID uuid); NimBLECharacteristic* getCharacteristic(const NimBLEUUID &uuid);
NimBLEUUID getUUID(); NimBLEUUID getUUID();
NimBLEServer* getServer(); NimBLEServer* getServer();
bool start(); bool start();
@ -76,7 +79,7 @@ public:
private: private:
NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer); NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer);
NimBLEService(NimBLEUUID uuid, uint16_t numHandles, NimBLEServer* pServer); NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLEServer* pServer);
friend class NimBLEServer; friend class NimBLEServer;
friend class NimBLEDevice; friend class NimBLEDevice;
@ -92,5 +95,6 @@ private:
}; // BLEService }; // BLEService
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#endif // CONFIG_BT_ENABLED #endif // CONFIG_BT_ENABLED
#endif /* MAIN_NIMBLESERVICE_H_ */ #endif /* MAIN_NIMBLESERVICE_H_ */

View File

@ -14,6 +14,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#include "NimBLEService.h" #include "NimBLEService.h"
@ -31,7 +34,7 @@ NimBLEService* NimBLEServiceMap::getByUUID(const char* uuid) {
* @param [in] UUID The UUID to look up the service. * @param [in] UUID The UUID to look up the service.
* @return The characteristic. * @return The characteristic.
*/ */
NimBLEService* NimBLEServiceMap::getByUUID(NimBLEUUID uuid, uint8_t inst_id) { NimBLEService* NimBLEServiceMap::getByUUID(const NimBLEUUID &uuid, uint8_t inst_id) {
for (auto &myPair : m_uuidMap) { for (auto &myPair : m_uuidMap) {
if (myPair.first->getUUID().equals(uuid)) { if (myPair.first->getUUID().equals(uuid)) {
return myPair.first; return myPair.first;
@ -59,7 +62,7 @@ NimBLEService* NimBLEServiceMap::getByHandle(uint16_t handle) {
* @param [in] characteristic The service to cache. * @param [in] characteristic The service to cache.
* @return N/A. * @return N/A.
*/ */
void NimBLEServiceMap::setByUUID(NimBLEUUID uuid, NimBLEService* service) { void NimBLEServiceMap::setByUUID(const NimBLEUUID &uuid, NimBLEService* service) {
m_uuidMap.insert(std::pair<NimBLEService*, std::string>(service, uuid.toString())); m_uuidMap.insert(std::pair<NimBLEService*, std::string>(service, uuid.toString()));
} // setByUUID } // setByUUID
@ -105,6 +108,7 @@ NimBLEService* NimBLEServiceMap::getFirst() {
return pRet; return pRet;
} // getFirst } // getFirst
/** /**
* @brief Get the next service in the map. * @brief Get the next service in the map.
* @return The next service in the map. * @return The next service in the map.
@ -116,6 +120,7 @@ NimBLEService* NimBLEServiceMap::getNext() {
return pRet; return pRet;
} // getNext } // getNext
/** /**
* @brief Removes service from maps. * @brief Removes service from maps.
* @return N/A. * @return N/A.
@ -125,6 +130,7 @@ void NimBLEServiceMap::removeService(NimBLEService* service) {
m_uuidMap.erase(service); m_uuidMap.erase(service);
} // removeService } // removeService
/** /**
* @brief Returns the amount of registered services * @brief Returns the amount of registered services
* @return amount of registered services * @return amount of registered services
@ -134,4 +140,6 @@ int NimBLEServiceMap::getRegisteredServiceCount(){
return m_uuidMap.size(); return m_uuidMap.size();
} }
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */

View File

@ -18,6 +18,8 @@
#include "NimBLEUUID.h" #include "NimBLEUUID.h"
#include "NimBLELog.h" #include "NimBLELog.h"
#include <algorithm>
static const char* LOG_TAG = "NimBLEUUID"; static const char* LOG_TAG = "NimBLEUUID";
@ -38,54 +40,29 @@ static const char* LOG_TAG = "NimBLEUUID";
* *
* @param [in] value The string to build a UUID from. * @param [in] value The string to build a UUID from.
*/ */
NimBLEUUID::NimBLEUUID(std::string value) { NimBLEUUID::NimBLEUUID(const std::string &value) {
m_valueSet = true; m_valueSet = true;
if (value.length() == 4) { if (value.length() == 4) {
m_uuid.u.type = BLE_UUID_TYPE_16; m_uuid.u.type = BLE_UUID_TYPE_16;
m_uuid.u16.value = 0; m_uuid.u16.value = strtoul(value.c_str(), NULL, 16);
for(int i=0;i<value.length();){
uint8_t MSB = value.c_str()[i];
uint8_t LSB = value.c_str()[i+1];
if(MSB > '9') MSB -= 7;
if(LSB > '9') LSB -= 7;
m_uuid.u16.value += (((MSB&0x0F) <<4) | (LSB & 0x0F))<<(2-i)*4;
i+=2;
}
} }
else if (value.length() == 8) { else if (value.length() == 8) {
m_uuid.u.type = BLE_UUID_TYPE_32; m_uuid.u.type = BLE_UUID_TYPE_32;
m_uuid.u32.value = 0; m_uuid.u32.value = strtoul(value.c_str(), NULL, 16);
for(int i=0;i<value.length();){
uint8_t MSB = value.c_str()[i];
uint8_t LSB = value.c_str()[i+1];
if(MSB > '9') MSB -= 7;
if(LSB > '9') LSB -= 7;
m_uuid.u32.value += (((MSB&0x0F) <<4) | (LSB & 0x0F))<<(6-i)*4;
i+=2;
} }
} else if (value.length() == 16) {
else if (value.length() == 16) { // how we can have 16 byte length string reprezenting 128 bit uuid??? needs to be investigated (lack of time) *this = NimBLEUUID((uint8_t*)value.data(), 16, true);
m_uuid.u.type = BLE_UUID_TYPE_128;
NimBLEUtils::memrcpy(m_uuid.u128.value, (uint8_t*)value.data(), 16);
} }
else if (value.length() == 36) { else if (value.length() == 36) {
// If the length of the string is 36 bytes then we will assume it is a long hex string in // If the length of the string is 36 bytes then we will assume it is a long hex string in
// UUID format. // UUID format.
m_uuid.u.type = BLE_UUID_TYPE_128; char * position = const_cast<char *>(value.c_str());
int n = 0; uint32_t first = strtoul(position, &position, 16);
for(int i=0;i<value.length();){ uint16_t second = strtoul(position + 1, &position, 16);
if(value.c_str()[i] == '-') uint16_t third = strtoul(position + 1, &position, 16);
i++; uint16_t fourth = strtoul(position + 1, &position, 16);
uint8_t MSB = value.c_str()[i]; uint64_t fifth = strtoull(position + 1, NULL, 16);
uint8_t LSB = value.c_str()[i+1]; *this = NimBLEUUID(first, second, third, (uint64_t(fourth) << 48) + fifth);
if(MSB > '9') MSB -= 7;
if(LSB > '9') LSB -= 7;
m_uuid.u128.value[15-n++] = ((MSB&0x0F) <<4) | (LSB & 0x0F);
i+=2;
}
} }
else { else {
NIMBLE_LOGE(LOG_TAG,"ERROR: UUID value not 2, 4, 16 or 36 bytes"); NIMBLE_LOGE(LOG_TAG,"ERROR: UUID value not 2, 4, 16 or 36 bytes");
@ -101,7 +78,7 @@ static const char* LOG_TAG = "NimBLEUUID";
* @param [in] size The size of the data. * @param [in] size The size of the data.
* @param [in] msbFirst Is the MSB first in pData memory? * @param [in] msbFirst Is the MSB first in pData memory?
*/ */
NimBLEUUID::NimBLEUUID(uint8_t* pData, size_t size, bool msbFirst) { NimBLEUUID::NimBLEUUID(const uint8_t* pData, size_t size, bool msbFirst) {
/*** TODO: change this to use the Nimble function for various lenght UUIDs: /*** TODO: change this to use the Nimble function for various lenght UUIDs:
int ble_uuid_init_from_buf(ble_uuid_any_t *uuid, const void *buf, size_t len); int ble_uuid_init_from_buf(ble_uuid_any_t *uuid, const void *buf, size_t len);
***/ ***/
@ -110,8 +87,9 @@ NimBLEUUID::NimBLEUUID(uint8_t* pData, size_t size, bool msbFirst) {
return; return;
} }
m_uuid.u.type = BLE_UUID_TYPE_128; m_uuid.u.type = BLE_UUID_TYPE_128;
if (msbFirst) { if (msbFirst) {
NimBLEUtils::memrcpy(m_uuid.u128.value, pData, 16); std::reverse_copy(pData, pData + 16, m_uuid.u128.value);
} else { } else {
memcpy(m_uuid.u128.value, pData, 16); memcpy(m_uuid.u128.value, pData, 16);
} }
@ -148,14 +126,33 @@ NimBLEUUID::NimBLEUUID(uint32_t uuid) {
* *
* @param [in] uuid The native UUID. * @param [in] uuid The native UUID.
*/ */
NimBLEUUID::NimBLEUUID(const ble_uuid128_t* uuid) {
NimBLEUUID::NimBLEUUID(ble_uuid128_t* uuid) {
m_uuid.u.type = BLE_UUID_TYPE_128; m_uuid.u.type = BLE_UUID_TYPE_128;
memcpy(m_uuid.u128.value, uuid->value, 16); memcpy(m_uuid.u128.value, uuid->value, 16);
m_valueSet = true; m_valueSet = true;
} // NimBLEUUID } // NimBLEUUID
/**
* @brief Create a UUID from the 128bit value using hex parts instead of string,
* instead of BLEUUID("ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6"), it becomes
* BLEUUID(0xebe0ccb0, 0x7a0a, 0x4b0c, 0x8a1a6ff2997da3a6)
*
* @param [in] first The first 32bit of the UUID.
* @param [in] second The next 16bit of the UUID.
* @param [in] third The next 16bit of the UUID.
* @param [in] fourth The last 64bit of the UUID, combining the last 2 parts of the string equivalent
*/
NimBLEUUID::NimBLEUUID(uint32_t first, uint16_t second, uint16_t third, uint64_t fourth) {
m_uuid.u.type = BLE_UUID_TYPE_128;
memcpy(m_uuid.u128.value + 12, &first, 4);
memcpy(m_uuid.u128.value + 10, &second, 2);
memcpy(m_uuid.u128.value + 8, &third, 2);
memcpy(m_uuid.u128.value, &fourth, 8);
m_valueSet = true;
}
NimBLEUUID::NimBLEUUID() { NimBLEUUID::NimBLEUUID() {
m_valueSet = false; m_valueSet = false;
} // NimBLEUUID } // NimBLEUUID
@ -165,7 +162,7 @@ NimBLEUUID::NimBLEUUID() {
* @brief Get the number of bits in this uuid. * @brief Get the number of bits in this uuid.
* @return The number of bits in the UUID. One of 16, 32 or 128. * @return The number of bits in the UUID. One of 16, 32 or 128.
*/ */
uint8_t NimBLEUUID::bitSize() { uint8_t NimBLEUUID::bitSize() const {
if (!m_valueSet) return 0; if (!m_valueSet) return 0;
return m_uuid.u.type; return m_uuid.u.type;
} // bitSize } // bitSize
@ -177,11 +174,8 @@ uint8_t NimBLEUUID::bitSize() {
* @param [in] uuid The UUID to compare against. * @param [in] uuid The UUID to compare against.
* @return True if the UUIDs are equal and false otherwise. * @return True if the UUIDs are equal and false otherwise.
*/ */
bool NimBLEUUID::equals(NimBLEUUID uuid) { bool NimBLEUUID::equals(const NimBLEUUID &uuid) const {
if(ble_uuid_cmp(&m_uuid.u, &uuid.getNative()->u) == 0){ return *this == uuid;
return true;
}
return false;
} }
@ -194,8 +188,7 @@ bool NimBLEUUID::equals(NimBLEUUID uuid) {
* NNNNNNNN * NNNNNNNN
* <UUID> * <UUID>
*/ */
NimBLEUUID NimBLEUUID::fromString(const std::string &_uuid) {
NimBLEUUID NimBLEUUID::fromString(std::string _uuid) {
uint8_t start = 0; uint8_t start = 0;
if (strstr(_uuid.c_str(), "0x") != nullptr) { // If the string starts with 0x, skip those characters. if (strstr(_uuid.c_str(), "0x") != nullptr) { // If the string starts with 0x, skip those characters.
start = 2; start = 2;
@ -220,7 +213,7 @@ NimBLEUUID NimBLEUUID::fromString(std::string _uuid) {
* *
* @return The native UUID value or NULL if not set. * @return The native UUID value or NULL if not set.
*/ */
ble_uuid_any_t* NimBLEUUID::getNative() { const ble_uuid_any_t* NimBLEUUID::getNative() const {
if (m_valueSet == false) { if (m_valueSet == false) {
NIMBLE_LOGD(LOG_TAG,"<< Return of un-initialized UUID!"); NIMBLE_LOGD(LOG_TAG,"<< Return of un-initialized UUID!");
return nullptr; return nullptr;
@ -235,47 +228,20 @@ ble_uuid_any_t* NimBLEUUID::getNative() {
* A UUID can be internally represented as 16bit, 32bit or the full 128bit. This method * A UUID can be internally represented as 16bit, 32bit or the full 128bit. This method
* will convert 16 or 32 bit representations to the full 128bit. * will convert 16 or 32 bit representations to the full 128bit.
*/ */
NimBLEUUID NimBLEUUID::to128() { const NimBLEUUID &NimBLEUUID::to128() {
// If we either don't have a value or are already a 128 bit UUID, nothing further to do. // If we either don't have a value or are already a 128 bit UUID, nothing further to do.
if (!m_valueSet || m_uuid.u.type == BLE_UUID_TYPE_128) { if (!m_valueSet || m_uuid.u.type == BLE_UUID_TYPE_128) {
return *this; return *this;
} }
// If we are 16 bit or 32 bit, then set the 4 bytes of the variable part of the UUID. // If we are 16 bit or 32 bit, then set the other bytes of the UUID.
if (m_uuid.u.type == BLE_UUID_TYPE_16) { if (m_uuid.u.type == BLE_UUID_TYPE_16) {
uint16_t temp = m_uuid.u16.value; *this = NimBLEUUID(m_uuid.u16.value, 0x0000, 0x1000, 0x800000805f9b34fb);
m_uuid.u128.value[15] = 0;
m_uuid.u128.value[14] = 0;
m_uuid.u128.value[13] = (temp >> 8) & 0xff;
m_uuid.u128.value[12] = temp & 0xff;
} }
else if (m_uuid.u.type == BLE_UUID_TYPE_32) { else if (m_uuid.u.type == BLE_UUID_TYPE_32) {
uint32_t temp = m_uuid.u32.value; *this = NimBLEUUID(m_uuid.u32.value, 0x0000, 0x1000, 0x800000805f9b34fb);
m_uuid.u128.value[15] = (temp >> 24) & 0xff;
m_uuid.u128.value[14] = (temp >> 16) & 0xff;
m_uuid.u128.value[13] = (temp >> 8) & 0xff;
m_uuid.u128.value[12] = temp & 0xff;
} }
// Set the fixed parts of the UUID.
m_uuid.u128.value[11] = 0x00;
m_uuid.u128.value[10] = 0x00;
m_uuid.u128.value[9] = 0x10;
m_uuid.u128.value[8] = 0x00;
m_uuid.u128.value[7] = 0x80;
m_uuid.u128.value[6] = 0x00;
m_uuid.u128.value[5] = 0x00;
m_uuid.u128.value[4] = 0x80;
m_uuid.u128.value[3] = 0x5f;
m_uuid.u128.value[2] = 0x9b;
m_uuid.u128.value[1] = 0x34;
m_uuid.u128.value[0] = 0xfb;
m_uuid.u.type = BLE_UUID_TYPE_128;
return *this; return *this;
} // to128 } // to128
@ -290,12 +256,32 @@ NimBLEUUID NimBLEUUID::to128() {
* *
* @return A string representation of the UUID. * @return A string representation of the UUID.
*/ */
std::string NimBLEUUID::toString() { std::string NimBLEUUID::toString() const {
if (!m_valueSet) return "<NULL>"; // If we have no value, nothing to format. return std::string(*this);
} // toString
bool NimBLEUUID::operator ==(const NimBLEUUID & rhs) const {
if(m_valueSet && rhs.m_valueSet) {
return ble_uuid_cmp(&m_uuid.u, &rhs.m_uuid.u) == 0;
}
return m_valueSet == rhs.m_valueSet;
}
bool NimBLEUUID::operator !=(const NimBLEUUID & rhs) const {
return !this->operator==(rhs);
}
NimBLEUUID::operator std::string() const {
if (!m_valueSet) return std::string(); // If we have no value, nothing to format.
char buf[BLE_UUID_STR_LEN]; char buf[BLE_UUID_STR_LEN];
return ble_uuid_to_str(&m_uuid.u, buf); return ble_uuid_to_str(&m_uuid.u, buf);
} // toString }
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */

View File

@ -30,18 +30,23 @@
*/ */
class NimBLEUUID { class NimBLEUUID {
public: public:
NimBLEUUID(std::string uuid); NimBLEUUID(const std::string &uuid);
NimBLEUUID(uint16_t uuid); NimBLEUUID(uint16_t uuid);
NimBLEUUID(uint32_t uuid); NimBLEUUID(uint32_t uuid);
NimBLEUUID(ble_uuid128_t* uuid); NimBLEUUID(const ble_uuid128_t* uuid);
NimBLEUUID(uint8_t* pData, size_t size, bool msbFirst); NimBLEUUID(const uint8_t* pData, size_t size, bool msbFirst);
NimBLEUUID(uint32_t first, uint16_t second, uint16_t third, uint64_t fourth);
NimBLEUUID(); NimBLEUUID();
uint8_t bitSize(); // Get the number of bits in this uuid. uint8_t bitSize() const; // Get the number of bits in this uuid.
bool equals(NimBLEUUID uuid); bool equals(const NimBLEUUID &uuid) const;
ble_uuid_any_t* getNative(); const ble_uuid_any_t* getNative() const;
NimBLEUUID to128(); const NimBLEUUID & to128();
std::string toString(); std::string toString() const;
static NimBLEUUID fromString(std::string uuid); // Create a NimBLEUUID from a string static NimBLEUUID fromString(const std::string &uuid); // Create a NimBLEUUID from a string
bool operator ==(const NimBLEUUID & rhs) const;
bool operator !=(const NimBLEUUID & rhs) const;
operator std::string() const;
private: private:
ble_uuid_any_t m_uuid; // The underlying UUID structure that this class wraps. ble_uuid_any_t m_uuid; // The underlying UUID structure that this class wraps.

View File

@ -11,38 +11,10 @@
#include "NimBLEUtils.h" #include "NimBLEUtils.h"
#include "NimBLELog.h" #include "NimBLELog.h"
#include "nimconfig.h"
static const char* LOG_TAG = "NimBLEUtils"; static const char* LOG_TAG = "NimBLEUtils";
/**
* @brief Copy memory from source to target but in reverse order.
*
* When we move memory from one location it is normally:
*
* ```
* [0][1][2]...[n] -> [0][1][2]...[n]
* ```
*
* with this function, it is:
*
* ```
* [0][1][2]...[n] -> [n][n-1][n-2]...[0]
* ```
*
* @param [in] target The target of the copy
* @param [in] source The source of the copy
* @param [in] size The number of bytes to copy
*/
void NimBLEUtils::memrcpy(uint8_t* target, uint8_t* source, uint32_t size) {
assert(size > 0);
target += (size - 1); // Point target to the last byte of the target data
while (size > 0) {
*target = *source;
target--;
source++;
size--;
}
} // memrcpy
int NimBLEUtils::checkConnParams(ble_gap_conn_params* params) { int NimBLEUtils::checkConnParams(ble_gap_conn_params* params) {
/* Check connection interval min */ /* Check connection interval min */
@ -78,6 +50,7 @@ int NimBLEUtils::checkConnParams(ble_gap_conn_params* params) {
const char* NimBLEUtils::returnCodeToString(int rc) { const char* NimBLEUtils::returnCodeToString(int rc) {
#if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT)
switch(rc) { switch(rc) {
case 0: case 0:
return "SUCCESS"; return "SUCCESS";
@ -355,19 +328,22 @@ const char* NimBLEUtils::returnCodeToString(int rc) {
return "Pairing over the LE transport failed - Pairing Request sent over the BR/EDR transport in process."; return "Pairing over the LE transport failed - Pairing Request sent over the BR/EDR transport in process.";
case (0x0500+BLE_SM_ERR_CROSS_TRANS ): case (0x0500+BLE_SM_ERR_CROSS_TRANS ):
return "BR/EDR Link Key generated on the BR/EDR transport cannot be used to derive and distribute keys for the LE transport."; return "BR/EDR Link Key generated on the BR/EDR transport cannot be used to derive and distribute keys for the LE transport.";
default: default:
return "Unknown"; return "Unknown";
} }
#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT)
return "";
#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT)
} }
/** /**
* @brief Convert the BLE Advertising Data flags to a string. * @brief Convert the BLE Advertising Data flags to a string.
* @param adFlags The flags to convert * @param adFlags The flags to convert
* @return std::string A string representation of the advertising flags. * @return std::string A string representation of the advertising flags.
*/ */
const char* NimBLEUtils::advTypeToString(uint8_t advType) { const char* NimBLEUtils::advTypeToString(uint8_t advType) {
#if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT)
switch(advType) { switch(advType) {
case BLE_HCI_ADV_TYPE_ADV_IND : //0 case BLE_HCI_ADV_TYPE_ADV_IND : //0
return "Undirected - Connectable / Scannable"; return "Undirected - Connectable / Scannable";
@ -382,7 +358,9 @@ const char* NimBLEUtils::advTypeToString(uint8_t advType) {
default: default:
return "Unknown flag"; return "Unknown flag";
} }
#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT)
return "";
#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT)
} // adFlagsToString } // adFlagsToString
@ -394,7 +372,7 @@ const char* NimBLEUtils::advTypeToString(uint8_t advType) {
* @param [in] length The length of the data to convert. * @param [in] length The length of the data to convert.
* @return A pointer to the formatted buffer. * @return A pointer to the formatted buffer.
*/ */
char* NimBLEUtils::buildHexData(uint8_t* target, uint8_t* source, uint8_t length) { char* NimBLEUtils::buildHexData(uint8_t* target, const uint8_t* source, uint8_t length) {
// Guard against too much data. // Guard against too much data.
if (length > 100) length = 100; if (length > 100) length = 100;
@ -422,17 +400,20 @@ char* NimBLEUtils::buildHexData(uint8_t* target, uint8_t* source, uint8_t length
} // buildHexData } // buildHexData
void NimBLEUtils::dumpGapEvent(ble_gap_event *event, void *arg){ void NimBLEUtils::dumpGapEvent(ble_gap_event *event, void *arg){
#if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT)
NIMBLE_LOGD(LOG_TAG, "Received a GAP event: %s", gapEventToString(event->type)); NIMBLE_LOGD(LOG_TAG, "Received a GAP event: %s", gapEventToString(event->type));
#endif
} }
/** /**
* @brief Convert a BT GAP event type to a string representation. * @brief Convert a BT GAP event type to a string representation.
* @param [in] eventType The type of event. * @param [in] eventType The type of event.
* @return A string representation of the event type. * @return A string representation of the event type.
*/ */
const char* NimBLEUtils::gapEventToString(uint8_t eventType) { const char* NimBLEUtils::gapEventToString(uint8_t eventType) {
#if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT)
switch (eventType) { switch (eventType) {
case BLE_GAP_EVENT_CONNECT : //0 case BLE_GAP_EVENT_CONNECT : //0
return "BLE_GAP_EVENT_CONNECT "; return "BLE_GAP_EVENT_CONNECT ";
@ -507,6 +488,9 @@ const char* NimBLEUtils::gapEventToString(uint8_t eventType) {
NIMBLE_LOGD(LOG_TAG, "gapEventToString: Unknown event type %d 0x%.2x", eventType, eventType); NIMBLE_LOGD(LOG_TAG, "gapEventToString: Unknown event type %d 0x%.2x", eventType, eventType);
return "Unknown event type"; return "Unknown event type";
} }
#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT)
return "";
#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT)
} // gapEventToString } // gapEventToString

View File

@ -25,10 +25,9 @@ class NimBLEUtils {
public: public:
static void dumpGapEvent(ble_gap_event *event, void *arg); static void dumpGapEvent(ble_gap_event *event, void *arg);
static const char* gapEventToString(uint8_t eventType); static const char* gapEventToString(uint8_t eventType);
static char* buildHexData(uint8_t* target, uint8_t* source, uint8_t length); static char* buildHexData(uint8_t* target, const uint8_t* source, uint8_t length);
static const char* advTypeToString(uint8_t advType); static const char* advTypeToString(uint8_t advType);
static const char* returnCodeToString(int rc); static const char* returnCodeToString(int rc);
static void memrcpy(uint8_t* target, uint8_t* source, uint32_t size);
static int checkConnParams(ble_gap_conn_params* params); static int checkConnParams(ble_gap_conn_params* params);
}; };

View File

@ -14,6 +14,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#include "NimBLEValue.h" #include "NimBLEValue.h"
#include "NimBLELog.h" #include "NimBLELog.h"
@ -31,7 +34,7 @@ NimBLEValue::NimBLEValue() {
* The accumulation is a growing set of data that is added to until a commit or cancel. * 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. * @param [in] part A message part being added.
*/ */
void NimBLEValue::addPart(std::string part) { void NimBLEValue::addPart(const std::string &part) {
NIMBLE_LOGD(LOG_TAG, ">> addPart: length=%d", part.length()); NIMBLE_LOGD(LOG_TAG, ">> addPart: length=%d", part.length());
m_accumulation += part; m_accumulation += part;
} // addPart } // addPart
@ -43,7 +46,7 @@ void NimBLEValue::addPart(std::string part) {
* @param [in] pData A message part being added. * @param [in] pData A message part being added.
* @param [in] length The number of bytes being added. * @param [in] length The number of bytes being added.
*/ */
void NimBLEValue::addPart(uint8_t* pData, size_t length) { void NimBLEValue::addPart(const uint8_t* pData, size_t length) {
NIMBLE_LOGD(LOG_TAG, ">> addPart: length=%d", length); NIMBLE_LOGD(LOG_TAG, ">> addPart: length=%d", length);
m_accumulation += std::string((char*) pData, length); m_accumulation += std::string((char*) pData, length);
} // addPart } // addPart
@ -122,7 +125,7 @@ void NimBLEValue::setReadOffset(uint16_t readOffset) {
/** /**
* @brief Set the current value. * @brief Set the current value.
*/ */
void NimBLEValue::setValue(std::string value) { void NimBLEValue::setValue(const std::string &value) {
m_value = value; m_value = value;
} // setValue } // setValue
@ -132,9 +135,9 @@ void NimBLEValue::setValue(std::string value) {
* @param [in] pData The data for the current value. * @param [in] pData The data for the current value.
* @param [in] The length of the new current value. * @param [in] The length of the new current value.
*/ */
void NimBLEValue::setValue(uint8_t* pData, size_t length) { void NimBLEValue::setValue(const uint8_t* pData, size_t length) {
m_value = std::string((char*) pData, length); m_value = std::string((char*) pData, length);
} // setValue } // setValue
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#endif // CONFIG_BT_ENABLED #endif // CONFIG_BT_ENABLED

View File

@ -16,6 +16,10 @@
#define MAIN_BLEVALUE_H_ #define MAIN_BLEVALUE_H_
#include "sdkconfig.h" #include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#include <string> #include <string>
/** /**
@ -24,8 +28,8 @@
class NimBLEValue { class NimBLEValue {
public: public:
NimBLEValue(); NimBLEValue();
void addPart(std::string part); void addPart(const std::string &part);
void addPart(uint8_t* pData, size_t length); void addPart(const uint8_t* pData, size_t length);
void cancel(); void cancel();
void commit(); void commit();
uint8_t* getData(); uint8_t* getData();
@ -33,8 +37,8 @@ public:
uint16_t getReadOffset(); uint16_t getReadOffset();
std::string getValue(); std::string getValue();
void setReadOffset(uint16_t readOffset); void setReadOffset(uint16_t readOffset);
void setValue(std::string value); void setValue(const std::string &value);
void setValue(uint8_t* pData, size_t length); void setValue(const uint8_t* pData, size_t length);
private: private:
std::string m_accumulation; std::string m_accumulation;
@ -42,5 +46,7 @@ private:
std::string m_value; std::string m_value;
}; };
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#endif // CONFIG_BT_ENABLED #endif // CONFIG_BT_ENABLED
#endif /* MAIN_BLEVALUE_H_ */ #endif /* MAIN_BLEVALUE_H_ */

View File

@ -1,6 +1,4 @@
/* Modifications copyright (C) 2020 Ryan Powell */
#ifndef __ESP_NIMBLE_CFG__ #ifndef __ESP_NIMBLE_CFG__
#define __ESP_NIMBLE_CFG__ #define __ESP_NIMBLE_CFG__
#include "nimconfig.h" #include "nimconfig.h"
@ -470,7 +468,7 @@
#endif #endif
#ifndef MYNEWT_VAL_BLE_HS_FLOW_CTRL_TX_ON_DISCONNECT #ifndef MYNEWT_VAL_BLE_HS_FLOW_CTRL_TX_ON_DISCONNECT
#define MYNEWT_VAL_BLE_HS_FLOW_CTRL_TX_ON_DISCONNECT CONFIG_BT_NIMBLE_FLOW_CTRL_TX_ON_DISCONNECT #define MYNEWT_VAL_BLE_HS_FLOW_CTRL_TX_ON_DISCONNECT CONFIG_BT_NIMBLE_HS_FLOW_CTRL_TX_ON_DISCONNECT
#endif #endif
#ifndef MYNEWT_VAL_BLE_HS_PHONY_HCI_ACKS #ifndef MYNEWT_VAL_BLE_HS_PHONY_HCI_ACKS

View File

@ -1,4 +1,3 @@
/* /*
* Copyright 2020 Espressif Systems (Shanghai) PTE LTD * Copyright 2020 Espressif Systems (Shanghai) PTE LTD
* *

View File

@ -98,8 +98,8 @@ struct hci_conn_update;
#define BLE_GAP_INITIAL_CONN_LATENCY 0 #define BLE_GAP_INITIAL_CONN_LATENCY 0
#define BLE_GAP_INITIAL_SUPERVISION_TIMEOUT 0x0100 #define BLE_GAP_INITIAL_SUPERVISION_TIMEOUT 0x0100
#define BLE_GAP_INITIAL_CONN_MIN_CE_LEN 0x0010 #define BLE_GAP_INITIAL_CONN_MIN_CE_LEN 0x0000
#define BLE_GAP_INITIAL_CONN_MAX_CE_LEN 0x0300 #define BLE_GAP_INITIAL_CONN_MAX_CE_LEN 0x0000
#define BLE_GAP_ROLE_MASTER 0 #define BLE_GAP_ROLE_MASTER 0
#define BLE_GAP_ROLE_SLAVE 1 #define BLE_GAP_ROLE_SLAVE 1
@ -1783,6 +1783,20 @@ int ble_gap_unpair(const ble_addr_t *peer_addr);
*/ */
int ble_gap_unpair_oldest_peer(void); int ble_gap_unpair_oldest_peer(void);
/**
* Similar to `ble_gap_unpair_oldest_peer()`, except it makes sure that the
* peer received in input parameters is not deleted.
*
* @param peer_addr Address of the peer (not to be deleted)
*
* @return 0 on success;
* A BLE host HCI return code if the controller
* rejected the request;
* A BLE host core return code on unexpected
* error.
*/
int ble_gap_unpair_oldest_except(const ble_addr_t *peer_addr);
#define BLE_GAP_PRIVATE_MODE_NETWORK 0 #define BLE_GAP_PRIVATE_MODE_NETWORK 0
#define BLE_GAP_PRIVATE_MODE_DEVICE 1 #define BLE_GAP_PRIVATE_MODE_DEVICE 1
@ -1886,20 +1900,6 @@ struct ble_gap_event_listener {
SLIST_ENTRY(ble_gap_event_listener) link; SLIST_ENTRY(ble_gap_event_listener) link;
}; };
/**
* Similar to `ble_gap_unpair_oldest_peer()`, except it makes sure that current
* peer is not deleted.
*
* @param peer_addr Address of the current peer (not to be deleted)
*
* @return 0 on success;
* A BLE host HCI return code if the controller
* rejected the request;
* A BLE host core return code on unexpected
* error.
*/
int ble_gap_unpair_oldest_except_curr(const ble_addr_t *curr_peer);
/** /**
* Registers listener for GAP events * Registers listener for GAP events
* *

View File

@ -288,8 +288,6 @@ int ble_store_clear(void);
/*** Utility functions. */ /*** Utility functions. */
int ble_store_clean_old_cccds(const ble_addr_t *curr_peer);
int ble_store_util_bonded_peers(ble_addr_t *out_peer_id_addrs, int ble_store_util_bonded_peers(ble_addr_t *out_peer_id_addrs,
int *out_num_peers, int *out_num_peers,
int max_peers); int max_peers);

View File

@ -330,11 +330,8 @@ static inline void net_buf_simple_restore(struct os_mbuf *buf,
buf->om_len = state->len; buf->om_len = state->len;
} }
static inline void sys_memcpy_swap(void *destination, const void *source, size_t length) static inline void sys_memcpy_swap(void *dst, const void *src, size_t length)
{ {
u8_t *dst = destination;
const u8_t *src = source;
__ASSERT(((src < dst && (src + length) <= dst) || __ASSERT(((src < dst && (src + length) <= dst) ||
(src > dst && (dst + length) <= src)), (src > dst && (dst + length) <= src)),
"Source and destination buffers must not overlap"); "Source and destination buffers must not overlap");
@ -342,7 +339,7 @@ static inline void sys_memcpy_swap(void *destination, const void *source, size_t
src += length - 1; src += length - 1;
for (; length > 0; length--) { for (; length > 0; length--) {
*dst++ = *src--; *((u8_t *)dst++) = *((u8_t *)src--);
} }
} }

View File

@ -41,31 +41,43 @@ modlog_dummy(const char *msg, ...)
#endif #endif
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
/// Uncomment these and comment out the 3 defines below to see NimBLE messages in Arduino. #define MODLOG_ESP_LOCAL(level, ml_msg_, ...) do { \
/* if (LOG_LOCAL_LEVEL >= level) esp_log_write(level, "NimBLE", ml_msg_, ##__VA_ARGS__); \
} while(0)
#ifdef ARDUINO_ARCH_ESP32
#include "nimconfig.h"
#endif
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_BT_NIMBLE_DEBUG)
#define MODLOG_DEBUG(ml_mod_, ml_msg_, ...) \ #define MODLOG_DEBUG(ml_mod_, ml_msg_, ...) \
esp_log_write(ESP_LOG_ERROR, "NimBLE",ml_msg_, ##__VA_ARGS__) MODLOG_ESP_LOCAL(ESP_LOG_ERROR, ml_msg_, ##__VA_ARGS__)
#define MODLOG_INFO(ml_mod_, ml_msg_, ...) \ #define MODLOG_INFO(ml_mod_, ml_msg_, ...) \
esp_log_write(ESP_LOG_ERROR, "NimBLE",ml_msg_, ##__VA_ARGS__) MODLOG_ESP_LOCAL(ESP_LOG_ERROR, ml_msg_, ##__VA_ARGS__)
#define MODLOG_WARN(ml_mod_, ml_msg_, ...) \ #define MODLOG_WARN(ml_mod_, ml_msg_, ...) \
esp_log_write(ESP_LOG_ERROR, "NimBLE",ml_msg_, ##__VA_ARGS__) MODLOG_ESP_LOCAL(ESP_LOG_ERROR, ml_msg_, ##__VA_ARGS__)
*/
#else
#define MODLOG_DEBUG(ml_mod_, ml_msg_, ...) \ #define MODLOG_DEBUG(ml_mod_, ml_msg_, ...) \
esp_log_write(ESP_LOG_DEBUG, "NimBLE",ml_msg_, ##__VA_ARGS__) MODLOG_ESP_LOCAL(ESP_LOG_DEBUG, ml_msg_, ##__VA_ARGS__)
#define MODLOG_INFO(ml_mod_, ml_msg_, ...) \ #define MODLOG_INFO(ml_mod_, ml_msg_, ...) \
esp_log_write(ESP_LOG_INFO, "NimBLE",ml_msg_, ##__VA_ARGS__) MODLOG_ESP_LOCAL(ESP_LOG_INFO, ml_msg_, ##__VA_ARGS__)
#define MODLOG_WARN(ml_mod_, ml_msg_, ...) \ #define MODLOG_WARN(ml_mod_, ml_msg_, ...) \
esp_log_write(ESP_LOG_WARN, "NimBLE",ml_msg_, ##__VA_ARGS__) MODLOG_ESP_LOCAL(ESP_LOG_WARN, ml_msg_, ##__VA_ARGS__)
#endif
#define MODLOG_ERROR(ml_mod_, ml_msg_, ...) \ #define MODLOG_ERROR(ml_mod_, ml_msg_, ...) \
esp_log_write(ESP_LOG_ERROR, "NimBLE",ml_msg_, ##__VA_ARGS__) MODLOG_ESP_LOCAL(ESP_LOG_ERROR, ml_msg_, ##__VA_ARGS__)
#define MODLOG_CRITICAL(ml_mod_, ml_msg_, ...) \ #define MODLOG_CRITICAL(ml_mod_, ml_msg_, ...) \
esp_log_write(ESP_LOG_ERROR, "NimBLE",ml_msg_, ##__VA_ARGS__) MODLOG_ESP_LOCAL(ESP_LOG_ERROR, ml_msg_, ##__VA_ARGS__)
#else #else

View File

@ -119,6 +119,7 @@ void ble_gap_preempt(void);
void ble_gap_preempt_done(void); void ble_gap_preempt_done(void);
void ble_gap_conn_broken(uint16_t conn_handle, int reason); void ble_gap_conn_broken(uint16_t conn_handle, int reason);
void ble_gap_reset_state(int reason);
int32_t ble_gap_timer(void); int32_t ble_gap_timer(void);
int ble_gap_init(void); int ble_gap_init(void);

View File

@ -33,6 +33,10 @@ int ble_hs_id_use_addr(uint8_t addr_type);
void ble_hs_id_reset(void); void ble_hs_id_reset(void);
void ble_hs_id_rnd_reset(void); void ble_hs_id_rnd_reset(void);
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
bool ble_hs_is_rpa(uint8_t *addr, uint8_t addr_type);
int ble_hs_id_set_pseudo_rnd(const uint8_t *);
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -35,6 +35,9 @@ int ble_hs_pvcy_add_entry(const uint8_t *addr, uint8_t addrtype,
const uint8_t *irk); const uint8_t *irk);
int ble_hs_pvcy_ensure_started(void); int ble_hs_pvcy_ensure_started(void);
int ble_hs_pvcy_set_mode(const ble_addr_t *addr, uint8_t priv_mode); int ble_hs_pvcy_set_mode(const ble_addr_t *addr, uint8_t priv_mode);
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
bool ble_hs_pvcy_enabled(void);
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -0,0 +1,108 @@
/*
* Copyright 2020 Espressif Systems (Shanghai) PTE LTD
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifdef __cplusplus
extern "C" {
#endif
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
/*
* An entry in the resolving list.
*/
struct ble_hs_resolv_entry {
uint8_t rl_addr_type;
uint8_t rl_local_irk[16];
uint8_t rl_peer_irk[16];
uint8_t rl_identity_addr[BLE_DEV_ADDR_LEN];
uint8_t rl_pseudo_id[BLE_DEV_ADDR_LEN];
uint8_t rl_local_rpa[BLE_DEV_ADDR_LEN];
uint8_t rl_peer_rpa[BLE_DEV_ADDR_LEN];
};
#if MYNEWT_VAL(BLE_STORE_CONFIG_PERSIST)
/* Persist peer records in NVS. XXX Need to handle this in `store` module */
int ble_store_persist_peer_records(void);
#endif
struct ble_hs_peer_sec {
ble_addr_t peer_addr;
uint8_t irk[16];
uint8_t irk_present: 1;
};
/*
* BLE host peer device record, this helps in storing peer RPA before bond is
* created and IRKs are exchanged.
*/
struct ble_hs_dev_records {
bool rec_used;
uint8_t pseudo_addr[BLE_DEV_ADDR_LEN];
uint8_t rand_addr[BLE_DEV_ADDR_LEN];
uint8_t identity_addr[BLE_DEV_ADDR_LEN];
struct ble_hs_peer_sec peer_sec;
};
/* Add a device to the resolving list */
int ble_hs_resolv_list_add(uint8_t *cmdbuf);
int ble_hs_gen_own_rpa_random(void);
uint8_t *ble_hs_get_rpa_local(void);
/* Remove a device from the resolving list */
int ble_hs_resolv_list_rmv(uint8_t, uint8_t *);
/* Clear the resolving list and peer dev record */
void ble_hs_resolv_list_clear_all(void);
/* Address resolution enable command */
void ble_hs_resolv_enable(bool);
/* Finds 'addr' in resolving list. Doesnt check if address resolution enabled */
struct ble_hs_resolv_entry *
ble_hs_resolv_list_find(uint8_t *addr);
/* Returns true if host based RPA (privacy) is enabled */
bool ble_host_rpa_enabled(void);
/* Searches peer device records (RPA) and fetches matching RL, peer_address
* into input parameters if RL is found */
void
ble_rpa_replace_peer_params_with_rl(uint8_t *, uint8_t *, struct ble_hs_resolv_entry **);
int ble_rpa_resolv_add_peer_rec(uint8_t *);
struct ble_hs_dev_records *ble_rpa_get_peer_dev_records(void);
int ble_rpa_get_num_peer_dev_records(void);
void ble_rpa_set_num_peer_dev_records(int);
int ble_rpa_remove_peer_dev_rec(struct ble_hs_dev_records *);
struct ble_hs_dev_records *ble_rpa_find_peer_dev_rec(uint8_t *);
/* Set the resolvable private address timeout */
int ble_hs_resolv_set_rpa_tmo(uint16_t);
/* Resolve a resolvable private address */
int ble_hs_resolv_rpa(uint8_t *rpa, uint8_t *irk);
/* Initialize resolv*/
void ble_hs_resolv_init(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -399,6 +399,7 @@ int ble_sm_slave_initiate(uint16_t conn_handle);
int ble_sm_enc_initiate(uint16_t conn_handle, uint8_t key_size, int ble_sm_enc_initiate(uint16_t conn_handle, uint8_t key_size,
const uint8_t *ltk, uint16_t ediv, const uint8_t *ltk, uint16_t ediv,
uint64_t rand_val, int auth); uint64_t rand_val, int auth);
int ble_sm_alg_encrypt(uint8_t *key, uint8_t *plaintext, uint8_t *enc_data);
int ble_sm_init(void); int ble_sm_init(void);
#define BLE_SM_LOG_CMD(is_tx, cmd_name, conn_handle, log_cb, cmd) \ #define BLE_SM_LOG_CMD(is_tx, cmd_name, conn_handle, log_cb, cmd) \
@ -419,6 +420,9 @@ int ble_sm_init(void);
#define ble_sm_init() 0 #define ble_sm_init() 0
#define ble_sm_alg_encrypt(key, plaintext, enc_data) \
BLE_HS_ENOTSUP
#endif #endif
struct ble_l2cap_chan *ble_sm_create_chan(uint16_t handle); struct ble_l2cap_chan *ble_sm_create_chan(uint16_t handle);

View File

@ -66,11 +66,10 @@ ble_att_tx(uint16_t conn_handle, struct os_mbuf *txom)
ble_hs_lock(); ble_hs_lock();
ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_ATT, &conn, rc = ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_ATT, &conn,
&chan); &chan);
if (chan == NULL) { if (rc != 0) {
os_mbuf_free_chain(txom); os_mbuf_free_chain(txom);
rc = BLE_HS_ENOTCONN;
} else { } else {
ble_att_truncate_to_mtu(chan, txom); ble_att_truncate_to_mtu(chan, txom);
rc = ble_l2cap_tx(conn, chan, txom); rc = ble_l2cap_tx(conn, chan, txom);

View File

@ -17,8 +17,6 @@
* under the License. * under the License.
*/ */
/* Modifications copyright (C) 2020 Ryan Powell */
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
@ -1855,7 +1853,6 @@ ble_gap_update_timer(void)
ble_hs_unlock(); ble_hs_unlock();
if (entry != NULL) { if (entry != NULL) {
ble_gap_update_notify(conn_handle, BLE_HS_ETIMEOUT);
ble_gap_update_entry_free(entry); ble_gap_update_entry_free(entry);
} }
} while (entry != NULL); } while (entry != NULL);
@ -5303,8 +5300,7 @@ ble_gap_unpair_oldest_peer(void)
} }
if (num_peers == 0) { if (num_peers == 0) {
return BLE_HS_ENOENT; return 0;
//return 0;
} }
rc = ble_gap_unpair(&oldest_peer_id_addr); rc = ble_gap_unpair(&oldest_peer_id_addr);
@ -5316,14 +5312,14 @@ ble_gap_unpair_oldest_peer(void)
} }
int int
ble_gap_unpair_oldest_except_curr(const ble_addr_t *curr_peer) ble_gap_unpair_oldest_except(const ble_addr_t *peer_addr)
{ {
ble_addr_t oldest_peer_id_addr[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
int num_peers; int num_peers;
int rc, i; int rc, i;
rc = ble_store_util_bonded_peers( rc = ble_store_util_bonded_peers(
&oldest_peer_id_addr[0], &num_peers, MYNEWT_VAL(BLE_STORE_MAX_BONDS)); &peer_id_addrs[0], &num_peers, MYNEWT_VAL(BLE_STORE_MAX_BONDS));
if (rc != 0) { if (rc != 0) {
return rc; return rc;
} }
@ -5333,21 +5329,16 @@ ble_gap_unpair_oldest_except_curr(const ble_addr_t *curr_peer)
} }
for (i = 0; i < num_peers; i++) { for (i = 0; i < num_peers; i++) {
if (memcmp(curr_peer, &oldest_peer_id_addr[i], sizeof (ble_addr_t)) != 0) { if (ble_addr_cmp(peer_addr, &peer_id_addrs[i]) != 0) {
break; break;
} }
} }
if (i < num_peers) { if (i >= num_peers) {
rc = ble_gap_unpair(&oldest_peer_id_addr[i]);
if (rc != 0) {
return rc;
}
} else {
return BLE_HS_ENOMEM; return BLE_HS_ENOMEM;
} }
return 0; return ble_gap_unpair(&peer_id_addrs[i]);
} }
void void
@ -5371,7 +5362,8 @@ ble_gap_passkey_event(uint16_t conn_handle,
} }
void void
ble_gap_enc_event(uint16_t conn_handle, int status, int security_restored) ble_gap_enc_event(uint16_t conn_handle, int status,
int security_restored, int bonded)
{ {
#if !NIMBLE_BLE_SM #if !NIMBLE_BLE_SM
return; return;
@ -5387,17 +5379,24 @@ ble_gap_enc_event(uint16_t conn_handle, int status, int security_restored)
ble_gap_event_listener_call(&event); ble_gap_event_listener_call(&event);
ble_gap_call_conn_event_cb(&event, conn_handle); ble_gap_call_conn_event_cb(&event, conn_handle);
/* H2zero mod if (status != 0) {
If bonding is not enabled don't store cccd data return;
if (status == 0) { }
/* If encryption succeded and encryption has been restored for bonded device,
* notify gatt server so it has chance to send notification/indication if needed.
*/ */
if (status == 0 && ble_hs_cfg.sm_bonding) {
/* End mod */
if (security_restored) { if (security_restored) {
ble_gatts_bonding_restored(conn_handle); ble_gatts_bonding_restored(conn_handle);
} else { return;
ble_gatts_bonding_established(conn_handle);
} }
/* If this is fresh pairing and bonding has been established,
* notify gatt server about that so previous subscriptions (before bonding)
* can be stored.
*/
if (bonded) {
ble_gatts_bonding_established(conn_handle);
} }
} }

View File

@ -99,7 +99,7 @@ int ble_gap_rx_l2cap_update_req(uint16_t conn_handle,
struct ble_gap_upd_params *params); struct ble_gap_upd_params *params);
void ble_gap_rx_phy_update_complete(struct hci_le_phy_upd_complete *evt); void ble_gap_rx_phy_update_complete(struct hci_le_phy_upd_complete *evt);
void ble_gap_enc_event(uint16_t conn_handle, int status, void ble_gap_enc_event(uint16_t conn_handle, int status,
int security_restored); int security_restored, int bonded);
void ble_gap_passkey_event(uint16_t conn_handle, void ble_gap_passkey_event(uint16_t conn_handle,
struct ble_gap_passkey_params *passkey_params); struct ble_gap_passkey_params *passkey_params);
void ble_gap_notify_rx_event(uint16_t conn_handle, uint16_t attr_handle, void ble_gap_notify_rx_event(uint16_t conn_handle, uint16_t attr_handle,

View File

@ -1689,8 +1689,8 @@ ble_gatts_bonding_established(uint16_t conn_handle)
conn = ble_hs_conn_find(conn_handle); conn = ble_hs_conn_find(conn_handle);
BLE_HS_DBG_ASSERT(conn != NULL); BLE_HS_DBG_ASSERT(conn != NULL);
BLE_HS_DBG_ASSERT(conn->bhc_sec_state.bonded);
if (conn->bhc_sec_state.bonded) {
cccd_value.peer_addr = conn->bhc_peer_addr; cccd_value.peer_addr = conn->bhc_peer_addr;
gatt_srv = &conn->bhc_gatt_svr; gatt_srv = &conn->bhc_gatt_svr;
@ -1714,7 +1714,6 @@ ble_gatts_bonding_established(uint16_t conn_handle)
BLE_HS_DBG_ASSERT(conn != NULL); BLE_HS_DBG_ASSERT(conn != NULL);
} }
} }
}
ble_hs_unlock(); ble_hs_unlock();
} }

View File

@ -410,15 +410,13 @@ ble_hs_conn_addrs(const struct ble_hs_conn *conn,
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY) #if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
/* RPA: Override peer address information. */ /* RPA: Override peer address information. */
struct ble_hs_resolv_entry *rl = NULL;
ble_addr_t bhc_peer_addr; ble_addr_t bhc_peer_addr;
bhc_peer_addr.type = conn->bhc_peer_addr.type; bhc_peer_addr.type = conn->bhc_peer_addr.type;
memcpy(bhc_peer_addr.val, conn->bhc_peer_addr.val, BLE_DEV_ADDR_LEN); memcpy(bhc_peer_addr.val, conn->bhc_peer_addr.val, BLE_DEV_ADDR_LEN);
struct ble_hs_resolv_entry *rl = NULL;
rl = ble_hs_resolv_list_find(bhc_peer_addr.val); rl = ble_hs_resolv_list_find(bhc_peer_addr.val);
if (rl != NULL) { if (rl != NULL) {
addrs->peer_ota_addr = conn->bhc_peer_rpa_addr;
memcpy(addrs->peer_id_addr.val, rl->rl_identity_addr, BLE_DEV_ADDR_LEN); memcpy(addrs->peer_id_addr.val, rl->rl_identity_addr, BLE_DEV_ADDR_LEN);
addrs->peer_id_addr.type = rl->rl_addr_type; addrs->peer_id_addr.type = rl->rl_addr_type;

View File

@ -240,7 +240,7 @@ ble_hs_hci_process_ack(uint16_t expected_opcode,
} }
if (rc == 0) { if (rc == 0) {
if (params_buf == NULL) { if (params_buf == NULL || out_ack->bha_params == NULL) {
out_ack->bha_params_len = 0; out_ack->bha_params_len = 0;
} else { } else {
if (out_ack->bha_params_len > params_buf_len) { if (out_ack->bha_params_len > params_buf_len) {

View File

@ -337,14 +337,6 @@ ble_hs_hci_evt_le_conn_complete(uint8_t subevent, uint8_t *data, int len)
struct ble_hs_resolv_entry *rl = NULL; struct ble_hs_resolv_entry *rl = NULL;
ble_rpa_replace_peer_params_with_rl(evt.peer_addr, ble_rpa_replace_peer_params_with_rl(evt.peer_addr,
&evt.peer_addr_type, &rl); &evt.peer_addr_type, &rl);
if (rl == NULL) {
if (ble_rpa_resolv_add_peer_rec(evt.peer_addr) != 0) {
BLE_HS_LOG(DEBUG, "Memory unavailable for new peer record\n");
}
}
/* Set the correct RPA for logging */
memcpy(evt.peer_rpa, data + 6, BLE_DEV_ADDR_LEN);
#endif #endif
} else { } else {
memset(evt.local_rpa, 0, BLE_DEV_ADDR_LEN); memset(evt.local_rpa, 0, BLE_DEV_ADDR_LEN);
@ -441,14 +433,6 @@ ble_hs_hci_evt_le_adv_rpt(uint8_t subevent, uint8_t *data, int len)
memcpy(desc.addr.val, data + off, 6); memcpy(desc.addr.val, data + off, 6);
off += 6; off += 6;
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
if (ble_host_rpa_enabled()) {
/* Now RPA to be resolved here, since controller is unaware of the
* address is RPA */
ble_rpa_replace_peer_params_with_rl(desc.addr.val,
&desc.addr.type, NULL);
}
#endif
desc.length_data = data[off]; desc.length_data = data[off];
++off; ++off;

View File

@ -56,7 +56,7 @@ ble_hs_misc_conn_chan_find(uint16_t conn_handle, uint16_t cid,
return rc; return rc;
} }
void int
ble_hs_misc_conn_chan_find_reqd(uint16_t conn_handle, uint16_t cid, ble_hs_misc_conn_chan_find_reqd(uint16_t conn_handle, uint16_t cid,
struct ble_hs_conn **out_conn, struct ble_hs_conn **out_conn,
struct ble_l2cap_chan **out_chan) struct ble_l2cap_chan **out_chan)
@ -66,7 +66,9 @@ ble_hs_misc_conn_chan_find_reqd(uint16_t conn_handle, uint16_t cid,
int rc; int rc;
rc = ble_hs_misc_conn_chan_find(conn_handle, cid, &conn, &chan); rc = ble_hs_misc_conn_chan_find(conn_handle, cid, &conn, &chan);
BLE_HS_DBG_ASSERT_EVAL(rc == 0); if (rc != 0) {
return rc;
}
if (out_conn != NULL) { if (out_conn != NULL) {
*out_conn = conn; *out_conn = conn;
@ -74,6 +76,8 @@ ble_hs_misc_conn_chan_find_reqd(uint16_t conn_handle, uint16_t cid,
if (out_chan != NULL) { if (out_chan != NULL) {
*out_chan = chan; *out_chan = chan;
} }
return 0;
} }
uint8_t uint8_t

View File

@ -115,7 +115,7 @@ int ble_hs_hci_evt_acl_process(struct os_mbuf *om);
int ble_hs_misc_conn_chan_find(uint16_t conn_handle, uint16_t cid, int ble_hs_misc_conn_chan_find(uint16_t conn_handle, uint16_t cid,
struct ble_hs_conn **out_conn, struct ble_hs_conn **out_conn,
struct ble_l2cap_chan **out_chan); struct ble_l2cap_chan **out_chan);
void ble_hs_misc_conn_chan_find_reqd(uint16_t conn_handle, uint16_t cid, int ble_hs_misc_conn_chan_find_reqd(uint16_t conn_handle, uint16_t cid,
struct ble_hs_conn **out_conn, struct ble_hs_conn **out_conn,
struct ble_l2cap_chan **out_chan); struct ble_l2cap_chan **out_chan);
uint8_t ble_hs_misc_addr_type_to_id(uint8_t addr_type); uint8_t ble_hs_misc_addr_type_to_id(uint8_t addr_type);

View File

@ -473,8 +473,13 @@ ble_l2cap_sig_update(uint16_t conn_handle,
STATS_INC(ble_l2cap_stats, update_init); STATS_INC(ble_l2cap_stats, update_init);
ble_hs_lock(); ble_hs_lock();
ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_SIG, rc = ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_SIG,
&conn, &chan); &conn, &chan);
if (rc != 0) {
ble_hs_unlock();
goto done;
}
master = conn->bhc_flags & BLE_HS_CONN_F_MASTER; master = conn->bhc_flags & BLE_HS_CONN_F_MASTER;
ble_hs_unlock(); ble_hs_unlock();

View File

@ -28,9 +28,11 @@ ble_l2cap_sig_tx(uint16_t conn_handle, struct os_mbuf *txom)
int rc; int rc;
ble_hs_lock(); ble_hs_lock();
ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_SIG, rc = ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_SIG,
&conn, &chan); &conn, &chan);
if (rc == 0) {
rc = ble_l2cap_tx(conn, chan, txom); rc = ble_l2cap_tx(conn, chan, txom);
}
ble_hs_unlock(); ble_hs_unlock();
return rc; return rc;

View File

@ -538,6 +538,11 @@ ble_sm_persist_keys(struct ble_sm_proc *proc)
case BLE_ADDR_PUBLIC: case BLE_ADDR_PUBLIC:
case BLE_ADDR_PUBLIC_ID: case BLE_ADDR_PUBLIC_ID:
conn->bhc_peer_addr.type = BLE_ADDR_PUBLIC_ID; conn->bhc_peer_addr.type = BLE_ADDR_PUBLIC_ID;
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
/* In case of Host based privacy, we should not be changing
* peer address type to BLE_ADDR_PUBLIC_ID */
conn->bhc_peer_addr.type = BLE_ADDR_PUBLIC;
#endif
break; break;
case BLE_ADDR_RANDOM: case BLE_ADDR_RANDOM:
@ -944,7 +949,7 @@ ble_sm_process_result(uint16_t conn_handle, struct ble_sm_result *res)
if (res->enc_cb) { if (res->enc_cb) {
BLE_HS_DBG_ASSERT(proc == NULL || rm); BLE_HS_DBG_ASSERT(proc == NULL || rm);
ble_gap_enc_event(conn_handle, res->app_status, res->restore); ble_gap_enc_event(conn_handle, res->app_status, res->restore, res->bonded);
} }
if (res->app_status == 0 && if (res->app_status == 0 &&
@ -1198,6 +1203,7 @@ ble_sm_enc_event_rx(uint16_t conn_handle, uint8_t evt_status, int encrypted)
ble_hs_unlock(); ble_hs_unlock();
res.bonded = bonded;
ble_sm_process_result(conn_handle, &res); ble_sm_process_result(conn_handle, &res);
} }
@ -1793,8 +1799,21 @@ ble_sm_pair_req_rx(uint16_t conn_handle, struct os_mbuf **om,
*/ */
proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, &prev); proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, &prev);
if (proc != NULL) { if (proc != NULL) {
/* Pairing already in progress; abort old procedure and start new. */ /* Fail if procedure is in progress unless we sent a slave security
/* XXX: Check the spec on this. */ * request to peer.
*/
if (proc->state != BLE_SM_PROC_STATE_SEC_REQ) {
res->sm_err = BLE_SM_ERR_UNSPECIFIED;
res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_UNSPECIFIED);
ble_hs_unlock();
return;
}
/* Remove the procedure because it was allocated when
* sending the Slave Security Request and it will be allocated
* again later in this method. We should probably refactor this
* in the future.
*/
ble_sm_proc_remove(proc, prev); ble_sm_proc_remove(proc, prev);
ble_sm_proc_free(proc); ble_sm_proc_free(proc);
} }
@ -2459,7 +2478,7 @@ ble_sm_timer(void)
* procedures without reconnect. * procedures without reconnect.
*/ */
while ((proc = STAILQ_FIRST(&exp_list)) != NULL) { while ((proc = STAILQ_FIRST(&exp_list)) != NULL) {
ble_gap_enc_event(proc->conn_handle, BLE_HS_ETIMEOUT, 0); ble_gap_enc_event(proc->conn_handle, BLE_HS_ETIMEOUT, 0, 0);
STAILQ_REMOVE_HEAD(&exp_list, next); STAILQ_REMOVE_HEAD(&exp_list, next);
ble_sm_proc_free(proc); ble_sm_proc_free(proc);

View File

@ -52,14 +52,19 @@ ble_sm_tx(uint16_t conn_handle, struct os_mbuf *txom)
{ {
struct ble_l2cap_chan *chan; struct ble_l2cap_chan *chan;
struct ble_hs_conn *conn; struct ble_hs_conn *conn;
int rc;
BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task()); BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
STATS_INC(ble_l2cap_stats, sm_tx); STATS_INC(ble_l2cap_stats, sm_tx);
ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_SM, rc = ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_SM,
&conn, &chan); &conn, &chan);
return ble_l2cap_tx(conn, chan, txom); if (rc == 0) {
rc = ble_l2cap_tx(conn, chan, txom);
}
return rc;
} }
#if NIMBLE_BLE_SM #if NIMBLE_BLE_SM

View File

@ -279,7 +279,7 @@ struct ble_sm_result {
void *state_arg; void *state_arg;
unsigned execute : 1; unsigned execute : 1;
unsigned enc_cb : 1; unsigned enc_cb : 1;
unsigned persist_keys:1; unsigned bonded : 1;
unsigned restore : 1; unsigned restore : 1;
}; };

View File

@ -19,6 +19,7 @@
#include "host/ble_store.h" #include "host/ble_store.h"
#include "ble_hs_priv.h" #include "ble_hs_priv.h"
#include "ble_hs_resolv_priv.h"
struct ble_store_util_peer_set { struct ble_store_util_peer_set {
ble_addr_t *peer_id_addrs; ble_addr_t *peer_id_addrs;
@ -27,12 +28,6 @@ struct ble_store_util_peer_set {
int status; int status;
}; };
struct ble_store_util_peer_cccd_set {
struct ble_store_util_peer_set peer_set;
ble_addr_t *curr_peer_addr;
};
static int static int
ble_store_util_iter_unique_peer(int obj_type, ble_store_util_iter_unique_peer(int obj_type,
union ble_store_value *val, union ble_store_value *val,
@ -65,42 +60,6 @@ ble_store_util_iter_unique_peer(int obj_type,
return 0; return 0;
} }
static int
ble_store_util_iter_peer_cccd(int obj_type,
union ble_store_value *val,
void *arg)
{
struct ble_store_util_peer_cccd_set *set;
int i;
set = arg;
/* Do nothing if this peer is a duplicate or current peer */
for (i = 0; i < set->peer_set.num_peers; i++) {
if (ble_addr_cmp(set->peer_set.peer_id_addrs + i, &val->cccd.peer_addr) == 0) {
return 0;
}
if (set->curr_peer_addr != NULL) {
if (ble_addr_cmp(set->curr_peer_addr, &val->cccd.peer_addr) == 0) {
return 0;
}
}
}
if (set->peer_set.num_peers >= set->peer_set.max_peers) {
/* Overflow; abort the iterate procedure. */
set->peer_set.status = BLE_HS_ENOMEM;
return 1;
}
set->peer_set.peer_id_addrs[set->peer_set.num_peers] = val->cccd.peer_addr;
set->peer_set.num_peers++;
return 0;
}
/** /**
* Retrieves the set of peer addresses for which a bond has been established. * Retrieves the set of peer addresses for which a bond has been established.
* *
@ -141,51 +100,6 @@ ble_store_util_bonded_peers(ble_addr_t *out_peer_id_addrs, int *out_num_peers,
return 0; return 0;
} }
/**
* Retrieves the set of peer addresses for which CCCDs are subscribed.
*
* @param out_peer_id_addrs On success, the set of peer addresses
* gets written here.
* @param out_num_peers On success, the number of peer addresses gets written
* here.
* @param max_peers The capacity of the destination buffer.
*
* @param curr_peer_addrs Current peer's address, ignore if NULL
*
* @return 0 on success;
* BLE_HS_ENOMEM if the destination buffer is too
* small;
* Other nonzero on error.
*/
static int
ble_store_util_subscribed_cccds(ble_addr_t *out_peer_id_addrs, int *out_num_peers,
int max_peers, ble_addr_t *curr_peer_addr)
{
struct ble_store_util_peer_cccd_set set = {
.peer_set = {
.peer_id_addrs = out_peer_id_addrs,
.num_peers = 0,
.max_peers = max_peers,
.status = 0,
},
.curr_peer_addr = curr_peer_addr,
};
int rc;
rc = ble_store_iterate(BLE_STORE_OBJ_TYPE_CCCD,
ble_store_util_iter_peer_cccd,
&set);
if (rc != 0) {
return rc;
}
if (set.peer_set.status != 0) {
return set.peer_set.status;
}
*out_num_peers = set.peer_set.num_peers;
return 0;
}
/** /**
* Deletes all entries from the store that are attached to the specified peer * Deletes all entries from the store that are attached to the specified peer
* address. This function deletes security entries and CCCD records. * address. This function deletes security entries and CCCD records.
@ -222,6 +136,25 @@ ble_store_util_delete_peer(const ble_addr_t *peer_id_addr)
return rc; return rc;
} }
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
struct ble_hs_dev_records *peer_rec =
ble_rpa_find_peer_dev_rec(key.sec.peer_addr.val);
if (peer_rec != NULL) {
rc = ble_hs_resolv_list_rmv(peer_rec->peer_sec.peer_addr.type,
peer_rec->peer_sec.peer_addr.val);
if (rc != 0) {
/* We can't do anything much here, continue with removing from peer_record */
BLE_HS_LOG(DEBUG, "Peer Device was not removed from RL \n");
}
rc = ble_rpa_remove_peer_dev_rec(peer_rec);
if (rc != 0) {
return rc;
}
}
#endif
return 0; return 0;
} }
@ -305,63 +238,6 @@ ble_store_util_delete_oldest_peer(void)
return 0; return 0;
} }
/**
* Delete CCCDs of unbonded devices.
*
* @param curr_peer Current peer's address (not to delete), ignore
* ignore if NULL
*
* @return 0 on success;
* nonzero on error.
*/
int
ble_store_clean_old_cccds(const ble_addr_t *curr_peer)
{
ble_addr_t peer_cccd_addrs[MYNEWT_VAL(BLE_STORE_MAX_CCCDS)];
ble_addr_t peer_bonded_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
int num_bonded_peers, num_cccd_peers;
int i, j, rc;
rc = ble_store_util_subscribed_cccds(&peer_cccd_addrs[0], &num_cccd_peers,
MYNEWT_VAL(BLE_STORE_MAX_CCCDS),
(void *) curr_peer);
if (rc != 0) {
return rc;
}
rc = ble_store_util_bonded_peers(&peer_bonded_addrs[0], &num_bonded_peers,
MYNEWT_VAL(BLE_STORE_MAX_BONDS));
if (rc != 0) {
return rc;
}
union ble_store_key key = {0};
/* Init rc to BLE_HS_ENOENT to indicate no CCCD is deleted */
rc = BLE_HS_ENOENT;
for (i = 0; i < num_cccd_peers; i++) {
key.cccd.peer_addr = peer_cccd_addrs[i];
for (j = 0; j < num_bonded_peers; j++) {
if (memcmp(&peer_cccd_addrs[i], &peer_bonded_addrs[j],
sizeof(ble_addr_t)) == 0) {
break;
}
}
if (j < num_bonded_peers) {
continue;
}
rc = ble_store_util_delete_all(BLE_STORE_OBJ_TYPE_CCCD, &key);
if (rc != 0) {
return rc;
}
}
return rc;
}
/** /**
* Round-robin status callback. If a there is insufficient storage capacity * Round-robin status callback. If a there is insufficient storage capacity
* for a new record, delete the oldest bond and proceed with the persist * for a new record, delete the oldest bond and proceed with the persist
@ -374,7 +250,6 @@ ble_store_clean_old_cccds(const ble_addr_t *curr_peer)
int int
ble_store_util_status_rr(struct ble_store_status_event *event, void *arg) ble_store_util_status_rr(struct ble_store_status_event *event, void *arg)
{ {
int rc = BLE_HS_EUNKNOWN;
switch (event->event_code) { switch (event->event_code) {
case BLE_STORE_EVENT_OVERFLOW: case BLE_STORE_EVENT_OVERFLOW:
switch (event->overflow.obj_type) { switch (event->overflow.obj_type) {
@ -382,25 +257,11 @@ ble_store_util_status_rr(struct ble_store_status_event *event, void *arg)
case BLE_STORE_OBJ_TYPE_PEER_SEC: case BLE_STORE_OBJ_TYPE_PEER_SEC:
return ble_gap_unpair_oldest_peer(); return ble_gap_unpair_oldest_peer();
case BLE_STORE_OBJ_TYPE_CCCD: case BLE_STORE_OBJ_TYPE_CCCD:
/* Try to remove unbonded CCCDs first */ /* Try unpairing oldest peer except current peer */
if ((rc = ble_store_clean_old_cccds((void *) &event->overflow.value->cccd.peer_addr)) == BLE_HS_ENOENT) { return ble_gap_unpair_oldest_except(&event->overflow.value->cccd.peer_addr);
/* No unbonded CCCDs found to delete, try unpairing oldest peer
* except current peer */
return ble_gap_unpair_oldest_except_curr((void *) &event->overflow.value->cccd.peer_addr);
}
return rc;
default: default:
return BLE_HS_EUNKNOWN; return BLE_HS_EUNKNOWN;
/* case BLE_STORE_OBJ_TYPE_OUR_SEC:
case BLE_STORE_OBJ_TYPE_PEER_SEC:
case BLE_STORE_OBJ_TYPE_CCCD:
return ble_gap_unpair_oldest_peer();
default:
return BLE_HS_EUNKNOWN;
*/
} }
case BLE_STORE_EVENT_FULL: case BLE_STORE_EVENT_FULL:

View File

@ -210,11 +210,11 @@ get_nvs_db_attribute(int obj_type, bool empty, void *value, int num_value)
err = get_nvs_matching_index(&p_dev_rec, value, num_value, err = get_nvs_matching_index(&p_dev_rec, value, num_value,
sizeof(struct ble_hs_dev_records)); sizeof(struct ble_hs_dev_records));
} else { } else {
if (obj_type == BLE_STORE_OBJ_TYPE_CCCD) { if (obj_type != BLE_STORE_OBJ_TYPE_CCCD) {
err = get_nvs_matching_index(&cur.sec, value, num_value, err = get_nvs_matching_index(&cur.sec, value, num_value,
sizeof(struct ble_store_value_sec)); sizeof(struct ble_store_value_sec));
} else { } else {
err = get_nvs_matching_index(&cur.sec, value, num_value, err = get_nvs_matching_index(&cur.cccd, value, num_value,
sizeof(struct ble_store_value_cccd)); sizeof(struct ble_store_value_cccd));
} }
} }

View File

@ -17,8 +17,6 @@
* under the License. * under the License.
*/ */
/* Modifications copyright (C) 2020 Ryan Powell*/
#ifndef _NIMBLE_NPL_H_ #ifndef _NIMBLE_NPL_H_
#define _NIMBLE_NPL_H_ #define _NIMBLE_NPL_H_
@ -26,6 +24,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "nimconfig.h" #include "nimconfig.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif

View File

@ -17,7 +17,6 @@
* under the License. * under the License.
*/ */
/* Modifications copyright (C) 2020 Ryan Powell */
#ifndef _NIMBLE_PORT_H #ifndef _NIMBLE_PORT_H
#define _NIMBLE_PORT_H #define _NIMBLE_PORT_H

View File

@ -1,17 +1,100 @@
#pragma once #pragma once
#define CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL 1
#define CONFIG_BT_NIMBLE_MAX_CONNECTIONS 3 #include "sdkconfig.h"
#define CONFIG_BT_NIMBLE_MAX_BONDS 3 /** For ESP-IDF compatibility
#define CONFIG_BT_NIMBLE_MAX_CCCDS 8 *
#define CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM 0 * Some versions of ESP-IDF used the config name format "CONFIG_NIMBLE_".
#define CONFIG_BT_NIMBLE_PINNED_TO_CORE_0 1 * This converts them to "CONFIG_BT_NIMBLE_" format used in the latest IDF.
*/
/* Detect if using ESP-IDF or Arduino (Arduino won't have these defines in sdkconfig)*/
#if defined(CONFIG_BT_NIMBLE_TASK_STACK_SIZE) || defined(CONFIG_NIMBLE_TASK_STACK_SIZE)
#if defined(CONFIG_NIMBLE_ENABLED)
#define CONFIG_BT_NIMBLE_ENABLED
#endif
#if defined(CONFIG_NIMBLE_ROLE_OBSERVER)
#define CONFIG_BT_NIMBLE_ROLE_OBSERVER
#endif
#if defined(CONFIG_NIMBLE_ROLE_BROADCASTER)
#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER
#endif
#if defined(CONFIG_NIMBLE_ROLE_CENTRAL)
#define CONFIG_BT_NIMBLE_ROLE_CENTRAL
#endif
#if defined(CONFIG_NIMBLE_ROLE_PERIPHERAL)
#define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
#endif
#if defined(CONFIG_NIMBLE_DEBUG)
#define CONFIG_BT_NIMBLE_DEBUG
#endif
#else // Using Arduino
/***********************************************
* Arduino config options
**********************************************/
/** Comment out if not using NimBLE Client functions
* Reduces flash size by approx. 7kB.
*/
#define CONFIG_BT_NIMBLE_ROLE_CENTRAL
/** Comment out if not using NimBLE Scan functions
* Reduces flash size by approx. 26kB.
*/
#define CONFIG_BT_NIMBLE_ROLE_OBSERVER
/** Comment out if not using NimBLE Server functions
* Reduces flash size by approx. 16kB.
*/
// #define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL // Tasmota
/** Comment out if not using NimBLE Advertising functions
* Reduces flash size by approx. 5kB.
*/
// #define CONFIG_BT_NIMBLE_ROLE_BROADCASTER // Tasmota
/** Uncomment to see debug log messages from the NimBLE host
* Uses approx. 32kB of flash memory.
*/
// #define CONFIG_BT_NIMBLE_DEBUG
/** Uncomment to see NimBLE host return codes as text debug log messages.
* Uses approx. 7kB of flash memory.
*/
// #define CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT
/** Uncomment to see GAP event codes as text in debug log messages.
* Uses approx. 1kB of flash memory.
*/
// #define CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT
/** Uncomment to see advertisment types as text while scanning in debug log messages.
* Uses approx. 250 bytes of flash memory.
*/
// #define CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT
/** Sets the core NimBLE host runs on */
#define CONFIG_BT_NIMBLE_PINNED_TO_CORE 0 #define CONFIG_BT_NIMBLE_PINNED_TO_CORE 0
/** Sets the stack size for the NimBLE host task */
#define CONFIG_BT_NIMBLE_TASK_STACK_SIZE 4096 #define CONFIG_BT_NIMBLE_TASK_STACK_SIZE 4096
#define CONFIG_BT_NIMBLE_ROLE_CENTRAL 1
#define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL 1 /** Sets the number of simultaneous connections (esp controller max is 9) */
#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER 1 #define CONFIG_BT_NIMBLE_MAX_CONNECTIONS 3
#define CONFIG_BT_NIMBLE_ROLE_OBSERVER 1
#define CONFIG_BT_NIMBLE_NVS_PERSIST 1 /** Sets the number of devices allowed to store/bond with */
#define CONFIG_BT_NIMBLE_MAX_BONDS 3 // Tasmota
/** Sets the number of CCCD's to store per bonded device */
#define CONFIG_BT_NIMBLE_MAX_CCCDS 3 // Tasmota
#define CONFIG_BT_NIMBLE_NVS_PERSIST 0 // Tasmota
#define CONFIG_BT_NIMBLE_SM_LEGACY 1 #define CONFIG_BT_NIMBLE_SM_LEGACY 1
#define CONFIG_BT_NIMBLE_SM_SC 1 #define CONFIG_BT_NIMBLE_SM_SC 1
#define CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME "nimble" #define CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME "nimble"
@ -29,6 +112,23 @@
#define CONFIG_BT_NIMBLE_HS_FLOW_CTRL_THRESH 2 #define CONFIG_BT_NIMBLE_HS_FLOW_CTRL_THRESH 2
#define CONFIG_BT_NIMBLE_HS_FLOW_CTRL_TX_ON_DISCONNECT 1 #define CONFIG_BT_NIMBLE_HS_FLOW_CTRL_TX_ON_DISCONNECT 1
#define CONFIG_BT_NIMBLE_RPA_TIMEOUT 900 #define CONFIG_BT_NIMBLE_RPA_TIMEOUT 900
#define CONFIG_BT_ENABLED 1 #define CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM 0
#define CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY 1
#define CONFIG_BT_NIMBLE_DEBUG 0 /** Do not comment out */
#ifndef CONFIG_BT_ENABLED
#define CONFIG_BT_ENABLED
#endif
#define CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY
#define CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL
#endif // #if defined(CONFIG_BT_NIMBLE_TASK_STACK_SIZE) || defined(CONFIG_NIMBLE_TASK_STACK_SIZE)
/** Cannot use client without scan */
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) && !defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
#define CONFIG_BT_NIMBLE_ROLE_OBSERVER
#endif
/** Cannot use server without advertise */
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) && !defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER
#endif

View File

@ -19,8 +19,6 @@
* under the License. * under the License.
*/ */
/* Modifications copyright (C) 2020 Ryan Powell */
#include "esp_attr.h" #include "esp_attr.h"
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
#include "nimconfig.h" #include "nimconfig.h"
@ -32,6 +30,8 @@ IRAM_ATTR void *nimble_platform_mem_malloc(size_t size)
return heap_caps_malloc(size, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); return heap_caps_malloc(size, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL #elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL
return heap_caps_malloc(size, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT); return heap_caps_malloc(size, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT);
#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_IRAM_8BIT
return heap_caps_malloc_prefer(size, 2, MALLOC_CAP_INTERNAL|MALLOC_CAP_IRAM_8BIT, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
#else #else
return malloc(size); return malloc(size);
#endif #endif
@ -43,6 +43,8 @@ IRAM_ATTR void *nimble_platform_mem_calloc(size_t n, size_t size)
return heap_caps_calloc(n, size, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); return heap_caps_calloc(n, size, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL #elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL
return heap_caps_calloc(n, size, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT); return heap_caps_calloc(n, size, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT);
#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_IRAM_8BIT
return heap_caps_calloc_prefer(n, size, 2, MALLOC_CAP_INTERNAL|MALLOC_CAP_IRAM_8BIT, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
#else #else
return calloc(n, size); return calloc(n, size);
#endif #endif