mirror of https://github.com/arendst/Tasmota.git
Merge pull request #8867 from Staars/mi32
MI_ESP32: update NimBLE-Arduino
This commit is contained in:
commit
dcab142b98
|
@ -122,21 +122,20 @@ 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.
|
The last two above changes reduce the heap usage significantly with minimal application code adjustments.
|
||||||
|
|
||||||
**NEW** on May 23, 2020
|
**UPDATED** on June 21, 2020
|
||||||
> ```
|
> ```
|
||||||
> NimBLEClient::getServices(bool refresh = false)
|
> NimBLEClient::getServices(bool refresh = false)
|
||||||
> NimBLERemoteService::getCharacteristics(bool refresh = false)
|
> NimBLERemoteService::getCharacteristics(bool refresh = false)
|
||||||
> NimBLERemoteCharacteristic::getDecriptors(bool refresh = false)
|
> NimBLERemoteCharacteristic::getDecriptors(bool refresh = false)
|
||||||
>```
|
>```
|
||||||
> These methods now take an optional (bool) parameter.
|
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 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
|
If false(default) it will return the respective vector empty or otherwise with the currently stored attributes.
|
||||||
with the currently stored attributes.
|
|
||||||
|
|
||||||
> Removed the automatic discovery of all peripheral attributes as they consumed time and resources for data
|
**Removed:** the automatic discovery of all peripheral attributes as they consumed time and resources for data
|
||||||
the user may not be interested in.
|
the user may not be interested in.
|
||||||
|
|
||||||
> Added `NimBLEClient::discoverAtrributes()` for the user to discover all the peripheral attributes
|
**Added:** `NimBLEClient::discoverAtrributes()` for the user to discover all the peripheral attributes
|
||||||
to replace the the former functionality.
|
to replace the the former functionality.
|
||||||
|
|
||||||
|
|
||||||
|
@ -145,12 +144,11 @@ to replace the the former functionality.
|
||||||
>getCharacteristic(NimBLEUUID)
|
>getCharacteristic(NimBLEUUID)
|
||||||
>getDescriptor(NimBLEUUID)
|
>getDescriptor(NimBLEUUID)
|
||||||
>```
|
>```
|
||||||
>These methods will now check the respective vectors for the attribute object and, if not found, will retrieve (only)
|
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.
|
the specified attribute from the peripheral.
|
||||||
|
|
||||||
> These changes allow more control for the user to manage the resources used for the attributes.
|
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.
|
||||||
|
|
|
@ -1,5 +1,17 @@
|
||||||
# *** UPDATE ***
|
# *** UPDATES ***
|
||||||
**Breaking change:** Client and scan now use `std::vector` instead of `std::map` for storing the remote attribute database.
|
**Breaking changes:**
|
||||||
|
**NEW** on June 21, 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(default) it will return the respective vector empty or otherwise with the currently stored attributes.
|
||||||
|
|
||||||
|
**NEW** on May 23, 2020
|
||||||
|
Client and scan now use `std::vector` instead of `std::map` for storing the remote attribute database.
|
||||||
|
|
||||||
This change will affect your application code if you use `NimBLEClient::getServices()` or `NimBLERemoteService::getCharacteristics()`
|
This change will affect your application code if you use `NimBLEClient::getServices()` or `NimBLERemoteService::getCharacteristics()`
|
||||||
in your application as they now return a pointer to `std::vector` of the respective attributes.
|
in your application as they now return a pointer to `std::vector` of the respective attributes.
|
||||||
|
@ -13,29 +25,32 @@ It is expected that there will be minimal impact on most applications, if you ne
|
||||||
# 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.
|
||||||
|
|
||||||
Why? Because the Bluedroid library is too bulky.
|
This library **significantly** reduces resource usage and improves performance for ESP32 BLE applications as compared
|
||||||
|
with the bluedroid based library. The goal is to maintain, as much as reasonable, compatibility with the original
|
||||||
|
library but refactored to use the NimBLE stack. In addition, this library will be more actively developed and maintained
|
||||||
|
to provide improved capabilites and stability over the original.
|
||||||
|
|
||||||
Initial client code testing has resulted in code size reduction of ~115k and reduced ram consumption of ~37k.
|
## Resource use improvement:
|
||||||
|
|
||||||
Server code testing results from @beegee-toyo [from the project here](https://github.com/beegee-tokyo/ESP32WiFiBLE-NimBLE):
|
### (Original) BLE_client example comparison (Debug):
|
||||||
|
#### Arduino BLE Library
|
||||||
|
Sketch uses **1216377** bytes (58%) of program storage space.
|
||||||
|
Memory after connection: Free Heap: **171548**
|
||||||
|
|
||||||
|
|
||||||
### Memory usage (compilation output)
|
|
||||||
#### Arduino BLE library
|
|
||||||
```log
|
|
||||||
RAM: [== ] 17.7% (used 58156 bytes from 327680 bytes)
|
|
||||||
Flash: [======== ] 76.0% (used 1345630 bytes from 1769472 bytes)
|
|
||||||
```
|
|
||||||
#### NimBLE-Arduino library
|
#### NimBLE-Arduino library
|
||||||
```log
|
Sketch uses **617256** bytes (29%) of program storage space.
|
||||||
RAM: [= ] 14.5% (used 47476 bytes from 327680 bytes)
|
Memory after connection: Free Heap: **270336**
|
||||||
Flash: [======= ] 69.5% (used 911378 bytes from 1310720 bytes)
|
***
|
||||||
```
|
### (Original) BLE_notify example comparison (Debug):
|
||||||
### Memory usage after **`setup()`** function
|
#### Arduino BLE Library
|
||||||
#### Arduino BLE library
|
Sketch uses **1208409** bytes (57%) of program storage space.
|
||||||
**`Internal Total heap 259104, internal Free Heap 91660`**
|
Memory after connection: Free Heap: **173300**
|
||||||
|
|
||||||
#### NimBLE-Arduino library
|
#### NimBLE-Arduino library
|
||||||
**`Internal Total heap 290288, internal Free Heap 182344`**
|
Sketch uses **603432** bytes (28%) of program storage space.
|
||||||
|
Memory after connection: Free Heap: **269792**
|
||||||
|
|
||||||
|
**As shown: there is nearly a 50% reduction in flash use and approx. 100kB less ram consumed!**
|
||||||
|
|
||||||
|
|
||||||
# Installation:
|
# Installation:
|
||||||
|
@ -62,20 +77,21 @@ 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 [@fead24e.](https://github.com/espressif/esp-nimble)
|
This Library is tracking the esp-nimble repo, nimble-1.2.0-idf master branch, currently [@46c1d9f.](https://github.com/espressif/esp-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)
|
Also tracking the NimBLE related changes in esp-idf, master branch, currently [@2ef4890.](https://github.com/espressif/esp-idf/tree/master/components/bt/host/nimble)
|
||||||
|
|
||||||
# Acknowledgments:
|
# Acknowledgments:
|
||||||
|
|
||||||
* @nkolban and @chegewara for the [original esp32 BLE library](https://github.com/nkolban/esp32-snippets) this project was derived from.
|
* @nkolban and @chegewara for the [original esp32 BLE library](https://github.com/nkolban/esp32-snippets) this project was derived from.
|
||||||
* @beegee-tokyo for contributing your time to test/debug and contributing the beacon examples.
|
* @beegee-tokyo for contributing your time to test/debug and contributing the beacon examples.
|
||||||
|
* @Jeroen88 for the amazing help debugging and improving the client code.
|
||||||
|
|
||||||
|
|
||||||
# Todo:
|
# Todo:
|
||||||
|
|
||||||
1. Code cleanup.
|
1. Create documentation.
|
||||||
2. Create documentation.
|
2. Add BLE Mesh code.
|
||||||
3. Expose more NimBLE features.
|
3. Expose more NimBLE features.
|
||||||
4. Add BLE Mesh code.
|
|
||||||
|
|
||||||
|
|
|
@ -22,11 +22,16 @@
|
||||||
|
|
||||||
#include "NimBLEDescriptor.h"
|
#include "NimBLEDescriptor.h"
|
||||||
|
|
||||||
#include <map>
|
#include <vector>
|
||||||
|
|
||||||
#define NIMBLE_DESC_FLAG_NOTIFY 0x0001
|
#define NIMBLE_DESC_FLAG_NOTIFY 0x0001
|
||||||
#define NIMBLE_DESC_FLAG_INDICATE 0x0002
|
#define NIMBLE_DESC_FLAG_INDICATE 0x0002
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t conn_id;
|
||||||
|
uint16_t sub_val;
|
||||||
|
} chr_sub_status_t;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Descriptor for Client Characteristic Configuration.
|
* @brief Descriptor for Client Characteristic Configuration.
|
||||||
|
@ -45,7 +50,7 @@ public:
|
||||||
private:
|
private:
|
||||||
NimBLE2902(NimBLECharacteristic* pCharacterisitic);
|
NimBLE2902(NimBLECharacteristic* pCharacterisitic);
|
||||||
friend class NimBLECharacteristic;
|
friend class NimBLECharacteristic;
|
||||||
std::map<uint16_t, uint16_t> m_subscribedMap;
|
std::vector<chr_sub_status_t> m_subscribedVec;
|
||||||
|
|
||||||
}; // NimBLE2902
|
}; // NimBLE2902
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ struct BLE2904_Data {
|
||||||
|
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Descriptor for Characteristic Presentation Format.
|
* @brief Descriptor for Characteristic Presentation Format.
|
||||||
*
|
*
|
||||||
|
|
|
@ -142,4 +142,10 @@ NimBLEAddress::operator std::string() const {
|
||||||
return std::string(buffer);
|
return std::string(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NimBLEAddress::operator uint64_t() const {
|
||||||
|
uint64_t address = 0;
|
||||||
|
memcpy(&address, m_address, sizeof m_address);
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -44,6 +44,7 @@ public:
|
||||||
bool operator ==(const NimBLEAddress & rhs) const;
|
bool operator ==(const NimBLEAddress & rhs) const;
|
||||||
bool operator !=(const NimBLEAddress & rhs) const;
|
bool operator !=(const NimBLEAddress & rhs) const;
|
||||||
operator std::string() const;
|
operator std::string() const;
|
||||||
|
operator uint64_t() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t m_address[6];
|
uint8_t m_address[6];
|
||||||
|
|
|
@ -37,6 +37,8 @@ NimBLEAdvertisedDevice::NimBLEAdvertisedDevice() {
|
||||||
m_serviceData = "";
|
m_serviceData = "";
|
||||||
m_txPower = 0;
|
m_txPower = 0;
|
||||||
m_pScan = nullptr;
|
m_pScan = nullptr;
|
||||||
|
m_payloadLength = 0;
|
||||||
|
m_payload = nullptr;
|
||||||
|
|
||||||
m_haveAppearance = false;
|
m_haveAppearance = false;
|
||||||
m_haveManufacturerData = false;
|
m_haveManufacturerData = false;
|
||||||
|
@ -45,6 +47,7 @@ NimBLEAdvertisedDevice::NimBLEAdvertisedDevice() {
|
||||||
m_haveServiceData = false;
|
m_haveServiceData = false;
|
||||||
m_haveServiceUUID = false;
|
m_haveServiceUUID = false;
|
||||||
m_haveTXPower = false;
|
m_haveTXPower = false;
|
||||||
|
m_callbackSent = false;
|
||||||
|
|
||||||
} // NimBLEAdvertisedDevice
|
} // NimBLEAdvertisedDevice
|
||||||
|
|
||||||
|
@ -62,6 +65,16 @@ NimBLEAddress NimBLEAdvertisedDevice::getAddress() {
|
||||||
} // getAddress
|
} // getAddress
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the advertised type.
|
||||||
|
*
|
||||||
|
* @return The advertised type of the advertised device.
|
||||||
|
*/
|
||||||
|
uint8_t NimBLEAdvertisedDevice::getAdvType() {
|
||||||
|
return m_advType;
|
||||||
|
} // getAddress
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the appearance.
|
* @brief Get the appearance.
|
||||||
*
|
*
|
||||||
|
@ -536,6 +549,11 @@ uint8_t NimBLEAdvertisedDevice::getAddressType() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
time_t NimBLEAdvertisedDevice::getTimestamp() {
|
||||||
|
return m_timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void NimBLEAdvertisedDevice::setAddressType(uint8_t type) {
|
void NimBLEAdvertisedDevice::setAddressType(uint8_t type) {
|
||||||
m_addressType = type;
|
m_addressType = type;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,18 +42,38 @@ public:
|
||||||
NimBLEAdvertisedDevice();
|
NimBLEAdvertisedDevice();
|
||||||
|
|
||||||
NimBLEAddress getAddress();
|
NimBLEAddress getAddress();
|
||||||
|
uint8_t getAdvType();
|
||||||
uint16_t getAppearance();
|
uint16_t getAppearance();
|
||||||
std::string getManufacturerData();
|
std::string getManufacturerData();
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T getManufacturerData(bool skipSizeCheck = false) {
|
||||||
|
std::string data = getManufacturerData();
|
||||||
|
if(!skipSizeCheck && data.size() < sizeof(T)) return T();
|
||||||
|
const char *pData = data.data();
|
||||||
|
return *((T *)pData);
|
||||||
|
}
|
||||||
|
|
||||||
std::string getName();
|
std::string getName();
|
||||||
int getRSSI();
|
int getRSSI();
|
||||||
NimBLEScan* getScan();
|
NimBLEScan* getScan();
|
||||||
std::string getServiceData();
|
std::string getServiceData();
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T getServiceData(bool skipSizeCheck = false) {
|
||||||
|
std::string data = getServiceData();
|
||||||
|
if(!skipSizeCheck && data.size() < sizeof(T)) return T();
|
||||||
|
const char *pData = data.data();
|
||||||
|
return *((T *)pData);
|
||||||
|
}
|
||||||
|
|
||||||
NimBLEUUID getServiceDataUUID();
|
NimBLEUUID getServiceDataUUID();
|
||||||
NimBLEUUID getServiceUUID();
|
NimBLEUUID getServiceUUID();
|
||||||
int8_t getTXPower();
|
int8_t getTXPower();
|
||||||
uint8_t* getPayload();
|
uint8_t* getPayload();
|
||||||
size_t getPayloadLength();
|
size_t getPayloadLength();
|
||||||
uint8_t getAddressType();
|
uint8_t getAddressType();
|
||||||
|
time_t getTimestamp();
|
||||||
void setAddressType(uint8_t type);
|
void setAddressType(uint8_t type);
|
||||||
|
|
||||||
|
|
||||||
|
@ -108,8 +128,10 @@ private:
|
||||||
std::string m_serviceData;
|
std::string m_serviceData;
|
||||||
NimBLEUUID m_serviceDataUUID;
|
NimBLEUUID m_serviceDataUUID;
|
||||||
uint8_t* m_payload;
|
uint8_t* m_payload;
|
||||||
size_t m_payloadLength = 0;
|
size_t m_payloadLength;
|
||||||
uint8_t m_addressType;
|
uint8_t m_addressType;
|
||||||
|
time_t m_timestamp;
|
||||||
|
bool m_callbackSent;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -100,7 +100,8 @@ void NimBLEAdvertising::setMaxInterval(uint16_t maxinterval) {
|
||||||
m_advParams.itvl_max = maxinterval;
|
m_advParams.itvl_max = maxinterval;
|
||||||
} // setMaxInterval
|
} // setMaxInterval
|
||||||
|
|
||||||
// These are dummy functions for now for compatibility
|
|
||||||
|
/* These are dummy functions for now for compatibility */
|
||||||
void NimBLEAdvertising::setMinPreferred(uint16_t mininterval) {
|
void NimBLEAdvertising::setMinPreferred(uint16_t mininterval) {
|
||||||
//m_advData.min_interval = mininterval;
|
//m_advData.min_interval = mininterval;
|
||||||
} //
|
} //
|
||||||
|
@ -108,7 +109,8 @@ void NimBLEAdvertising::setMinPreferred(uint16_t mininterval) {
|
||||||
void NimBLEAdvertising::setMaxPreferred(uint16_t maxinterval) {
|
void NimBLEAdvertising::setMaxPreferred(uint16_t maxinterval) {
|
||||||
//m_advData.max_interval = maxinterval;
|
//m_advData.max_interval = maxinterval;
|
||||||
} //
|
} //
|
||||||
//////////////////////////////////////////////////////////
|
/*******************************************************/
|
||||||
|
|
||||||
|
|
||||||
void NimBLEAdvertising::setScanResponse(bool set) {
|
void NimBLEAdvertising::setScanResponse(bool set) {
|
||||||
m_scanResp = set;
|
m_scanResp = set;
|
||||||
|
@ -204,19 +206,19 @@ void NimBLEAdvertising::start() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int numServices = m_serviceUUIDs.size();
|
|
||||||
int rc = 0;
|
|
||||||
uint8_t addressType;
|
|
||||||
uint8_t payloadLen = 3; //start with 3 bytes for the flags data
|
|
||||||
|
|
||||||
// If already advertising just return
|
// If already advertising just return
|
||||||
if(ble_gap_adv_active()) {
|
if(ble_gap_adv_active()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_customAdvData && !m_advSvcsSet && numServices > 0) {
|
int rc = 0;
|
||||||
for (int i = 0; i < numServices; i++) {
|
|
||||||
if(m_serviceUUIDs[i].getNative()->u.type == BLE_UUID_TYPE_16) {
|
if (!m_customAdvData && !m_advDataSet) {
|
||||||
|
//start with 3 bytes for the flags data
|
||||||
|
uint8_t payloadLen = 3;
|
||||||
|
|
||||||
|
for(auto &it : m_serviceUUIDs) {
|
||||||
|
if(it.getNative()->u.type == BLE_UUID_TYPE_16) {
|
||||||
int add = (m_advData.num_uuids16 > 0) ? 2 : 4;
|
int add = (m_advData.num_uuids16 > 0) ? 2 : 4;
|
||||||
if((payloadLen + add) > 31){
|
if((payloadLen + add) > 31){
|
||||||
m_advData.uuids16_is_complete = 0;
|
m_advData.uuids16_is_complete = 0;
|
||||||
|
@ -231,13 +233,13 @@ void NimBLEAdvertising::start() {
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
memcpy(&m_advData.uuids16[m_advData.num_uuids16].value,
|
memcpy(&m_advData.uuids16[m_advData.num_uuids16].value,
|
||||||
&m_serviceUUIDs[i].getNative()->u16.value, sizeof(uint16_t));
|
&it.getNative()->u16.value, 2);
|
||||||
|
|
||||||
m_advData.uuids16[m_advData.num_uuids16].u.type = BLE_UUID_TYPE_16;
|
m_advData.uuids16[m_advData.num_uuids16].u.type = BLE_UUID_TYPE_16;
|
||||||
m_advData.uuids16_is_complete = 1;
|
m_advData.uuids16_is_complete = 1;
|
||||||
m_advData.num_uuids16++;
|
m_advData.num_uuids16++;
|
||||||
}
|
}
|
||||||
if(m_serviceUUIDs[i].getNative()->u.type == BLE_UUID_TYPE_32) {
|
if(it.getNative()->u.type == BLE_UUID_TYPE_32) {
|
||||||
int add = (m_advData.num_uuids32 > 0) ? 4 : 6;
|
int add = (m_advData.num_uuids32 > 0) ? 4 : 6;
|
||||||
if((payloadLen + add) > 31){
|
if((payloadLen + add) > 31){
|
||||||
m_advData.uuids32_is_complete = 0;
|
m_advData.uuids32_is_complete = 0;
|
||||||
|
@ -252,13 +254,13 @@ void NimBLEAdvertising::start() {
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
memcpy(&m_advData.uuids32[m_advData.num_uuids32].value,
|
memcpy(&m_advData.uuids32[m_advData.num_uuids32].value,
|
||||||
&m_serviceUUIDs[i].getNative()->u32.value, sizeof(uint32_t));
|
&it.getNative()->u32.value, 4);
|
||||||
|
|
||||||
m_advData.uuids32[m_advData.num_uuids32].u.type = BLE_UUID_TYPE_32;
|
m_advData.uuids32[m_advData.num_uuids32].u.type = BLE_UUID_TYPE_32;
|
||||||
m_advData.uuids32_is_complete = 1;
|
m_advData.uuids32_is_complete = 1;
|
||||||
m_advData.num_uuids32++;
|
m_advData.num_uuids32++;
|
||||||
}
|
}
|
||||||
if(m_serviceUUIDs[i].getNative()->u.type == BLE_UUID_TYPE_128){
|
if(it.getNative()->u.type == BLE_UUID_TYPE_128){
|
||||||
int add = (m_advData.num_uuids128 > 0) ? 16 : 18;
|
int add = (m_advData.num_uuids128 > 0) ? 16 : 18;
|
||||||
if((payloadLen + add) > 31){
|
if((payloadLen + add) > 31){
|
||||||
m_advData.uuids128_is_complete = 0;
|
m_advData.uuids128_is_complete = 0;
|
||||||
|
@ -267,12 +269,13 @@ void NimBLEAdvertising::start() {
|
||||||
payloadLen += add;
|
payloadLen += add;
|
||||||
|
|
||||||
if(nullptr == (m_advData.uuids128 = (ble_uuid128_t*)realloc(m_advData.uuids128,
|
if(nullptr == (m_advData.uuids128 = (ble_uuid128_t*)realloc(m_advData.uuids128,
|
||||||
(m_advData.num_uuids128 + 1) * sizeof(ble_uuid128_t)))) {
|
(m_advData.num_uuids128 + 1) * sizeof(ble_uuid128_t))))
|
||||||
|
{
|
||||||
NIMBLE_LOGE(LOG_TAG, "Error, no mem");
|
NIMBLE_LOGE(LOG_TAG, "Error, no mem");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
memcpy(&m_advData.uuids128[m_advData.num_uuids128].value,
|
memcpy(&m_advData.uuids128[m_advData.num_uuids128].value,
|
||||||
&m_serviceUUIDs[i].getNative()->u128.value, 16);
|
&it.getNative()->u128.value, 16);
|
||||||
|
|
||||||
m_advData.uuids128[m_advData.num_uuids128].u.type = BLE_UUID_TYPE_128;
|
m_advData.uuids128[m_advData.num_uuids128].u.type = BLE_UUID_TYPE_128;
|
||||||
m_advData.uuids128_is_complete = 1;
|
m_advData.uuids128_is_complete = 1;
|
||||||
|
@ -315,11 +318,11 @@ void NimBLEAdvertising::start() {
|
||||||
|
|
||||||
rc = ble_gap_adv_rsp_set_fields(&m_scanData);
|
rc = ble_gap_adv_rsp_set_fields(&m_scanData);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "error setting scan response data; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
NIMBLE_LOGC(LOG_TAG, "error setting scan response data; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
// if not using scan response and there is room,
|
// if not using scan response and there is room,
|
||||||
// throw the tx power data into the advertisment
|
// put the tx power data into the advertisment
|
||||||
} else if (payloadLen < 29) {
|
} else if (payloadLen < 29) {
|
||||||
m_advData.tx_pwr_lvl_is_present = 1;
|
m_advData.tx_pwr_lvl_is_present = 1;
|
||||||
m_advData.tx_pwr_lvl = NimBLEDevice::getPower();
|
m_advData.tx_pwr_lvl = NimBLEDevice::getPower();
|
||||||
|
@ -327,7 +330,7 @@ void NimBLEAdvertising::start() {
|
||||||
|
|
||||||
rc = ble_gap_adv_set_fields(&m_advData);
|
rc = ble_gap_adv_set_fields(&m_advData);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "error setting advertisement data; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
NIMBLE_LOGC(LOG_TAG, "error setting advertisement data; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,22 +352,16 @@ void NimBLEAdvertising::start() {
|
||||||
m_advData.num_uuids16 = 0;
|
m_advData.num_uuids16 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_advSvcsSet = true;
|
m_advDataSet = true;
|
||||||
}
|
|
||||||
|
|
||||||
rc = ble_hs_id_infer_auto(0, &addressType);
|
|
||||||
if (rc != 0) {
|
|
||||||
NIMBLE_LOGC(LOG_TAG, "Error determining address type; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
||||||
abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
rc = ble_gap_adv_start(addressType, NULL, BLE_HS_FOREVER,
|
rc = ble_gap_adv_start(0, NULL, BLE_HS_FOREVER,
|
||||||
&m_advParams,
|
&m_advParams,
|
||||||
(pServer != nullptr) ? NimBLEServer::handleGapEvent : NULL,
|
(pServer != nullptr) ? NimBLEServer::handleGapEvent : NULL,
|
||||||
pServer);
|
pServer);
|
||||||
#else
|
#else
|
||||||
rc = ble_gap_adv_start(addressType, NULL, BLE_HS_FOREVER,
|
rc = ble_gap_adv_start(0, NULL, BLE_HS_FOREVER,
|
||||||
&m_advParams, NULL,NULL);
|
&m_advParams, NULL,NULL);
|
||||||
#endif
|
#endif
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
|
@ -398,7 +395,7 @@ void NimBLEAdvertising::stop() {
|
||||||
* we need clear the flag so it reloads it.
|
* we need clear the flag so it reloads it.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertising::onHostReset() {
|
void NimBLEAdvertising::onHostReset() {
|
||||||
m_advSvcsSet = false;
|
m_advDataSet = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
/**************************/
|
/**************************/
|
||||||
|
|
||||||
#include "NimBLEUUID.h"
|
#include "NimBLEUUID.h"
|
||||||
#include "FreeRTOS.h"
|
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -103,7 +102,7 @@ private:
|
||||||
bool m_customAdvData = false; // Are we using custom advertising data?
|
bool m_customAdvData = false; // Are we using custom advertising data?
|
||||||
bool m_customScanResponseData = false; // Are we using custom scan response data?
|
bool m_customScanResponseData = false; // Are we using custom scan response data?
|
||||||
bool m_scanResp = true;
|
bool m_scanResp = true;
|
||||||
bool m_advSvcsSet = false;
|
bool m_advDataSet = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -19,21 +19,18 @@
|
||||||
#include "NimBLE2902.h"
|
#include "NimBLE2902.h"
|
||||||
#include "NimBLE2904.h"
|
#include "NimBLE2904.h"
|
||||||
#include "NimBLEDevice.h"
|
#include "NimBLEDevice.h"
|
||||||
#include "NimBLEUtils.h"
|
|
||||||
#include "NimBLELog.h"
|
#include "NimBLELog.h"
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#define NULL_HANDLE (0xffff)
|
#define NULL_HANDLE (0xffff)
|
||||||
|
|
||||||
static NimBLECharacteristicCallbacks defaultCallback;
|
static NimBLECharacteristicCallbacks defaultCallback;
|
||||||
|
|
||||||
static const char* LOG_TAG = "NimBLECharacteristic";
|
static const char* LOG_TAG = "NimBLECharacteristic";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Construct a characteristic
|
* @brief Construct a characteristic
|
||||||
* @param [in] uuid - UUID (const char*) for the characteristic.
|
* @param [in] uuid - UUID (const char*) for the characteristic.
|
||||||
* @param [in] properties - Properties for the characteristic.
|
* @param [in] properties - Properties for the characteristic.
|
||||||
|
* @param [in] pService - pointer to the service instance this characteristic belongs to.
|
||||||
*/
|
*/
|
||||||
NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties, NimBLEService* pService)
|
NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties, NimBLEService* pService)
|
||||||
: NimBLECharacteristic(NimBLEUUID(uuid), properties, pService) {
|
: NimBLECharacteristic(NimBLEUUID(uuid), properties, pService) {
|
||||||
|
@ -43,6 +40,7 @@ NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties
|
||||||
* @brief Construct a characteristic
|
* @brief Construct a characteristic
|
||||||
* @param [in] uuid - UUID for the characteristic.
|
* @param [in] uuid - UUID for the characteristic.
|
||||||
* @param [in] properties - Properties for the characteristic.
|
* @param [in] properties - Properties for the characteristic.
|
||||||
|
* @param [in] pService - pointer to the service instance this characteristic belongs to.
|
||||||
*/
|
*/
|
||||||
NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t properties, NimBLEService* pService) {
|
NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t properties, NimBLEService* pService) {
|
||||||
m_uuid = uuid;
|
m_uuid = uuid;
|
||||||
|
@ -50,15 +48,10 @@ NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t prop
|
||||||
m_properties = properties;
|
m_properties = properties;
|
||||||
m_pCallbacks = &defaultCallback;
|
m_pCallbacks = &defaultCallback;
|
||||||
m_pService = pService;
|
m_pService = pService;
|
||||||
// Backward Compatibility - to be removed
|
m_value = "";
|
||||||
/* setBroadcastProperty((properties & PROPERTY_BROADCAST) != 0);
|
m_valMux = portMUX_INITIALIZER_UNLOCKED;
|
||||||
setReadProperty((properties & PROPERTY_READ) != 0);
|
m_pTaskData = nullptr;
|
||||||
setWriteProperty((properties & PROPERTY_WRITE) != 0);
|
m_timestamp = 0;
|
||||||
setNotifyProperty((properties & PROPERTY_NOTIFY) != 0);
|
|
||||||
setIndicateProperty((properties & PROPERTY_INDICATE) != 0);
|
|
||||||
setWriteNoResponseProperty((properties & PROPERTY_WRITE_NR) != 0);
|
|
||||||
*/
|
|
||||||
///////////////////////////////////////////
|
|
||||||
} // NimBLECharacteristic
|
} // NimBLECharacteristic
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,23 +61,6 @@ NimBLECharacteristic::~NimBLECharacteristic() {
|
||||||
} // ~NimBLECharacteristic
|
} // ~NimBLECharacteristic
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Associate a descriptor with this characteristic.
|
|
||||||
* @param [in] pDescriptor
|
|
||||||
* @return N/A.
|
|
||||||
*/
|
|
||||||
void NimBLECharacteristic::addDescriptor(NimBLEDescriptor* pDescriptor) {
|
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> addDescriptor(): Adding %s to %s", pDescriptor->toString().c_str(), toString().c_str());
|
|
||||||
// Check that we don't add the same descriptor twice.
|
|
||||||
if (m_descriptorMap.getByUUID(pDescriptor->getUUID()) != nullptr) {
|
|
||||||
NIMBLE_LOGW(LOG_TAG, "<< Adding a new descriptor with the same UUID as a previous one");
|
|
||||||
//return;
|
|
||||||
}
|
|
||||||
m_descriptorMap.setByUUID(pDescriptor->getUUID(), pDescriptor);
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< addDescriptor()");
|
|
||||||
} // addDescriptor
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a new BLE Descriptor associated with this characteristic.
|
* @brief Create a new BLE Descriptor associated with this characteristic.
|
||||||
* @param [in] uuid - The UUID of the descriptor.
|
* @param [in] uuid - The UUID of the descriptor.
|
||||||
|
@ -104,25 +80,26 @@ NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const char* uuid, uint3
|
||||||
*/
|
*/
|
||||||
NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID &uuid, uint32_t properties, uint16_t max_len) {
|
NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID &uuid, uint32_t properties, uint16_t max_len) {
|
||||||
NimBLEDescriptor* pDescriptor = nullptr;
|
NimBLEDescriptor* pDescriptor = nullptr;
|
||||||
if(uuid.equals(NimBLEUUID((uint16_t)0x2902))) {
|
if(uuid == NimBLEUUID(uint16_t(0x2902))) {
|
||||||
if(!(m_properties & BLE_GATT_CHR_F_NOTIFY) && !(m_properties & BLE_GATT_CHR_F_INDICATE)) {
|
if(!(m_properties & BLE_GATT_CHR_F_NOTIFY) && !(m_properties & BLE_GATT_CHR_F_INDICATE)) {
|
||||||
assert(0 && "Cannot create 2902 descriptior without characteristic notification or indication property set");
|
assert(0 && "Cannot create 2902 descriptior without characteristic notification or indication property set");
|
||||||
}
|
}
|
||||||
// We cannot have more than one 2902 descriptor, if it's already been created just return a pointer to it.
|
// We cannot have more than one 2902 descriptor, if it's already been created just return a pointer to it.
|
||||||
pDescriptor = m_descriptorMap.getByUUID(uuid);
|
pDescriptor = getDescriptorByUUID(uuid);
|
||||||
if(pDescriptor == nullptr) {
|
if(pDescriptor == nullptr) {
|
||||||
pDescriptor = new NimBLE2902(this);
|
pDescriptor = new NimBLE2902(this);
|
||||||
} else {
|
} else {
|
||||||
return pDescriptor;
|
return pDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (uuid.equals(NimBLEUUID((uint16_t)0x2904))) {
|
} else if (uuid == NimBLEUUID(uint16_t(0x2904))) {
|
||||||
pDescriptor = new NimBLE2904(this);
|
pDescriptor = new NimBLE2904(this);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
pDescriptor = new NimBLEDescriptor(uuid, properties, max_len, this);
|
pDescriptor = new NimBLEDescriptor(uuid, properties, max_len, this);
|
||||||
}
|
}
|
||||||
addDescriptor(pDescriptor);
|
|
||||||
|
m_dscVec.push_back(pDescriptor);
|
||||||
return pDescriptor;
|
return pDescriptor;
|
||||||
} // createCharacteristic
|
} // createCharacteristic
|
||||||
|
|
||||||
|
@ -132,8 +109,8 @@ NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID &uuid,
|
||||||
* @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve.
|
* @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve.
|
||||||
* @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned.
|
* @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned.
|
||||||
*/
|
*/
|
||||||
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* descriptorUUID) {
|
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* uuid) {
|
||||||
return m_descriptorMap.getByUUID(NimBLEUUID(descriptorUUID));
|
return getDescriptorByUUID(NimBLEUUID(uuid));
|
||||||
} // getDescriptorByUUID
|
} // getDescriptorByUUID
|
||||||
|
|
||||||
|
|
||||||
|
@ -142,8 +119,13 @@ NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* descript
|
||||||
* @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve.
|
* @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve.
|
||||||
* @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned.
|
* @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned.
|
||||||
*/
|
*/
|
||||||
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &descriptorUUID) {
|
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &uuid) {
|
||||||
return m_descriptorMap.getByUUID(descriptorUUID);
|
for (auto &it : m_dscVec) {
|
||||||
|
if (it->getUUID() == uuid) {
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
} // getDescriptorByUUID
|
} // getDescriptorByUUID
|
||||||
|
|
||||||
|
|
||||||
|
@ -155,13 +137,8 @@ uint16_t NimBLECharacteristic::getHandle() {
|
||||||
return m_handle;
|
return m_handle;
|
||||||
} // getHandle
|
} // getHandle
|
||||||
|
|
||||||
/*
|
|
||||||
void NimBLECharacteristic::setAccessPermissions(uint16_t perm) {
|
|
||||||
m_permissions = perm;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
uint8_t NimBLECharacteristic::getProperties() {
|
uint16_t NimBLECharacteristic::getProperties() {
|
||||||
return m_properties;
|
return m_properties;
|
||||||
} // getProperties
|
} // getProperties
|
||||||
|
|
||||||
|
@ -187,26 +164,28 @@ NimBLEUUID NimBLECharacteristic::getUUID() {
|
||||||
* @brief Retrieve the current value of the characteristic.
|
* @brief Retrieve the current value of the characteristic.
|
||||||
* @return A pointer to storage containing the current characteristic value.
|
* @return A pointer to storage containing the current characteristic value.
|
||||||
*/
|
*/
|
||||||
std::string NimBLECharacteristic::getValue() {
|
std::string NimBLECharacteristic::getValue(time_t *timestamp) {
|
||||||
return m_value.getValue();
|
portENTER_CRITICAL(&m_valMux);
|
||||||
|
std::string retVal = m_value;
|
||||||
|
if(timestamp != nullptr) {
|
||||||
|
*timestamp = m_timestamp;
|
||||||
|
}
|
||||||
|
portEXIT_CRITICAL(&m_valMux);
|
||||||
|
|
||||||
|
return retVal;
|
||||||
} // getValue
|
} // getValue
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Retrieve the current raw data of the characteristic.
|
|
||||||
* @return A pointer to storage containing the current characteristic data.
|
|
||||||
*/
|
|
||||||
uint8_t* NimBLECharacteristic::getData() {
|
|
||||||
return m_value.getData();
|
|
||||||
} // getData
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieve the the current data length of the characteristic.
|
* @brief Retrieve the the current data length of the characteristic.
|
||||||
* @return The length of the current characteristic data.
|
* @return The length of the current characteristic data.
|
||||||
*/
|
*/
|
||||||
size_t NimBLECharacteristic::getDataLength() {
|
size_t NimBLECharacteristic::getDataLength() {
|
||||||
return m_value.getLength();
|
portENTER_CRITICAL(&m_valMux);
|
||||||
|
size_t len = m_value.length();
|
||||||
|
portEXIT_CRITICAL(&m_valMux);
|
||||||
|
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -225,32 +204,41 @@ int NimBLECharacteristic::handleGapEvent(uint16_t conn_handle, uint16_t attr_han
|
||||||
if(ble_uuid_cmp(uuid, &pCharacteristic->getUUID().getNative()->u) == 0){
|
if(ble_uuid_cmp(uuid, &pCharacteristic->getUUID().getNative()->u) == 0){
|
||||||
switch(ctxt->op) {
|
switch(ctxt->op) {
|
||||||
case BLE_GATT_ACCESS_OP_READ_CHR: {
|
case BLE_GATT_ACCESS_OP_READ_CHR: {
|
||||||
//NIMBLE_LOGD(LOG_TAG, "read char pkthdr len:%d flags:%d", ctxt->om->om_pkthdr_len, ctxt->om->om_flags);
|
|
||||||
// If the packet header is only 8 bytes this is a follow up of a long read
|
// If the packet header is only 8 bytes this is a follow up of a long read
|
||||||
// so we don't want to call the onRead() callback again.
|
// so we don't want to call the onRead() callback again.
|
||||||
if(ctxt->om->om_pkthdr_len > 8) {
|
if(ctxt->om->om_pkthdr_len > 8) {
|
||||||
pCharacteristic->m_pCallbacks->onRead(pCharacteristic);
|
pCharacteristic->m_pCallbacks->onRead(pCharacteristic);
|
||||||
}
|
}
|
||||||
rc = os_mbuf_append(ctxt->om, pCharacteristic->getData(), pCharacteristic->m_value.getLength());
|
|
||||||
|
portENTER_CRITICAL(&pCharacteristic->m_valMux);
|
||||||
|
rc = os_mbuf_append(ctxt->om, (uint8_t*)pCharacteristic->m_value.data(),
|
||||||
|
pCharacteristic->m_value.length());
|
||||||
|
portEXIT_CRITICAL(&pCharacteristic->m_valMux);
|
||||||
|
|
||||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||||
}
|
}
|
||||||
|
|
||||||
case BLE_GATT_ACCESS_OP_WRITE_CHR: {
|
case BLE_GATT_ACCESS_OP_WRITE_CHR: {
|
||||||
//NIMBLE_LOGD(LOG_TAG, "write char pkthdr len:%d datalen:%d", ctxt->om->om_pkthdr_len, ctxt->om->om_len);
|
|
||||||
if (ctxt->om->om_len > BLE_ATT_ATTR_MAX_LEN) {
|
if (ctxt->om->om_len > BLE_ATT_ATTR_MAX_LEN) {
|
||||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
//pCharacteristic->setValue(ctxt->om->om_data, ctxt->om->om_len);
|
uint8_t buf[BLE_ATT_ATTR_MAX_LEN];
|
||||||
pCharacteristic->m_value.addPart(ctxt->om->om_data, ctxt->om->om_len);
|
size_t len = ctxt->om->om_len;
|
||||||
|
memcpy(buf, ctxt->om->om_data,len);
|
||||||
|
|
||||||
os_mbuf *next;
|
os_mbuf *next;
|
||||||
next = SLIST_NEXT(ctxt->om, om_next);
|
next = SLIST_NEXT(ctxt->om, om_next);
|
||||||
while(next != NULL){
|
while(next != NULL){
|
||||||
//NIMBLE_LOGD(LOG_TAG, "Found long write data, len:%d", next->om_len);
|
if((len + next->om_len) > BLE_ATT_ATTR_MAX_LEN) {
|
||||||
pCharacteristic->m_value.addPart(next->om_data, next->om_len);
|
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||||
|
}
|
||||||
|
memcpy(&buf[len-1], next->om_data, next->om_len);
|
||||||
|
len += next->om_len;
|
||||||
next = SLIST_NEXT(next, om_next);
|
next = SLIST_NEXT(next, om_next);
|
||||||
}
|
}
|
||||||
pCharacteristic->m_value.commit();
|
|
||||||
|
pCharacteristic->setValue(buf, len);
|
||||||
pCharacteristic->m_pCallbacks->onWrite(pCharacteristic);
|
pCharacteristic->m_pCallbacks->onWrite(pCharacteristic);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -278,14 +266,19 @@ void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) {
|
||||||
subVal |= NIMBLE_DESC_FLAG_INDICATE;
|
subVal |= NIMBLE_DESC_FLAG_INDICATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_semaphoreConfEvt.give((subVal | NIMBLE_DESC_FLAG_INDICATE) ? 0 :
|
if(m_pTaskData != nullptr) {
|
||||||
NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_DISABLED);
|
m_pTaskData->rc = (subVal & NIMBLE_DESC_FLAG_INDICATE) ? 0 :
|
||||||
|
NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_DISABLED;
|
||||||
|
xTaskNotifyGive(m_pTaskData->task);
|
||||||
|
}
|
||||||
|
|
||||||
NIMBLE_LOGI(LOG_TAG, "New subscribe value for conn: %d val: %d", event->subscribe.conn_handle, subVal);
|
NIMBLE_LOGI(LOG_TAG, "New subscribe value for conn: %d val: %d",
|
||||||
|
event->subscribe.conn_handle, subVal);
|
||||||
|
|
||||||
NimBLE2902* p2902 = (NimBLE2902*)getDescriptorByUUID((uint16_t)0x2902);
|
NimBLE2902* p2902 = (NimBLE2902*)getDescriptorByUUID(uint16_t(0x2902));
|
||||||
if(p2902 == nullptr){
|
if(p2902 == nullptr){
|
||||||
ESP_LOGE(LOG_TAG, "No 2902 descriptor found for %s", getUUID().toString().c_str());
|
ESP_LOGE(LOG_TAG, "No 2902 descriptor found for %s",
|
||||||
|
std::string(getUUID()).c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,21 +287,28 @@ void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) {
|
||||||
p2902->m_pCallbacks->onWrite(p2902);
|
p2902->m_pCallbacks->onWrite(p2902);
|
||||||
|
|
||||||
|
|
||||||
auto it = p2902->m_subscribedMap.find(event->subscribe.conn_handle);
|
auto it = p2902->m_subscribedVec.begin();
|
||||||
if(subVal > 0 && it == p2902->m_subscribedMap.cend()) {
|
for(;it != p2902->m_subscribedVec.end(); ++it) {
|
||||||
p2902->m_subscribedMap.insert(std::pair<uint16_t, uint16_t>(event->subscribe.conn_handle, subVal));
|
if((*it).conn_id == event->subscribe.conn_handle) {
|
||||||
return;
|
break;
|
||||||
} else if(it != p2902->m_subscribedMap.cend()) {
|
}
|
||||||
p2902->m_subscribedMap.erase(event->subscribe.conn_handle);
|
}
|
||||||
|
|
||||||
|
if(subVal > 0) {
|
||||||
|
if(it == p2902->m_subscribedVec.end()) {
|
||||||
|
chr_sub_status_t client_sub;
|
||||||
|
client_sub.conn_id = event->subscribe.conn_handle;
|
||||||
|
client_sub.sub_val = subVal;
|
||||||
|
p2902->m_subscribedVec.push_back(client_sub);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
if(event->subscribe.reason == BLE_GAP_SUBSCRIBE_REASON_TERM) {
|
(*it).sub_val = subVal;
|
||||||
p2902->m_subscribedMap.erase(event->subscribe.conn_handle);
|
|
||||||
return;
|
} else if(it != p2902->m_subscribedVec.end()) {
|
||||||
|
p2902->m_subscribedVec.erase(it);
|
||||||
|
p2902->m_subscribedVec.shrink_to_fit();
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
(*it).second = subVal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -319,7 +319,7 @@ void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) {
|
||||||
* @return N/A
|
* @return N/A
|
||||||
*/
|
*/
|
||||||
void NimBLECharacteristic::indicate() {
|
void NimBLECharacteristic::indicate() {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> indicate: length: %d", m_value.getValue().length());
|
NIMBLE_LOGD(LOG_TAG, ">> indicate: length: %d", getDataLength());
|
||||||
notify(false);
|
notify(false);
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< indicate");
|
NIMBLE_LOGD(LOG_TAG, "<< indicate");
|
||||||
} // indicate
|
} // indicate
|
||||||
|
@ -331,91 +331,102 @@ void NimBLECharacteristic::indicate() {
|
||||||
* @return N/A.
|
* @return N/A.
|
||||||
*/
|
*/
|
||||||
void NimBLECharacteristic::notify(bool is_notification) {
|
void NimBLECharacteristic::notify(bool is_notification) {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> notify: length: %d", m_value.getValue().length());
|
NIMBLE_LOGD(LOG_TAG, ">> notify: length: %d", getDataLength());
|
||||||
|
|
||||||
assert(getService() != nullptr);
|
NimBLE2902* p2902 = (NimBLE2902*)getDescriptorByUUID(uint16_t(0x2902));
|
||||||
assert(getService()->getServer() != nullptr);
|
|
||||||
|
|
||||||
|
if(p2902 == nullptr) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG,
|
||||||
|
"<< notify-Error; Notify/indicate not enabled for characterisitc: %s",
|
||||||
|
std::string(getUUID()).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
if (getService()->getServer()->getConnectedCount() == 0) {
|
if (p2902->m_subscribedVec.size() == 0) {
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< notify: No connected clients.");
|
NIMBLE_LOGD(LOG_TAG, "<< notify: No clients subscribed.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pCallbacks->onNotify(this);
|
m_pCallbacks->onNotify(this);
|
||||||
|
|
||||||
|
std::string value = getValue();
|
||||||
|
size_t length = value.length();
|
||||||
|
bool reqSec = (m_properties & BLE_GATT_CHR_F_READ_AUTHEN) ||
|
||||||
|
(m_properties & BLE_GATT_CHR_F_READ_AUTHOR) ||
|
||||||
|
(m_properties & BLE_GATT_CHR_F_READ_ENC);
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
NimBLE2902* p2902 = (NimBLE2902*)getDescriptorByUUID((uint16_t)0x2902);
|
|
||||||
|
|
||||||
for (auto it = p2902->m_subscribedMap.cbegin(); it != p2902->m_subscribedMap.cend(); ++it) {
|
for (auto &it : p2902->m_subscribedVec) {
|
||||||
uint16_t _mtu = getService()->getServer()->getPeerMTU((*it).first);
|
uint16_t _mtu = getService()->getServer()->getPeerMTU(it.conn_id);
|
||||||
// Must rebuild the data on each loop iteration as NimBLE will release it.
|
|
||||||
size_t length = m_value.getValue().length();
|
|
||||||
uint8_t* data = (uint8_t*)m_value.getValue().data();
|
|
||||||
os_mbuf *om;
|
|
||||||
|
|
||||||
if(_mtu == 0) {
|
// check if connected and subscribed
|
||||||
//NIMBLE_LOGD(LOG_TAG, "peer not connected, removing from map");
|
if(_mtu == 0 || it.sub_val == 0) {
|
||||||
p2902->m_subscribedMap.erase((*it).first);
|
|
||||||
it = p2902->m_subscribedMap.cbegin();
|
|
||||||
if(it == p2902->m_subscribedMap.cend()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if security requirements are satisfied
|
||||||
|
if(reqSec) {
|
||||||
|
struct ble_gap_conn_desc desc;
|
||||||
|
rc = ble_gap_conn_find(it.conn_id, &desc);
|
||||||
|
if(rc != 0 || !desc.sec_state.encrypted) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (length > _mtu - 3) {
|
if (length > _mtu - 3) {
|
||||||
NIMBLE_LOGW(LOG_TAG, "- Truncating to %d bytes (maximum notify size)", _mtu - 3);
|
NIMBLE_LOGW(LOG_TAG, "- Truncating to %d bytes (maximum notify size)", _mtu - 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((*it).second == 0) {
|
if(is_notification && (!(it.sub_val & NIMBLE_DESC_FLAG_NOTIFY))) {
|
||||||
//NIMBLE_LOGI(LOG_TAG, "Skipping unsubscribed client");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_notification && (!((*it).second & NIMBLE_DESC_FLAG_NOTIFY))) {
|
|
||||||
NIMBLE_LOGW(LOG_TAG,
|
NIMBLE_LOGW(LOG_TAG,
|
||||||
"Sending notification to client subscribed to indications, sending indication instead");
|
"Sending notification to client subscribed to indications, sending indication instead");
|
||||||
is_notification = false;
|
is_notification = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!is_notification && (!((*it).second & NIMBLE_DESC_FLAG_INDICATE))) {
|
if(!is_notification && (!(it.sub_val & NIMBLE_DESC_FLAG_INDICATE))) {
|
||||||
NIMBLE_LOGW(LOG_TAG,
|
NIMBLE_LOGW(LOG_TAG,
|
||||||
"Sending indication to client subscribed to notifications, sending notifications instead");
|
"Sending indication to client subscribed to notification, sending notification instead");
|
||||||
is_notification = true;
|
is_notification = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't create the m_buf until we are sure to send the data or else
|
// don't create the m_buf until we are sure to send the data or else
|
||||||
// we could be allocating a buffer that doesn't get released.
|
// we could be allocating a buffer that doesn't get released.
|
||||||
// We also must create it in each loop iteration because it is consumed with each host call.
|
// We also must create it in each loop iteration because it is consumed with each host call.
|
||||||
om = ble_hs_mbuf_from_flat(data, length);
|
os_mbuf *om = ble_hs_mbuf_from_flat((uint8_t*)value.data(), length);
|
||||||
|
|
||||||
if(!is_notification) {
|
NimBLECharacteristicCallbacks::Status statusRC;
|
||||||
m_semaphoreConfEvt.take("indicate");
|
|
||||||
rc = ble_gattc_indicate_custom((*it).first, m_handle, om);
|
if(!is_notification && (m_properties & NIMBLE_PROPERTY::INDICATE)) {
|
||||||
|
ble_task_data_t taskData = {nullptr, xTaskGetCurrentTaskHandle(),0, nullptr};
|
||||||
|
m_pTaskData = &taskData;
|
||||||
|
|
||||||
|
rc = ble_gattc_indicate_custom(it.conn_id, m_handle, om);
|
||||||
if(rc != 0){
|
if(rc != 0){
|
||||||
m_semaphoreConfEvt.give();
|
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_GATT;
|
||||||
m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::ERROR_GATT, rc);
|
} else {
|
||||||
return;
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
rc = m_pTaskData->rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = m_semaphoreConfEvt.wait();
|
m_pTaskData = nullptr;
|
||||||
|
|
||||||
if(rc == BLE_HS_ETIMEOUT) {
|
if(rc == BLE_HS_EDONE) {
|
||||||
m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_TIMEOUT, rc);
|
rc = 0;
|
||||||
} else if(rc == BLE_HS_EDONE) {
|
statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_INDICATE;
|
||||||
m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::SUCCESS_INDICATE, rc);
|
} else if(rc == BLE_HS_ETIMEOUT) {
|
||||||
|
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_TIMEOUT;
|
||||||
} else {
|
} else {
|
||||||
m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_FAILURE, rc);
|
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_FAILURE;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rc = ble_gattc_notify_custom((*it).first, m_handle, om);
|
rc = ble_gattc_notify_custom(it.conn_id, m_handle, om);
|
||||||
if(rc == 0) {
|
if(rc == 0) {
|
||||||
m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::SUCCESS_NOTIFY, 0);
|
statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_NOTIFY;
|
||||||
} else {
|
} else {
|
||||||
m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::ERROR_GATT, rc);
|
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_GATT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_pCallbacks->onStatus(this, statusRC, rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< notify");
|
NIMBLE_LOGD(LOG_TAG, "<< notify");
|
||||||
|
@ -434,87 +445,6 @@ void NimBLECharacteristic::setCallbacks(NimBLECharacteristicCallbacks* pCallback
|
||||||
}
|
}
|
||||||
} // setCallbacks
|
} // setCallbacks
|
||||||
|
|
||||||
// Backward compatibility - to be removed ////////////////////////////////
|
|
||||||
/**
|
|
||||||
* @brief Set the permission to broadcast.
|
|
||||||
* A characteristics has properties associated with it which define what it is capable of doing.
|
|
||||||
* One of these is the broadcast flag.
|
|
||||||
* @param [in] value The flag value of the property.
|
|
||||||
* @return N/A
|
|
||||||
*/
|
|
||||||
void NimBLECharacteristic::setBroadcastProperty(bool value) {
|
|
||||||
if (value) {
|
|
||||||
m_properties = (m_properties | BLE_GATT_CHR_F_BROADCAST);
|
|
||||||
} else {
|
|
||||||
m_properties = (m_properties & ~BLE_GATT_CHR_F_BROADCAST);
|
|
||||||
}
|
|
||||||
} // setBroadcastProperty
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the Indicate property value.
|
|
||||||
* @param [in] value Set to true if we are to allow indicate messages.
|
|
||||||
*/
|
|
||||||
void NimBLECharacteristic::setIndicateProperty(bool value) {
|
|
||||||
if (value) {
|
|
||||||
m_properties = (m_properties | BLE_GATT_CHR_F_INDICATE);
|
|
||||||
} else {
|
|
||||||
m_properties = (m_properties & ~BLE_GATT_CHR_F_INDICATE);
|
|
||||||
}
|
|
||||||
} // setIndicateProperty
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the Notify property value.
|
|
||||||
* @param [in] value Set to true if we are to allow notification messages.
|
|
||||||
*/
|
|
||||||
void NimBLECharacteristic::setNotifyProperty(bool value) {
|
|
||||||
if (value) {
|
|
||||||
m_properties = (m_properties | BLE_GATT_CHR_F_NOTIFY);
|
|
||||||
} else {
|
|
||||||
m_properties = (m_properties & ~BLE_GATT_CHR_F_NOTIFY);
|
|
||||||
}
|
|
||||||
} // setNotifyProperty
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the Read property value.
|
|
||||||
* @param [in] value Set to true if we are to allow reads.
|
|
||||||
*/
|
|
||||||
void NimBLECharacteristic::setReadProperty(bool value) {
|
|
||||||
if (value) {
|
|
||||||
m_properties = (m_properties | BLE_GATT_CHR_F_READ);
|
|
||||||
} else {
|
|
||||||
m_properties = (m_properties & ~BLE_GATT_CHR_F_READ);
|
|
||||||
}
|
|
||||||
} // setReadProperty
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the Write No Response property value.
|
|
||||||
* @param [in] value Set to true if we are to allow writes with no response.
|
|
||||||
*/
|
|
||||||
void NimBLECharacteristic::setWriteNoResponseProperty(bool value) {
|
|
||||||
if (value) {
|
|
||||||
m_properties = (m_properties | BLE_GATT_CHR_F_WRITE_NO_RSP);
|
|
||||||
} else {
|
|
||||||
m_properties = (m_properties & ~BLE_GATT_CHR_F_WRITE_NO_RSP);
|
|
||||||
}
|
|
||||||
} // setWriteNoResponseProperty
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the Write property value.
|
|
||||||
* @param [in] value Set to true if we are to allow writes.
|
|
||||||
*/
|
|
||||||
void NimBLECharacteristic::setWriteProperty(bool value) {
|
|
||||||
if (value) {
|
|
||||||
m_properties = (m_properties | BLE_GATT_CHR_F_WRITE );
|
|
||||||
} else {
|
|
||||||
m_properties = (m_properties & ~BLE_GATT_CHR_F_WRITE );
|
|
||||||
}
|
|
||||||
} // setWriteProperty
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the value of the characteristic.
|
* @brief Set the value of the characteristic.
|
||||||
|
@ -522,21 +452,21 @@ void NimBLECharacteristic::setWriteProperty(bool value) {
|
||||||
* @param [in] length The length of the data in bytes.
|
* @param [in] length The length of the data in bytes.
|
||||||
*/
|
*/
|
||||||
void NimBLECharacteristic::setValue(const uint8_t* data, size_t length) {
|
void NimBLECharacteristic::setValue(const uint8_t* data, size_t length) {
|
||||||
|
#if CONFIG_LOG_DEFAULT_LEVEL > 3 || (ARDUINO_ARCH_ESP32 && CORE_DEBUG_LEVEL >= 4)
|
||||||
char* pHex = NimBLEUtils::buildHexData(nullptr, data, length);
|
char* pHex = NimBLEUtils::buildHexData(nullptr, data, length);
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> setValue: length=%d, data=%s, characteristic UUID=%s", length, pHex, getUUID().toString().c_str());
|
NIMBLE_LOGD(LOG_TAG, ">> setValue: length=%d, data=%s, characteristic UUID=%s", length, pHex, getUUID().toString().c_str());
|
||||||
free(pHex);
|
free(pHex);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (length > BLE_ATT_ATTR_MAX_LEN) {
|
if (length > BLE_ATT_ATTR_MAX_LEN) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, BLE_ATT_ATTR_MAX_LEN);
|
NIMBLE_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, BLE_ATT_ATTR_MAX_LEN);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_value.setValue(data, length);
|
portENTER_CRITICAL(&m_valMux);
|
||||||
|
m_value = std::string((char*)data, length);
|
||||||
// if(m_handle != NULL_HANDLE) {
|
m_timestamp = time(nullptr);
|
||||||
//ble_gatts_chr_updated(m_handle);
|
portEXIT_CRITICAL(&m_valMux);
|
||||||
// ble_gattc_notify(getService()->getServer()->m_connId, m_handle);
|
|
||||||
// }
|
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< setValue");
|
NIMBLE_LOGD(LOG_TAG, "<< setValue");
|
||||||
} // setValue
|
} // setValue
|
||||||
|
@ -553,41 +483,6 @@ void NimBLECharacteristic::setValue(const std::string &value) {
|
||||||
setValue((uint8_t*)(value.data()), value.length());
|
setValue((uint8_t*)(value.data()), value.length());
|
||||||
} // setValue
|
} // setValue
|
||||||
|
|
||||||
void NimBLECharacteristic::setValue(uint16_t& data16) {
|
|
||||||
uint8_t temp[2];
|
|
||||||
temp[0] = data16;
|
|
||||||
temp[1] = data16 >> 8;
|
|
||||||
setValue(temp, 2);
|
|
||||||
} // setValue
|
|
||||||
|
|
||||||
void NimBLECharacteristic::setValue(uint32_t& data32) {
|
|
||||||
uint8_t temp[4];
|
|
||||||
temp[0] = data32;
|
|
||||||
temp[1] = data32 >> 8;
|
|
||||||
temp[2] = data32 >> 16;
|
|
||||||
temp[3] = data32 >> 24;
|
|
||||||
setValue(temp, 4);
|
|
||||||
} // setValue
|
|
||||||
|
|
||||||
void NimBLECharacteristic::setValue(int& data32) {
|
|
||||||
uint8_t temp[4];
|
|
||||||
temp[0] = data32;
|
|
||||||
temp[1] = data32 >> 8;
|
|
||||||
temp[2] = data32 >> 16;
|
|
||||||
temp[3] = data32 >> 24;
|
|
||||||
setValue(temp, 4);
|
|
||||||
} // setValue
|
|
||||||
|
|
||||||
void NimBLECharacteristic::setValue(float& data32) {
|
|
||||||
float temp = data32;
|
|
||||||
setValue((uint8_t*)&temp, 4);
|
|
||||||
} // setValue
|
|
||||||
|
|
||||||
void NimBLECharacteristic::setValue(double& data64) {
|
|
||||||
double temp = data64;
|
|
||||||
setValue((uint8_t*)&temp, 8);
|
|
||||||
} // setValue
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return a string representation of the characteristic.
|
* @brief Return a string representation of the characteristic.
|
||||||
|
|
|
@ -42,42 +42,15 @@ typedef enum {
|
||||||
|
|
||||||
#include "NimBLEService.h"
|
#include "NimBLEService.h"
|
||||||
#include "NimBLEDescriptor.h"
|
#include "NimBLEDescriptor.h"
|
||||||
#include "NimBLEUUID.h"
|
|
||||||
#include "NimBLEValue.h"
|
|
||||||
#include "FreeRTOS.h"
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
class NimBLEService;
|
class NimBLEService;
|
||||||
class NimBLEDescriptor;
|
class NimBLEDescriptor;
|
||||||
class NimBLECharacteristicCallbacks;
|
class NimBLECharacteristicCallbacks;
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A management structure for %BLE descriptors.
|
|
||||||
*/
|
|
||||||
class NimBLEDescriptorMap {
|
|
||||||
public:
|
|
||||||
void setByUUID(const char* uuid, NimBLEDescriptor* pDescriptor);
|
|
||||||
void setByUUID(const NimBLEUUID &uuid, NimBLEDescriptor* pDescriptor);
|
|
||||||
// void setByHandle(uint16_t handle, NimBLEDescriptor* pDescriptor);
|
|
||||||
NimBLEDescriptor* getByUUID(const char* uuid);
|
|
||||||
NimBLEDescriptor* getByUUID(const NimBLEUUID &uuid);
|
|
||||||
// NimBLEDescriptor* getByHandle(uint16_t handle);
|
|
||||||
std::string toString();
|
|
||||||
NimBLEDescriptor* getFirst();
|
|
||||||
NimBLEDescriptor* getNext();
|
|
||||||
uint8_t getSize();
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::map<NimBLEDescriptor*, std::string> m_uuidMap;
|
|
||||||
// std::map<uint16_t, BLEDescriptor*> m_handleMap;
|
|
||||||
std::map<NimBLEDescriptor*, std::string>::iterator m_iterator;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The model of a %BLE Characteristic.
|
* @brief The model of a %BLE Characteristic.
|
||||||
*
|
*
|
||||||
|
@ -87,84 +60,78 @@ private:
|
||||||
class NimBLECharacteristic {
|
class NimBLECharacteristic {
|
||||||
public:
|
public:
|
||||||
NimBLEDescriptor* createDescriptor(const char* uuid,
|
NimBLEDescriptor* createDescriptor(const char* uuid,
|
||||||
uint32_t properties = NIMBLE_PROPERTY::READ |
|
uint32_t properties =
|
||||||
|
NIMBLE_PROPERTY::READ |
|
||||||
NIMBLE_PROPERTY::WRITE,
|
NIMBLE_PROPERTY::WRITE,
|
||||||
uint16_t max_len = 100);
|
uint16_t max_len = 100);
|
||||||
NimBLEDescriptor* createDescriptor(const NimBLEUUID &uuid,
|
NimBLEDescriptor* createDescriptor(const NimBLEUUID &uuid,
|
||||||
uint32_t properties = NIMBLE_PROPERTY::READ |
|
uint32_t properties =
|
||||||
|
NIMBLE_PROPERTY::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* uuid);
|
||||||
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &descriptorUUID);
|
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &uuid);
|
||||||
NimBLEUUID getUUID();
|
NimBLEUUID getUUID();
|
||||||
std::string getValue();
|
std::string getValue(time_t *timestamp = nullptr);
|
||||||
uint8_t* getData();
|
|
||||||
size_t getDataLength();
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
|
||||||
|
std::string value = getValue();
|
||||||
|
if(!skipSizeCheck && value.size() < sizeof(T)) return T();
|
||||||
|
const char *pData = value.data();
|
||||||
|
return *((T *)pData);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t getDataLength();
|
||||||
void indicate();
|
void indicate();
|
||||||
void notify(bool is_notification = true);
|
void notify(bool is_notification = true);
|
||||||
void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
|
void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
|
||||||
// Backward Compatibility - to be removed
|
|
||||||
void setBroadcastProperty(bool value);
|
|
||||||
void setIndicateProperty(bool value);
|
|
||||||
void setNotifyProperty(bool value);
|
|
||||||
void setReadProperty(bool value);
|
|
||||||
void setWriteProperty(bool value);
|
|
||||||
void setWriteNoResponseProperty(bool value);
|
|
||||||
//////////////////////////////////////////////////////
|
|
||||||
void setValue(const uint8_t* data, size_t size);
|
void setValue(const uint8_t* data, size_t size);
|
||||||
void setValue(const std::string &value);
|
void setValue(const std::string &value);
|
||||||
void setValue(uint16_t& data16);
|
|
||||||
void setValue(uint32_t& data32);
|
template<typename T>
|
||||||
void setValue(int& data32);
|
void setValue(const T &s) {
|
||||||
void setValue(float& data32);
|
setValue((uint8_t*)&s, sizeof(T));
|
||||||
void setValue(double& data64);
|
}
|
||||||
|
|
||||||
std::string toString();
|
std::string toString();
|
||||||
uint16_t getHandle();
|
uint16_t getHandle();
|
||||||
// void setAccessPermissions(uint16_t perm);
|
|
||||||
|
|
||||||
// Backward Compatibility - to be removed
|
|
||||||
/* static const uint32_t PROPERTY_READ = 1<<0;
|
|
||||||
static const uint32_t PROPERTY_WRITE = 1<<1;
|
|
||||||
static const uint32_t PROPERTY_NOTIFY = 1<<2;
|
|
||||||
static const uint32_t PROPERTY_BROADCAST = 1<<3;
|
|
||||||
static const uint32_t PROPERTY_INDICATE = 1<<4;
|
|
||||||
static const uint32_t PROPERTY_WRITE_NR = 1<<5;
|
|
||||||
*/
|
|
||||||
//////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
friend class NimBLEServer;
|
friend class NimBLEServer;
|
||||||
friend class NimBLEService;
|
friend class NimBLEService;
|
||||||
// friend class NimBLEDescriptor;
|
|
||||||
// friend class NimBLECharacteristicMap;
|
|
||||||
|
|
||||||
NimBLECharacteristic(const char* uuid, uint16_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
|
NimBLECharacteristic(const char* uuid,
|
||||||
|
uint16_t properties =
|
||||||
|
NIMBLE_PROPERTY::READ |
|
||||||
|
NIMBLE_PROPERTY::WRITE,
|
||||||
NimBLEService* pService = nullptr);
|
NimBLEService* pService = nullptr);
|
||||||
NimBLECharacteristic(const 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();
|
|
||||||
|
|
||||||
NimBLEUUID m_uuid;
|
~NimBLECharacteristic();
|
||||||
NimBLEDescriptorMap m_descriptorMap;
|
|
||||||
uint16_t m_handle;
|
|
||||||
uint16_t m_properties;
|
|
||||||
NimBLECharacteristicCallbacks* m_pCallbacks;
|
|
||||||
NimBLEService* m_pService;
|
|
||||||
NimBLEValue m_value;
|
|
||||||
// uint16_t m_permissions;
|
|
||||||
|
|
||||||
void addDescriptor(NimBLEDescriptor* pDescriptor);
|
|
||||||
NimBLEService* getService();
|
NimBLEService* getService();
|
||||||
uint8_t getProperties();
|
uint16_t getProperties();
|
||||||
void setSubscribe(struct ble_gap_event *event);
|
void setSubscribe(struct ble_gap_event *event);
|
||||||
static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||||
|
|
||||||
FreeRTOS::Semaphore m_semaphoreConfEvt = FreeRTOS::Semaphore("ConfEvt");
|
NimBLEUUID m_uuid;
|
||||||
|
uint16_t m_handle;
|
||||||
|
uint16_t m_properties;
|
||||||
|
NimBLECharacteristicCallbacks* m_pCallbacks;
|
||||||
|
NimBLEService* m_pService;
|
||||||
|
std::string m_value;
|
||||||
|
std::vector<NimBLEDescriptor*> m_dscVec;
|
||||||
|
ble_task_data_t *m_pTaskData;
|
||||||
|
portMUX_TYPE m_valMux;
|
||||||
|
time_t m_timestamp;
|
||||||
}; // NimBLECharacteristic
|
}; // NimBLECharacteristic
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,132 +0,0 @@
|
||||||
/*
|
|
||||||
* NimBLECharacteristicMap.cpp
|
|
||||||
*
|
|
||||||
* Created: on March 3, 2020
|
|
||||||
* Author H2zero
|
|
||||||
*
|
|
||||||
* BLECharacteristicMap.cpp
|
|
||||||
*
|
|
||||||
* Created on: Jun 22, 2017
|
|
||||||
* Author: kolban
|
|
||||||
*/
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
|
|
||||||
#include "NimBLEService.h"
|
|
||||||
#include "NimBLELog.h"
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the characteristic by handle.
|
|
||||||
* @param [in] handle The handle to look up the characteristic.
|
|
||||||
* @return The characteristic.
|
|
||||||
*/
|
|
||||||
NimBLECharacteristic* NimBLECharacteristicMap::getByHandle(uint16_t handle) {
|
|
||||||
return m_handleMap.at(handle);
|
|
||||||
} // getByHandle
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the characteristic by UUID.
|
|
||||||
* @param [in] UUID The UUID to look up the characteristic.
|
|
||||||
* @return The characteristic.
|
|
||||||
*/
|
|
||||||
NimBLECharacteristic* NimBLECharacteristicMap::getByUUID(const char* uuid) {
|
|
||||||
return getByUUID(NimBLEUUID(uuid));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the characteristic by UUID.
|
|
||||||
* @param [in] UUID The UUID to look up the characteristic.
|
|
||||||
* @return The characteristic.
|
|
||||||
*/
|
|
||||||
NimBLECharacteristic* NimBLECharacteristicMap::getByUUID(const NimBLEUUID &uuid) {
|
|
||||||
for (auto &myPair : m_uuidMap) {
|
|
||||||
if (myPair.first->getUUID().equals(uuid)) {
|
|
||||||
return myPair.first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
} // getByUUID
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the number of characteristics in the map.
|
|
||||||
*/
|
|
||||||
uint8_t NimBLECharacteristicMap::getSize() {
|
|
||||||
return (uint8_t)m_uuidMap.size();
|
|
||||||
} // getSize
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the first characteristic in the map.
|
|
||||||
* @return The first characteristic in the map.
|
|
||||||
*/
|
|
||||||
NimBLECharacteristic* NimBLECharacteristicMap::getFirst() {
|
|
||||||
m_iterator = m_uuidMap.begin();
|
|
||||||
if (m_iterator == m_uuidMap.end()) return nullptr;
|
|
||||||
NimBLECharacteristic* pRet = m_iterator->first;
|
|
||||||
m_iterator++;
|
|
||||||
return pRet;
|
|
||||||
} // getFirst
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the next characteristic in the map.
|
|
||||||
* @return The next characteristic in the map.
|
|
||||||
*/
|
|
||||||
NimBLECharacteristic* NimBLECharacteristicMap::getNext() {
|
|
||||||
if (m_iterator == m_uuidMap.end()) return nullptr;
|
|
||||||
NimBLECharacteristic* pRet = m_iterator->first;
|
|
||||||
m_iterator++;
|
|
||||||
return pRet;
|
|
||||||
} // getNext
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the characteristic by handle.
|
|
||||||
* @param [in] handle The handle of the characteristic.
|
|
||||||
* @param [in] characteristic The characteristic to cache.
|
|
||||||
* @return N/A.
|
|
||||||
*/
|
|
||||||
void NimBLECharacteristicMap::setByHandle(uint16_t handle, NimBLECharacteristic* characteristic) {
|
|
||||||
m_handleMap.insert(std::pair<uint16_t, NimBLECharacteristic*>(handle, characteristic));
|
|
||||||
} // setByHandle
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the characteristic by UUID.
|
|
||||||
* @param [in] uuid The uuid of the characteristic.
|
|
||||||
* @param [in] characteristic The characteristic to cache.
|
|
||||||
* @return N/A.
|
|
||||||
*/
|
|
||||||
void NimBLECharacteristicMap::setByUUID(NimBLECharacteristic* pCharacteristic, const NimBLEUUID &uuid) {
|
|
||||||
m_uuidMap.insert(std::pair<NimBLECharacteristic*, std::string>(pCharacteristic, uuid.toString()));
|
|
||||||
} // setByUUID
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return a string representation of the characteristic map.
|
|
||||||
* @return A string representation of the characteristic map.
|
|
||||||
*/
|
|
||||||
std::string NimBLECharacteristicMap::toString() {
|
|
||||||
std::string res;
|
|
||||||
int count = 0;
|
|
||||||
char hex[5];
|
|
||||||
for (auto &myPair: m_uuidMap) {
|
|
||||||
if (count > 0) {res += "\n";}
|
|
||||||
snprintf(hex, sizeof(hex), "%04x", myPair.first->getHandle());
|
|
||||||
count++;
|
|
||||||
res += "handle: 0x";
|
|
||||||
res += hex;
|
|
||||||
res += ", uuid: " + myPair.first->getUUID().toString();
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
} // toString
|
|
||||||
|
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
|
@ -18,7 +18,6 @@
|
||||||
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||||
|
|
||||||
#include "NimBLEClient.h"
|
#include "NimBLEClient.h"
|
||||||
#include "NimBLEUtils.h"
|
|
||||||
#include "NimBLEDevice.h"
|
#include "NimBLEDevice.h"
|
||||||
#include "NimBLELog.h"
|
#include "NimBLELog.h"
|
||||||
|
|
||||||
|
@ -54,7 +53,10 @@ 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_isConnected = false;
|
m_isConnected = false;
|
||||||
|
m_waitingToConnect = false;
|
||||||
m_connectTimeout = 30000;
|
m_connectTimeout = 30000;
|
||||||
|
m_deleteCallbacks = false;
|
||||||
|
m_pTaskData = nullptr;
|
||||||
|
|
||||||
m_pConnParams.scan_itvl = 16; // Scan interval in 0.625ms units (NimBLE Default)
|
m_pConnParams.scan_itvl = 16; // Scan interval in 0.625ms units (NimBLE Default)
|
||||||
m_pConnParams.scan_window = 16; // Scan window in 0.625ms units (NimBLE Default)
|
m_pConnParams.scan_window = 16; // Scan window in 0.625ms units (NimBLE Default)
|
||||||
|
@ -74,7 +76,7 @@ NimBLEClient::NimBLEClient()
|
||||||
NimBLEClient::~NimBLEClient() {
|
NimBLEClient::~NimBLEClient() {
|
||||||
// We may have allocated service references associated with this client.
|
// We may have allocated service references associated with this client.
|
||||||
// Before we are finished with the client, we must release resources.
|
// Before we are finished with the client, we must release resources.
|
||||||
clearServices();
|
deleteServices();
|
||||||
|
|
||||||
if(m_deleteCallbacks && m_pClientCallbacks != &defaultCallbacks) {
|
if(m_deleteCallbacks && m_pClientCallbacks != &defaultCallbacks) {
|
||||||
delete m_pClientCallbacks;
|
delete m_pClientCallbacks;
|
||||||
|
@ -84,18 +86,40 @@ NimBLEClient::~NimBLEClient() {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Clear any existing services.
|
* @brief Delete any existing services.
|
||||||
*/
|
*/
|
||||||
void NimBLEClient::clearServices() {
|
void NimBLEClient::deleteServices() {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> clearServices");
|
NIMBLE_LOGD(LOG_TAG, ">> deleteServices");
|
||||||
// Delete all the services.
|
// Delete all the services.
|
||||||
for(auto &it: m_servicesVector) {
|
for(auto &it: m_servicesVector) {
|
||||||
delete it;
|
delete it;
|
||||||
}
|
}
|
||||||
m_servicesVector.clear();
|
m_servicesVector.clear();
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< clearServices");
|
NIMBLE_LOGD(LOG_TAG, "<< deleteServices");
|
||||||
} // clearServices
|
} // deleteServices
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete service by UUID
|
||||||
|
* @param [in] uuid The UUID of the service to be deleted from the local database.
|
||||||
|
* @return Number of services left.
|
||||||
|
*/
|
||||||
|
size_t NimBLEClient::deleteService(const NimBLEUUID &uuid) {
|
||||||
|
NIMBLE_LOGD(LOG_TAG, ">> deleteService");
|
||||||
|
// Delete the requested service.
|
||||||
|
for(auto it = m_servicesVector.begin(); it != m_servicesVector.end(); ++it) {
|
||||||
|
if((*it)->getUUID() == uuid) {
|
||||||
|
delete *it;
|
||||||
|
m_servicesVector.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NIMBLE_LOGD(LOG_TAG, "<< deleteService");
|
||||||
|
|
||||||
|
return m_servicesVector.size();
|
||||||
|
} // deleteServices
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -135,6 +159,10 @@ bool NimBLEClient::connect(const NimBLEAddress &address, uint8_t type, bool refr
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!NimBLEDevice::getScan()->stop()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
m_peerAddress = address;
|
m_peerAddress = address;
|
||||||
|
|
||||||
|
@ -142,7 +170,8 @@ bool NimBLEClient::connect(const NimBLEAddress &address, uint8_t type, bool refr
|
||||||
memcpy(&peerAddrt.val, address.getNative(),6);
|
memcpy(&peerAddrt.val, address.getNative(),6);
|
||||||
peerAddrt.type = type;
|
peerAddrt.type = type;
|
||||||
|
|
||||||
m_semaphoreOpenEvt.take("connect");
|
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
|
||||||
|
m_pTaskData = &taskData;
|
||||||
|
|
||||||
/** Try to connect the the advertiser. Allow 30 seconds (30000 ms) for
|
/** Try to connect the the advertiser. Allow 30 seconds (30000 ms) for
|
||||||
* timeout (default value of m_connectTimeout).
|
* timeout (default value of m_connectTimeout).
|
||||||
|
@ -152,7 +181,7 @@ bool NimBLEClient::connect(const NimBLEAddress &address, uint8_t type, bool refr
|
||||||
rc = ble_gap_connect(BLE_OWN_ADDR_PUBLIC, &peerAddrt, m_connectTimeout, &m_pConnParams,
|
rc = ble_gap_connect(BLE_OWN_ADDR_PUBLIC, &peerAddrt, m_connectTimeout, &m_pConnParams,
|
||||||
NimBLEClient::handleGapEvent, this);
|
NimBLEClient::handleGapEvent, this);
|
||||||
if(rc == BLE_HS_EBUSY) {
|
if(rc == BLE_HS_EBUSY) {
|
||||||
vTaskDelay(1);
|
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
}while(rc == BLE_HS_EBUSY);
|
}while(rc == BLE_HS_EBUSY);
|
||||||
|
|
||||||
|
@ -162,23 +191,23 @@ bool NimBLEClient::connect(const NimBLEAddress &address, uint8_t type, bool refr
|
||||||
type,
|
type,
|
||||||
m_peerAddress.toString().c_str(),
|
m_peerAddress.toString().c_str(),
|
||||||
rc, NimBLEUtils::returnCodeToString(rc));
|
rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
|
m_pTaskData = nullptr;
|
||||||
m_semaphoreOpenEvt.give();
|
|
||||||
m_waitingToConnect = false;
|
m_waitingToConnect = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_waitingToConnect = true;
|
m_waitingToConnect = true;
|
||||||
|
|
||||||
rc = m_semaphoreOpenEvt.wait("connect"); // Wait for the connection to complete.
|
// Wait for the connection to complete.
|
||||||
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
|
||||||
if(rc != 0){
|
if(taskData.rc != 0){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(refreshServices) {
|
if(refreshServices) {
|
||||||
NIMBLE_LOGD(LOG_TAG, "Refreshing Services for: (%s)", address.toString().c_str());
|
NIMBLE_LOGD(LOG_TAG, "Refreshing Services for: (%s)", address.toString().c_str());
|
||||||
clearServices();
|
deleteServices();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pClientCallbacks->onConnect(this);
|
m_pClientCallbacks->onConnect(this);
|
||||||
|
@ -194,17 +223,18 @@ bool NimBLEClient::connect(const NimBLEAddress &address, uint8_t type, bool refr
|
||||||
* @return True on success.
|
* @return True on success.
|
||||||
*/
|
*/
|
||||||
bool NimBLEClient::secureConnection() {
|
bool NimBLEClient::secureConnection() {
|
||||||
|
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
|
||||||
m_semeaphoreSecEvt.take("secureConnection");
|
m_pTaskData = &taskData;
|
||||||
|
|
||||||
int rc = NimBLEDevice::startSecurity(m_conn_id);
|
int rc = NimBLEDevice::startSecurity(m_conn_id);
|
||||||
if(rc != 0){
|
if(rc != 0){
|
||||||
m_semeaphoreSecEvt.give();
|
m_pTaskData = nullptr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = m_semeaphoreSecEvt.wait("secureConnection");
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
if(rc != 0){
|
|
||||||
|
if(taskData.rc != 0){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,15 +250,11 @@ int NimBLEClient::disconnect(uint8_t reason) {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> disconnect()");
|
NIMBLE_LOGD(LOG_TAG, ">> disconnect()");
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
if(m_isConnected){
|
if(m_isConnected){
|
||||||
m_isConnected = false; // flag the disconnect now so no calls are performed after
|
|
||||||
rc = ble_gap_terminate(m_conn_id, reason);
|
rc = ble_gap_terminate(m_conn_id, reason);
|
||||||
if(rc != 0){
|
if(rc != 0){
|
||||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_terminate failed: rc=%d %s", rc,
|
NIMBLE_LOGE(LOG_TAG, "ble_gap_terminate failed: rc=%d %s", rc,
|
||||||
NimBLEUtils::returnCodeToString(rc));
|
NimBLEUtils::returnCodeToString(rc));
|
||||||
}
|
}
|
||||||
// Sometimes a disconnect event is not sent so we need to make sure
|
|
||||||
// the device can be found again.
|
|
||||||
NimBLEDevice::removeIgnored(m_peerAddress);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< disconnect()");
|
NIMBLE_LOGD(LOG_TAG, "<< disconnect()");
|
||||||
|
@ -394,15 +420,13 @@ NimBLERemoteService* NimBLEClient::getService(const NimBLEUUID &uuid) {
|
||||||
* @param [in] bool value to indicate if the current vector should be cleared and
|
* @param [in] bool value to indicate if the current vector should be cleared and
|
||||||
* subsequently all services retrieved from the peripheral.
|
* subsequently all services retrieved from the peripheral.
|
||||||
* If false the vector will be returned with the currently stored services,
|
* If false the vector will be returned with the currently stored services,
|
||||||
* if vector is empty it will retrieve all services from the peripheral.
|
* If true it will retrieve all services from the peripheral and return the vector with all services
|
||||||
* @return a pointer to the vector of available services.
|
* @return a pointer to the vector of available services.
|
||||||
*/
|
*/
|
||||||
std::vector<NimBLERemoteService*>* NimBLEClient::getServices(bool refresh) {
|
std::vector<NimBLERemoteService*>* NimBLEClient::getServices(bool refresh) {
|
||||||
if(refresh) {
|
if(refresh) {
|
||||||
clearServices();
|
deleteServices();
|
||||||
}
|
|
||||||
|
|
||||||
if(m_servicesVector.empty()) {
|
|
||||||
if (!retrieveServices()) {
|
if (!retrieveServices()) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Error: Failed to get services");
|
NIMBLE_LOGE(LOG_TAG, "Error: Failed to get services");
|
||||||
}
|
}
|
||||||
|
@ -442,30 +466,31 @@ bool NimBLEClient::retrieveServices(const NimBLEUUID *uuid_filter) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_semaphoreSearchCmplEvt.take("retrieveServices");
|
int rc = 0;
|
||||||
|
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
|
||||||
|
|
||||||
if(uuid_filter == nullptr) {
|
if(uuid_filter == nullptr) {
|
||||||
rc = ble_gattc_disc_all_svcs(m_conn_id, NimBLEClient::serviceDiscoveredCB, this);
|
rc = ble_gattc_disc_all_svcs(m_conn_id, NimBLEClient::serviceDiscoveredCB, &taskData);
|
||||||
} else {
|
} else {
|
||||||
rc = ble_gattc_disc_svc_by_uuid(m_conn_id, &uuid_filter->getNative()->u,
|
rc = ble_gattc_disc_svc_by_uuid(m_conn_id, &uuid_filter->getNative()->u,
|
||||||
NimBLEClient::serviceDiscoveredCB, this);
|
NimBLEClient::serviceDiscoveredCB, &taskData);
|
||||||
}
|
}
|
||||||
|
|
||||||
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_semaphoreSearchCmplEvt.give();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait until we have all the services
|
// wait until we have all the services
|
||||||
if(m_semaphoreSearchCmplEvt.wait("retrieveServices") == 0){
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
|
||||||
|
if(taskData.rc == 0){
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< retrieveServices");
|
NIMBLE_LOGD(LOG_TAG, "<< retrieveServices");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -489,41 +514,34 @@ int NimBLEClient::serviceDiscoveredCB(
|
||||||
NIMBLE_LOGD(LOG_TAG,"Service Discovered >> status: %d handle: %d",
|
NIMBLE_LOGD(LOG_TAG,"Service Discovered >> status: %d handle: %d",
|
||||||
error->status, (error->status == 0) ? service->start_handle : -1);
|
error->status, (error->status == 0) ? service->start_handle : -1);
|
||||||
|
|
||||||
NimBLEClient *peer = (NimBLEClient*)arg;
|
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
|
||||||
int rc=0;
|
NimBLEClient *client = (NimBLEClient*)pTaskData->pATT;
|
||||||
|
|
||||||
// Make sure the service discovery is for this device
|
// Make sure the service discovery is for this device
|
||||||
if(peer->getConnId() != conn_handle){
|
if(client->getConnId() != conn_handle){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (error->status) {
|
if(error->status == 0) {
|
||||||
case 0: {
|
|
||||||
// Found a service - add it to the vector
|
// Found a service - add it to the vector
|
||||||
NimBLERemoteService* pRemoteService = new NimBLERemoteService(peer, service);
|
NimBLERemoteService* pRemoteService = new NimBLERemoteService(client, service);
|
||||||
peer->m_servicesVector.push_back(pRemoteService);
|
client->m_servicesVector.push_back(pRemoteService);
|
||||||
break;
|
return 0;
|
||||||
}
|
|
||||||
case BLE_HS_EDONE:{
|
|
||||||
// All services discovered; start discovering characteristics.
|
|
||||||
|
|
||||||
//NIMBLE_LOGD(LOG_TAG,"Giving search semaphore - completed");
|
|
||||||
peer->m_semaphoreSearchCmplEvt.give(0);
|
|
||||||
rc = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// Error; abort discovery.
|
|
||||||
rc = error->status;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc != 0) {
|
if(error->status == BLE_HS_EDONE) {
|
||||||
// pass non-zero to semaphore on error to indicate an error finding services
|
pTaskData->rc = 0;
|
||||||
peer->m_semaphoreSearchCmplEvt.give(1);
|
} else {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "characteristicDiscCB() rc=%d %s",
|
||||||
|
error->status,
|
||||||
|
NimBLEUtils::returnCodeToString(error->status));
|
||||||
|
pTaskData->rc = error->status;
|
||||||
}
|
}
|
||||||
NIMBLE_LOGD(LOG_TAG,"<< Service Discovered. status: %d", rc);
|
|
||||||
return rc;
|
xTaskNotifyGive(pTaskData->task);
|
||||||
|
|
||||||
|
NIMBLE_LOGD(LOG_TAG,"<< << Service Discovered");
|
||||||
|
return error->status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -595,15 +613,11 @@ uint16_t NimBLEClient::getMTU() {
|
||||||
* @param [in] arg = pointer to the client instance
|
* @param [in] arg = pointer to the client instance
|
||||||
*/
|
*/
|
||||||
/*STATIC*/ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
/*STATIC*/ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||||
|
|
||||||
NimBLEClient* client = (NimBLEClient*)arg;
|
NimBLEClient* client = (NimBLEClient*)arg;
|
||||||
//struct ble_gap_conn_desc desc;
|
|
||||||
//struct ble_hs_adv_fields fields;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "Got Client event %s", NimBLEUtils::gapEventToString(event->type));
|
NIMBLE_LOGD(LOG_TAG, "Got Client event %s", NimBLEUtils::gapEventToString(event->type));
|
||||||
|
|
||||||
// Execute handler code based on the type of event received.
|
|
||||||
switch(event->type) {
|
switch(event->type) {
|
||||||
|
|
||||||
case BLE_GAP_EVENT_DISCONNECT: {
|
case BLE_GAP_EVENT_DISCONNECT: {
|
||||||
|
@ -620,9 +634,6 @@ uint16_t NimBLEClient::getMTU() {
|
||||||
|
|
||||||
NIMBLE_LOGI(LOG_TAG, "disconnect; reason=%d, %s", event->disconnect.reason,
|
NIMBLE_LOGI(LOG_TAG, "disconnect; reason=%d, %s", event->disconnect.reason,
|
||||||
NimBLEUtils::returnCodeToString(event->disconnect.reason));
|
NimBLEUtils::returnCodeToString(event->disconnect.reason));
|
||||||
//print_conn_desc(&event->disconnect.conn);
|
|
||||||
//MODLOG_DFLT(INFO, "\n");
|
|
||||||
|
|
||||||
|
|
||||||
// If Host reset tell the device now before returning to prevent
|
// If Host reset tell the device now before returning to prevent
|
||||||
// any errors caused by calling host functions before resyncing.
|
// any errors caused by calling host functions before resyncing.
|
||||||
|
@ -639,15 +650,9 @@ uint16_t NimBLEClient::getMTU() {
|
||||||
}
|
}
|
||||||
|
|
||||||
//client->m_conn_id = BLE_HS_CONN_HANDLE_NONE;
|
//client->m_conn_id = BLE_HS_CONN_HANDLE_NONE;
|
||||||
|
|
||||||
// Indicate a non-success return value to any semaphores waiting
|
|
||||||
client->m_semaphoreOpenEvt.give(1);
|
|
||||||
client->m_semaphoreSearchCmplEvt.give(1);
|
|
||||||
client->m_semeaphoreSecEvt.give(1);
|
|
||||||
|
|
||||||
client->m_pClientCallbacks->onDisconnect(client);
|
client->m_pClientCallbacks->onDisconnect(client);
|
||||||
|
rc = event->disconnect.reason;
|
||||||
return 0;
|
break;
|
||||||
} // BLE_GAP_EVENT_DISCONNECT
|
} // BLE_GAP_EVENT_DISCONNECT
|
||||||
|
|
||||||
case BLE_GAP_EVENT_CONNECT: {
|
case BLE_GAP_EVENT_CONNECT: {
|
||||||
|
@ -667,30 +672,25 @@ uint16_t NimBLEClient::getMTU() {
|
||||||
|
|
||||||
client->m_conn_id = event->connect.conn_handle;
|
client->m_conn_id = event->connect.conn_handle;
|
||||||
|
|
||||||
// rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
|
|
||||||
// assert(rc == 0);
|
|
||||||
// print_conn_desc(&desc);
|
|
||||||
// MODLOG_DFLT(INFO, "\n");
|
|
||||||
|
|
||||||
|
|
||||||
// In the case of a multiconnecting device we ignore this device when
|
|
||||||
// scanning since we are already connected to it
|
|
||||||
NimBLEDevice::addIgnored(client->m_peerAddress);
|
|
||||||
|
|
||||||
rc = ble_gattc_exchange_mtu(client->m_conn_id, NULL,NULL);
|
rc = ble_gattc_exchange_mtu(client->m_conn_id, NULL,NULL);
|
||||||
if(rc != 0) {
|
if(rc != 0) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "ble_gattc_exchange_mtu: rc=%d %s",rc,
|
NIMBLE_LOGE(LOG_TAG, "ble_gattc_exchange_mtu: rc=%d %s",rc,
|
||||||
NimBLEUtils::returnCodeToString(rc));
|
NimBLEUtils::returnCodeToString(rc));
|
||||||
// if error getting mtu indicate a connection error.
|
break;
|
||||||
client->m_semaphoreOpenEvt.give(rc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In the case of a multiconnecting device we ignore this device when
|
||||||
|
// scanning since we are already connected to it
|
||||||
|
NimBLEDevice::addIgnored(client->m_peerAddress);
|
||||||
} else {
|
} else {
|
||||||
// Connection attempt failed
|
|
||||||
NIMBLE_LOGE(LOG_TAG, "Error: Connection failed; status=%d %s",
|
NIMBLE_LOGE(LOG_TAG, "Error: Connection failed; status=%d %s",
|
||||||
event->connect.status,
|
event->connect.status,
|
||||||
NimBLEUtils::returnCodeToString(event->connect.status));
|
NimBLEUtils::returnCodeToString(event->connect.status));
|
||||||
|
|
||||||
|
client->m_isConnected = false;
|
||||||
|
rc = event->connect.status;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
client->m_semaphoreOpenEvt.give(event->connect.status);
|
|
||||||
return 0;
|
return 0;
|
||||||
} // BLE_GAP_EVENT_CONNECT
|
} // BLE_GAP_EVENT_CONNECT
|
||||||
|
|
||||||
|
@ -701,7 +701,7 @@ uint16_t NimBLEClient::getMTU() {
|
||||||
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);
|
||||||
|
|
||||||
for(auto &it: client->m_servicesVector) {
|
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 its range
|
||||||
if(it->getEndHandle() < event->notify_rx.attr_handle) {
|
if(it->getEndHandle() < event->notify_rx.attr_handle) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -720,6 +720,11 @@ uint16_t NimBLEClient::getMTU() {
|
||||||
if(characteristic != cVector->cend()) {
|
if(characteristic != cVector->cend()) {
|
||||||
NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", (*characteristic)->toString().c_str());
|
NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", (*characteristic)->toString().c_str());
|
||||||
|
|
||||||
|
portENTER_CRITICAL(&(*characteristic)->m_valMux);
|
||||||
|
(*characteristic)->m_value = std::string((char *)event->notify_rx.om->om_data, event->notify_rx.om->om_len);
|
||||||
|
(*characteristic)->m_timestamp = time(nullptr);
|
||||||
|
portEXIT_CRITICAL(&(*characteristic)->m_valMux);
|
||||||
|
|
||||||
if ((*characteristic)->m_notifyCallback != nullptr) {
|
if ((*characteristic)->m_notifyCallback != nullptr) {
|
||||||
NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s",
|
NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s",
|
||||||
(*characteristic)->toString().c_str());
|
(*characteristic)->toString().c_str());
|
||||||
|
@ -727,7 +732,6 @@ uint16_t NimBLEClient::getMTU() {
|
||||||
event->notify_rx.om->om_len,
|
event->notify_rx.om->om_len,
|
||||||
!event->notify_rx.indication);
|
!event->notify_rx.indication);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -738,7 +742,7 @@ uint16_t NimBLEClient::getMTU() {
|
||||||
case BLE_GAP_EVENT_CONN_UPDATE_REQ:
|
case BLE_GAP_EVENT_CONN_UPDATE_REQ:
|
||||||
case BLE_GAP_EVENT_L2CAP_UPDATE_REQ: {
|
case BLE_GAP_EVENT_L2CAP_UPDATE_REQ: {
|
||||||
if(client->m_conn_id != event->conn_update_req.conn_handle){
|
if(client->m_conn_id != event->conn_update_req.conn_handle){
|
||||||
return 0; //BLE_HS_ENOTCONN BLE_ATT_ERR_INVALID_HANDLE
|
return 0;
|
||||||
}
|
}
|
||||||
NIMBLE_LOGD(LOG_TAG, "Peer requesting to update connection parameters");
|
NIMBLE_LOGD(LOG_TAG, "Peer requesting to update connection parameters");
|
||||||
NIMBLE_LOGD(LOG_TAG, "MinInterval: %d, MaxInterval: %d, Latency: %d, Timeout: %d",
|
NIMBLE_LOGD(LOG_TAG, "MinInterval: %d, MaxInterval: %d, Latency: %d, Timeout: %d",
|
||||||
|
@ -764,7 +768,7 @@ uint16_t NimBLEClient::getMTU() {
|
||||||
|
|
||||||
case BLE_GAP_EVENT_CONN_UPDATE: {
|
case BLE_GAP_EVENT_CONN_UPDATE: {
|
||||||
if(client->m_conn_id != event->conn_update.conn_handle){
|
if(client->m_conn_id != event->conn_update.conn_handle){
|
||||||
return 0; //BLE_HS_ENOTCONN BLE_ATT_ERR_INVALID_HANDLE
|
return 0;
|
||||||
}
|
}
|
||||||
if(event->conn_update.status == 0) {
|
if(event->conn_update.status == 0) {
|
||||||
NIMBLE_LOGI(LOG_TAG, "Connection parameters updated.");
|
NIMBLE_LOGI(LOG_TAG, "Connection parameters updated.");
|
||||||
|
@ -776,7 +780,7 @@ uint16_t NimBLEClient::getMTU() {
|
||||||
|
|
||||||
case BLE_GAP_EVENT_ENC_CHANGE: {
|
case BLE_GAP_EVENT_ENC_CHANGE: {
|
||||||
if(client->m_conn_id != event->enc_change.conn_handle){
|
if(client->m_conn_id != event->enc_change.conn_handle){
|
||||||
return 0; //BLE_HS_ENOTCONN BLE_ATT_ERR_INVALID_HANDLE
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(event->enc_change.status == 0) {
|
if(event->enc_change.status == 0) {
|
||||||
|
@ -791,23 +795,23 @@ uint16_t NimBLEClient::getMTU() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
client->m_semeaphoreSecEvt.give(event->enc_change.status);
|
rc = event->enc_change.status;
|
||||||
return 0;
|
break;
|
||||||
} //BLE_GAP_EVENT_ENC_CHANGE
|
} //BLE_GAP_EVENT_ENC_CHANGE
|
||||||
|
|
||||||
case BLE_GAP_EVENT_MTU: {
|
case BLE_GAP_EVENT_MTU: {
|
||||||
if(client->m_conn_id != event->mtu.conn_handle){
|
if(client->m_conn_id != event->mtu.conn_handle){
|
||||||
return 0; //BLE_HS_ENOTCONN BLE_ATT_ERR_INVALID_HANDLE
|
return 0;
|
||||||
}
|
}
|
||||||
NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d",
|
NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d",
|
||||||
event->mtu.conn_handle,
|
event->mtu.conn_handle,
|
||||||
event->mtu.value);
|
event->mtu.value);
|
||||||
client->m_semaphoreOpenEvt.give(0);
|
rc = 0;
|
||||||
return 0;
|
break;
|
||||||
} // BLE_GAP_EVENT_MTU
|
} // BLE_GAP_EVENT_MTU
|
||||||
|
|
||||||
case BLE_GAP_EVENT_PASSKEY_ACTION: {
|
case BLE_GAP_EVENT_PASSKEY_ACTION: {
|
||||||
struct ble_sm_io pkey = {0};
|
struct ble_sm_io pkey = {0,0};
|
||||||
|
|
||||||
if(client->m_conn_id != event->passkey.conn_handle)
|
if(client->m_conn_id != event->passkey.conn_handle)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -868,6 +872,14 @@ uint16_t NimBLEClient::getMTU() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} // Switch
|
} // Switch
|
||||||
|
|
||||||
|
if(client->m_pTaskData != nullptr) {
|
||||||
|
client->m_pTaskData->rc = rc;
|
||||||
|
xTaskNotifyGive(client->m_pTaskData->task);
|
||||||
|
client->m_pTaskData = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
} // handleGapEvent
|
} // handleGapEvent
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,17 +21,14 @@
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||||
|
|
||||||
#include "NimBLEAddress.h"
|
#include "NimBLEAddress.h"
|
||||||
|
#include "NimBLEUUID.h"
|
||||||
|
#include "NimBLEUtils.h"
|
||||||
#include "NimBLEAdvertisedDevice.h"
|
#include "NimBLEAdvertisedDevice.h"
|
||||||
#include "NimBLERemoteService.h"
|
#include "NimBLERemoteService.h"
|
||||||
|
|
||||||
#include <vector>
|
#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;
|
||||||
|
@ -52,6 +49,8 @@ public:
|
||||||
std::vector<NimBLERemoteService*>::iterator end();
|
std::vector<NimBLERemoteService*>::iterator end();
|
||||||
NimBLERemoteService* getService(const char* uuid);
|
NimBLERemoteService* getService(const char* uuid);
|
||||||
NimBLERemoteService* getService(const NimBLEUUID &uuid);
|
NimBLERemoteService* getService(const NimBLEUUID &uuid);
|
||||||
|
void deleteServices();
|
||||||
|
size_t deleteService(const NimBLEUUID &uuid);
|
||||||
std::string getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID);
|
std::string getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID);
|
||||||
bool setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID,
|
bool setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID,
|
||||||
const std::string &value);
|
const std::string &value);
|
||||||
|
@ -82,19 +81,16 @@ private:
|
||||||
const struct ble_gatt_error *error,
|
const struct ble_gatt_error *error,
|
||||||
const struct ble_gatt_svc *service,
|
const struct ble_gatt_svc *service,
|
||||||
void *arg);
|
void *arg);
|
||||||
void clearServices();
|
|
||||||
bool retrieveServices(const NimBLEUUID *uuid_filter = nullptr);
|
bool retrieveServices(const NimBLEUUID *uuid_filter = nullptr);
|
||||||
|
|
||||||
NimBLEAddress m_peerAddress = NimBLEAddress("");
|
NimBLEAddress m_peerAddress = NimBLEAddress("");
|
||||||
uint16_t m_conn_id;
|
uint16_t m_conn_id;
|
||||||
bool m_isConnected = false;
|
bool m_isConnected;
|
||||||
bool m_waitingToConnect =false;
|
bool m_waitingToConnect;
|
||||||
bool m_deleteCallbacks = true;
|
bool m_deleteCallbacks;
|
||||||
int32_t m_connectTimeout;
|
int32_t m_connectTimeout;
|
||||||
NimBLEClientCallbacks* m_pClientCallbacks = nullptr;
|
NimBLEClientCallbacks* m_pClientCallbacks;
|
||||||
FreeRTOS::Semaphore m_semaphoreOpenEvt = FreeRTOS::Semaphore("OpenEvt");
|
ble_task_data_t *m_pTaskData;
|
||||||
FreeRTOS::Semaphore m_semaphoreSearchCmplEvt = FreeRTOS::Semaphore("SearchCmplEvt");
|
|
||||||
FreeRTOS::Semaphore m_semeaphoreSecEvt = FreeRTOS::Semaphore("Security");
|
|
||||||
|
|
||||||
std::vector<NimBLERemoteService*> m_servicesVector;
|
std::vector<NimBLERemoteService*> m_servicesVector;
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@ NimBLEDescriptor::NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties, uint16_
|
||||||
m_pCharacteristic = nullptr; // No initial characteristic.
|
m_pCharacteristic = nullptr; // No initial characteristic.
|
||||||
m_pCallbacks = &defaultCallbacks; // No initial callback.
|
m_pCallbacks = &defaultCallbacks; // No initial callback.
|
||||||
m_value.attr_value = (uint8_t*) calloc(max_len,1); // Allocate storage for the value.
|
m_value.attr_value = (uint8_t*) calloc(max_len,1); // Allocate storage for the value.
|
||||||
|
m_valMux = portMUX_INITIALIZER_UNLOCKED;
|
||||||
m_properties = 0;
|
m_properties = 0;
|
||||||
|
|
||||||
if (properties & BLE_GATT_CHR_F_READ) { // convert uint16_t properties to uint8_t
|
if (properties & BLE_GATT_CHR_F_READ) { // convert uint16_t properties to uint8_t
|
||||||
|
@ -137,17 +138,37 @@ int NimBLEDescriptor::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||||
if(ble_uuid_cmp(uuid, &pDescriptor->getUUID().getNative()->u) == 0){
|
if(ble_uuid_cmp(uuid, &pDescriptor->getUUID().getNative()->u) == 0){
|
||||||
switch(ctxt->op) {
|
switch(ctxt->op) {
|
||||||
case BLE_GATT_ACCESS_OP_READ_DSC: {
|
case BLE_GATT_ACCESS_OP_READ_DSC: {
|
||||||
|
// If the packet header is only 8 bytes this is a follow up of a long read
|
||||||
|
// so we don't want to call the onRead() callback again.
|
||||||
|
if(ctxt->om->om_pkthdr_len > 8) {
|
||||||
pDescriptor->m_pCallbacks->onRead(pDescriptor);
|
pDescriptor->m_pCallbacks->onRead(pDescriptor);
|
||||||
|
}
|
||||||
|
portENTER_CRITICAL(&pDescriptor->m_valMux);
|
||||||
rc = os_mbuf_append(ctxt->om, pDescriptor->getValue(), pDescriptor->getLength());
|
rc = os_mbuf_append(ctxt->om, pDescriptor->getValue(), pDescriptor->getLength());
|
||||||
|
portEXIT_CRITICAL(&pDescriptor->m_valMux);
|
||||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||||
}
|
}
|
||||||
|
|
||||||
case BLE_GATT_ACCESS_OP_WRITE_DSC: {
|
case BLE_GATT_ACCESS_OP_WRITE_DSC: {
|
||||||
if (ctxt->om->om_len > BLE_ATT_ATTR_MAX_LEN) {
|
if (ctxt->om->om_len > pDescriptor->m_value.attr_max_len) {
|
||||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
pDescriptor->setValue(ctxt->om->om_data, ctxt->om->om_len);
|
uint8_t buf[pDescriptor->m_value.attr_max_len];
|
||||||
|
size_t len = ctxt->om->om_len;
|
||||||
|
memcpy(buf, ctxt->om->om_data,len);
|
||||||
|
os_mbuf *next;
|
||||||
|
next = SLIST_NEXT(ctxt->om, om_next);
|
||||||
|
while(next != NULL){
|
||||||
|
if((len + next->om_len) > pDescriptor->m_value.attr_max_len) {
|
||||||
|
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||||
|
}
|
||||||
|
memcpy(&buf[len-1], next->om_data, next->om_len);
|
||||||
|
len += next->om_len;
|
||||||
|
next = SLIST_NEXT(next, om_next);
|
||||||
|
}
|
||||||
|
|
||||||
|
pDescriptor->setValue(buf, len);
|
||||||
pDescriptor->m_pCallbacks->onWrite(pDescriptor);
|
pDescriptor->m_pCallbacks->onWrite(pDescriptor);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -191,12 +212,14 @@ void NimBLEDescriptor::setHandle(uint16_t handle) {
|
||||||
* @param [in] length The length of the data in bytes.
|
* @param [in] length The length of the data in bytes.
|
||||||
*/
|
*/
|
||||||
void NimBLEDescriptor::setValue(const uint8_t* data, size_t length) {
|
void NimBLEDescriptor::setValue(const uint8_t* data, size_t length) {
|
||||||
if (length > BLE_ATT_ATTR_MAX_LEN) {
|
if (length > m_value.attr_max_len) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, BLE_ATT_ATTR_MAX_LEN);
|
NIMBLE_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, m_value.attr_max_len);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
portENTER_CRITICAL(&m_valMux);
|
||||||
m_value.attr_len = length;
|
m_value.attr_len = length;
|
||||||
memcpy(m_value.attr_value, data, length);
|
memcpy(m_value.attr_value, data, length);
|
||||||
|
portEXIT_CRITICAL(&m_valMux);
|
||||||
} // setValue
|
} // setValue
|
||||||
|
|
||||||
|
|
||||||
|
@ -209,13 +232,6 @@ void NimBLEDescriptor::setValue(const std::string &value) {
|
||||||
} // setValue
|
} // setValue
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
void NimBLEDescriptor::setAccessPermissions(uint8_t perm) {
|
|
||||||
m_permissions = perm;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return a string representation of the descriptor.
|
* @brief Return a string representation of the descriptor.
|
||||||
* @return A string representation of the descriptor.
|
* @return A string representation of the descriptor.
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
|
|
||||||
#include "NimBLECharacteristic.h"
|
#include "NimBLECharacteristic.h"
|
||||||
#include "NimBLEUUID.h"
|
#include "NimBLEUUID.h"
|
||||||
#include "FreeRTOS.h"
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -34,8 +33,6 @@ typedef struct
|
||||||
uint8_t *attr_value; /*!< the pointer to attribute value */
|
uint8_t *attr_value; /*!< the pointer to attribute value */
|
||||||
} attr_value_t;
|
} attr_value_t;
|
||||||
|
|
||||||
typedef attr_value_t esp_attr_value_t; /*!< compatibility for esp32 */
|
|
||||||
|
|
||||||
class NimBLEService;
|
class NimBLEService;
|
||||||
class NimBLECharacteristic;
|
class NimBLECharacteristic;
|
||||||
class NimBLEDescriptorCallbacks;
|
class NimBLEDescriptorCallbacks;
|
||||||
|
@ -46,20 +43,21 @@ class NimBLEDescriptorCallbacks;
|
||||||
*/
|
*/
|
||||||
class NimBLEDescriptor {
|
class NimBLEDescriptor {
|
||||||
public:
|
public:
|
||||||
virtual ~NimBLEDescriptor();
|
uint16_t getHandle();
|
||||||
uint16_t getHandle(); // Get the handle of the descriptor.
|
size_t getLength();
|
||||||
size_t getLength(); // Get the length of the value of the descriptor.
|
NimBLEUUID getUUID();
|
||||||
NimBLEUUID getUUID(); // Get the UUID of the descriptor.
|
uint8_t* getValue();
|
||||||
uint8_t* getValue(); // Get a pointer to the value of the descriptor.
|
void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks);
|
||||||
// void setAccessPermissions(uint8_t perm); // Set the permissions of the descriptor.
|
void setValue(const uint8_t* data, size_t size);
|
||||||
void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks); // Set callbacks to be invoked for the descriptor.
|
void setValue(const std::string &value);
|
||||||
void setValue(const uint8_t* data, size_t size); // Set the value of the descriptor as a pointer to data.
|
std::string toString();
|
||||||
void setValue(const std::string &value); // Set the value of the descriptor as a data buffer.
|
|
||||||
|
|
||||||
std::string toString(); // Convert the descriptor to a string representation.
|
template<typename T>
|
||||||
|
void setValue(const T &s) {
|
||||||
|
setValue((uint8_t*)&s, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class NimBLEDescriptorMap;
|
|
||||||
friend class NimBLECharacteristic;
|
friend class NimBLECharacteristic;
|
||||||
friend class NimBLEService;
|
friend class NimBLEService;
|
||||||
friend class NimBLE2902;
|
friend class NimBLE2902;
|
||||||
|
@ -73,18 +71,20 @@ private:
|
||||||
uint16_t max_len,
|
uint16_t max_len,
|
||||||
NimBLECharacteristic* pCharacteristic);
|
NimBLECharacteristic* pCharacteristic);
|
||||||
|
|
||||||
|
~NimBLEDescriptor();
|
||||||
|
|
||||||
|
static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||||
|
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||||
|
void setHandle(uint16_t handle);
|
||||||
|
|
||||||
NimBLEUUID m_uuid;
|
NimBLEUUID m_uuid;
|
||||||
uint16_t m_handle;
|
uint16_t m_handle;
|
||||||
NimBLEDescriptorCallbacks* m_pCallbacks;
|
NimBLEDescriptorCallbacks* m_pCallbacks;
|
||||||
NimBLECharacteristic* m_pCharacteristic;
|
NimBLECharacteristic* m_pCharacteristic;
|
||||||
uint8_t m_properties;
|
uint8_t m_properties;
|
||||||
attr_value_t m_value;
|
attr_value_t m_value;
|
||||||
|
portMUX_TYPE m_valMux;
|
||||||
static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
}; // NimBLEDescriptor
|
||||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
|
||||||
|
|
||||||
void setHandle(uint16_t handle);
|
|
||||||
}; // BLEDescriptor
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,149 +0,0 @@
|
||||||
/*
|
|
||||||
* NimBLEDescriptorMap.cpp
|
|
||||||
*
|
|
||||||
* Created: on March 10, 2020
|
|
||||||
* Author H2zero
|
|
||||||
*
|
|
||||||
* Originally:
|
|
||||||
*
|
|
||||||
* BLEDescriptorMap.cpp
|
|
||||||
*
|
|
||||||
* Created on: Jun 22, 2017
|
|
||||||
* Author: kolban
|
|
||||||
*/
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
|
|
||||||
#include "NimBLECharacteristic.h"
|
|
||||||
#include "NimBLEDescriptor.h"
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the descriptor by UUID.
|
|
||||||
* @param [in] UUID The UUID to look up the descriptor.
|
|
||||||
* @return The descriptor. If not present, then nullptr is returned.
|
|
||||||
*/
|
|
||||||
NimBLEDescriptor* NimBLEDescriptorMap::getByUUID(const char* uuid) {
|
|
||||||
return getByUUID(NimBLEUUID(uuid));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the descriptor by UUID.
|
|
||||||
* @param [in] UUID The UUID to look up the descriptor.
|
|
||||||
* @return The descriptor. If not present, then nullptr is returned.
|
|
||||||
*/
|
|
||||||
NimBLEDescriptor* NimBLEDescriptorMap::getByUUID(const NimBLEUUID &uuid) {
|
|
||||||
for (auto &myPair : m_uuidMap) {
|
|
||||||
if (myPair.first->getUUID().equals(uuid)) {
|
|
||||||
return myPair.first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
} // getByUUID
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the descriptor by handle.
|
|
||||||
* @param [in] handle The handle to look up the descriptor.
|
|
||||||
* @return The descriptor.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
NimBLEDescriptor* NimBLEDescriptorMap::getByHandle(uint16_t handle) {
|
|
||||||
return m_handleMap.at(handle);
|
|
||||||
} // getByHandle
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the descriptor by UUID.
|
|
||||||
* @param [in] uuid The uuid of the descriptor.
|
|
||||||
* @param [in] characteristic The descriptor to cache.
|
|
||||||
* @return N/A.
|
|
||||||
*/
|
|
||||||
void NimBLEDescriptorMap::setByUUID(const char* uuid, NimBLEDescriptor* pDescriptor){
|
|
||||||
m_uuidMap.insert(std::pair<NimBLEDescriptor*, std::string>(pDescriptor, uuid));
|
|
||||||
} // setByUUID
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the descriptor by UUID.
|
|
||||||
* @param [in] uuid The uuid of the descriptor.
|
|
||||||
* @param [in] characteristic The descriptor to cache.
|
|
||||||
* @return N/A.
|
|
||||||
*/
|
|
||||||
void NimBLEDescriptorMap::setByUUID(const NimBLEUUID &uuid, NimBLEDescriptor* pDescriptor) {
|
|
||||||
m_uuidMap.insert(std::pair<NimBLEDescriptor*, std::string>(pDescriptor, uuid.toString()));
|
|
||||||
} // setByUUID
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the descriptor by handle.
|
|
||||||
* @param [in] handle The handle of the descriptor.
|
|
||||||
* @param [in] descriptor The descriptor to cache.
|
|
||||||
* @return N/A.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
void NimBLEDescriptorMap::setByHandle(uint16_t handle, NimBLEDescriptor* pDescriptor) {
|
|
||||||
m_handleMap.insert(std::pair<uint16_t, NimBLEDescriptor*>(handle, pDescriptor));
|
|
||||||
} // setByHandle
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the number of descriptors in the map.
|
|
||||||
*/
|
|
||||||
uint8_t NimBLEDescriptorMap::getSize() {
|
|
||||||
return (uint8_t)m_uuidMap.size();
|
|
||||||
} // getSize
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return a string representation of the descriptor map.
|
|
||||||
* @return A string representation of the descriptor map.
|
|
||||||
*/
|
|
||||||
std::string NimBLEDescriptorMap::toString() {
|
|
||||||
std::string res;
|
|
||||||
char hex[5];
|
|
||||||
int count = 0;
|
|
||||||
for (auto &myPair : m_uuidMap) {
|
|
||||||
if (count > 0) {res += "\n";}
|
|
||||||
snprintf(hex, sizeof(hex), "%04x", myPair.first->getHandle());
|
|
||||||
count++;
|
|
||||||
res += "handle: 0x";
|
|
||||||
res += hex;
|
|
||||||
res += ", uuid: " + myPair.first->getUUID().toString();
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
} // toString
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the first descriptor in the map.
|
|
||||||
* @return The first descriptor in the map.
|
|
||||||
*/
|
|
||||||
NimBLEDescriptor* NimBLEDescriptorMap::getFirst() {
|
|
||||||
m_iterator = m_uuidMap.begin();
|
|
||||||
if (m_iterator == m_uuidMap.end()) return nullptr;
|
|
||||||
NimBLEDescriptor* pRet = m_iterator->first;
|
|
||||||
m_iterator++;
|
|
||||||
return pRet;
|
|
||||||
} // getFirst
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the next descriptor in the map.
|
|
||||||
* @return The next descriptor in the map.
|
|
||||||
*/
|
|
||||||
NimBLEDescriptor* NimBLEDescriptorMap::getNext() {
|
|
||||||
if (m_iterator == m_uuidMap.end()) return nullptr;
|
|
||||||
NimBLEDescriptor* pRet = m_iterator->first;
|
|
||||||
m_iterator++;
|
|
||||||
return pRet;
|
|
||||||
} // getNext
|
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
|
@ -152,21 +152,26 @@ void NimBLEDevice::stopAdvertising() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rc =0;
|
||||||
|
|
||||||
if(pClient->m_isConnected) {
|
if(pClient->m_isConnected) {
|
||||||
if (pClient->disconnect() != 0) {
|
rc = pClient->disconnect();
|
||||||
|
if (rc != 0 && rc != BLE_HS_EALREADY && rc != BLE_HS_ENOTCONN) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(pClient->m_isConnected) {
|
while(pClient->m_isConnected) {
|
||||||
vTaskDelay(1);
|
vTaskDelay(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pClient->m_waitingToConnect) {
|
if(pClient->m_waitingToConnect) {
|
||||||
if(ble_gap_conn_cancel() != 0){
|
rc = ble_gap_conn_cancel();
|
||||||
|
if (rc != 0 && rc != BLE_HS_EALREADY) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
while(pClient->m_waitingToConnect) {
|
while(pClient->m_waitingToConnect) {
|
||||||
vTaskDelay(1);
|
vTaskDelay(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,7 @@ public:
|
||||||
static void setSecurityPasskey(uint32_t pin);
|
static void setSecurityPasskey(uint32_t pin);
|
||||||
static uint32_t getSecurityPasskey();
|
static uint32_t getSecurityPasskey();
|
||||||
static void setSecurityCallbacks(NimBLESecurityCallbacks* pCallbacks);
|
static void setSecurityCallbacks(NimBLESecurityCallbacks* pCallbacks);
|
||||||
|
static int startSecurity(uint16_t conn_id);
|
||||||
static int setMTU(uint16_t mtu);
|
static int setMTU(uint16_t mtu);
|
||||||
static uint16_t getMTU();
|
static uint16_t getMTU();
|
||||||
static bool isIgnored(const NimBLEAddress &address);
|
static bool isIgnored(const NimBLEAddress &address);
|
||||||
|
@ -159,7 +160,6 @@ private:
|
||||||
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 bool m_synced;
|
static bool m_synced;
|
||||||
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||||
|
|
|
@ -25,25 +25,25 @@
|
||||||
#if CORE_DEBUG_LEVEL >= 4
|
#if CORE_DEBUG_LEVEL >= 4
|
||||||
#define NIMBLE_LOGD( tag, format, ... ) MODLOG_DFLT(ERROR, "D %s: "#format"\n",tag,##__VA_ARGS__)
|
#define NIMBLE_LOGD( tag, format, ... ) MODLOG_DFLT(ERROR, "D %s: "#format"\n",tag,##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define NIMBLE_LOGD( tag, format, ... )
|
#define NIMBLE_LOGD( tag, format, ... ) (void)tag
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CORE_DEBUG_LEVEL >= 3
|
#if CORE_DEBUG_LEVEL >= 3
|
||||||
#define NIMBLE_LOGI( tag, format, ... ) MODLOG_DFLT(ERROR, "I %s: "#format"\n",tag,##__VA_ARGS__)
|
#define NIMBLE_LOGI( tag, format, ... ) MODLOG_DFLT(ERROR, "I %s: "#format"\n",tag,##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define NIMBLE_LOGI( tag, format, ... )
|
#define NIMBLE_LOGI( tag, format, ... ) (void)tag
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CORE_DEBUG_LEVEL >= 2
|
#if CORE_DEBUG_LEVEL >= 2
|
||||||
#define NIMBLE_LOGW( tag, format, ... ) MODLOG_DFLT(ERROR, "W %s: "#format"\n",tag,##__VA_ARGS__)
|
#define NIMBLE_LOGW( tag, format, ... ) MODLOG_DFLT(ERROR, "W %s: "#format"\n",tag,##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define NIMBLE_LOGW( tag, format, ... )
|
#define NIMBLE_LOGW( tag, format, ... ) (void)tag
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CORE_DEBUG_LEVEL >= 1
|
#if CORE_DEBUG_LEVEL >= 1
|
||||||
#define NIMBLE_LOGE( tag, format, ... ) MODLOG_DFLT(ERROR, "E %s: "#format"\n",tag,##__VA_ARGS__)
|
#define NIMBLE_LOGE( tag, format, ... ) MODLOG_DFLT(ERROR, "E %s: "#format"\n",tag,##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define NIMBLE_LOGE( tag, format, ... )
|
#define NIMBLE_LOGE( tag, format, ... ) (void)tag
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define NIMBLE_LOGC( tag, format, ... ) MODLOG_DFLT(CRITICAL, "CRIT %s: "#format"\n",tag,##__VA_ARGS__)
|
#define NIMBLE_LOGC( tag, format, ... ) MODLOG_DFLT(CRITICAL, "CRIT %s: "#format"\n",tag,##__VA_ARGS__)
|
||||||
|
|
|
@ -53,13 +53,14 @@ static const char* LOG_TAG = "NimBLERemoteCharacteristic";
|
||||||
m_uuid = nullptr;
|
m_uuid = nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_handle = chr->val_handle;
|
m_handle = chr->val_handle;
|
||||||
m_defHandle = chr->def_handle;
|
m_defHandle = chr->def_handle;
|
||||||
m_charProp = chr->properties;
|
m_charProp = chr->properties;
|
||||||
m_pRemoteService = pRemoteService;
|
m_pRemoteService = pRemoteService;
|
||||||
m_notifyCallback = nullptr;
|
m_notifyCallback = nullptr;
|
||||||
m_rawData = nullptr;
|
m_timestamp = 0;
|
||||||
m_dataLen = 0;
|
m_valMux = portMUX_INITIALIZER_UNLOCKED;
|
||||||
} // NimBLERemoteCharacteristic
|
} // NimBLERemoteCharacteristic
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,10 +68,7 @@ static const char* LOG_TAG = "NimBLERemoteCharacteristic";
|
||||||
*@brief Destructor.
|
*@brief Destructor.
|
||||||
*/
|
*/
|
||||||
NimBLERemoteCharacteristic::~NimBLERemoteCharacteristic() {
|
NimBLERemoteCharacteristic::~NimBLERemoteCharacteristic() {
|
||||||
removeDescriptors(); // Release resources for any descriptor information we may have allocated.
|
deleteDescriptors();
|
||||||
if(m_rawData != nullptr) {
|
|
||||||
free(m_rawData);
|
|
||||||
}
|
|
||||||
} // ~NimBLERemoteCharacteristic
|
} // ~NimBLERemoteCharacteristic
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -150,12 +148,12 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
|
||||||
NIMBLE_LOGD(LOG_TAG,"Descriptor Discovered >> status: %d handle: %d",
|
NIMBLE_LOGD(LOG_TAG,"Descriptor Discovered >> status: %d handle: %d",
|
||||||
error->status, (error->status == 0) ? dsc->handle : -1);
|
error->status, (error->status == 0) ? dsc->handle : -1);
|
||||||
|
|
||||||
disc_filter_t *filter = (disc_filter_t*)arg;
|
desc_filter_t *filter = (desc_filter_t*)arg;
|
||||||
NimBLEUUID *uuid_filter = (NimBLEUUID*)filter->uuid;
|
const NimBLEUUID *uuid_filter = filter->uuid;
|
||||||
NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)filter->attribute;
|
ble_task_data_t *pTaskData = (ble_task_data_t*)filter->task_data;
|
||||||
|
NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)pTaskData->pATT;
|
||||||
int rc=0;
|
int rc=0;
|
||||||
|
|
||||||
// Make sure the discovery is for this device
|
|
||||||
if(characteristic->getRemoteService()->getClient()->getConnId() != conn_handle){
|
if(characteristic->getRemoteService()->getClient()->getConnId() != conn_handle){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -175,7 +173,7 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
|
||||||
rc = BLE_HS_EDONE;
|
rc = BLE_HS_EDONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Found a descriptor - add it to the vector
|
|
||||||
NimBLERemoteDescriptor* pNewRemoteDescriptor = new NimBLERemoteDescriptor(characteristic, dsc);
|
NimBLERemoteDescriptor* pNewRemoteDescriptor = new NimBLERemoteDescriptor(characteristic, dsc);
|
||||||
characteristic->m_descriptorVector.push_back(pNewRemoteDescriptor);
|
characteristic->m_descriptorVector.push_back(pNewRemoteDescriptor);
|
||||||
break;
|
break;
|
||||||
|
@ -185,18 +183,20 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** If rc == BLE_HS_EDONE, release the semaphore with a success error code and stop the discovery process.
|
/** If rc == BLE_HS_EDONE, resume the task 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.
|
* 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 we get any other error code tell the application to abort by returning non-zero in the rc.
|
||||||
*/
|
*/
|
||||||
if (rc == BLE_HS_EDONE) {
|
if (rc == BLE_HS_EDONE) {
|
||||||
characteristic->m_semaphoreGetDescEvt.give(0);
|
pTaskData->rc = 0;
|
||||||
|
xTaskNotifyGive(pTaskData->task);
|
||||||
} else if(rc != 0) {
|
} else if(rc != 0) {
|
||||||
/* Error; abort discovery. */
|
// Error; abort discovery.
|
||||||
// pass error code to semaphore waiting
|
pTaskData->rc = rc;
|
||||||
characteristic->m_semaphoreGetDescEvt.give(rc);
|
xTaskNotifyGive(pTaskData->task);
|
||||||
}
|
}
|
||||||
NIMBLE_LOGD(LOG_TAG,"<< Descriptor Discovered. status: %d", rc);
|
|
||||||
|
NIMBLE_LOGD(LOG_TAG,"<< Descriptor Discovered. status: %d", pTaskData->rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,11 +209,8 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt
|
||||||
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;
|
||||||
disc_filter_t filter;
|
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
|
||||||
filter.uuid = uuid_filter;
|
desc_filter_t filter = {uuid_filter, &taskData};
|
||||||
filter.attribute = this;
|
|
||||||
|
|
||||||
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,
|
||||||
|
@ -222,11 +219,12 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt
|
||||||
&filter);
|
&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();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_semaphoreGetDescEvt.wait("retrieveDescriptors") != 0) {
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
|
||||||
|
if(taskData.rc != 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,10 +270,8 @@ NimBLERemoteDescriptor* NimBLERemoteCharacteristic::getDescriptor(const NimBLEUU
|
||||||
*/
|
*/
|
||||||
std::vector<NimBLERemoteDescriptor*>* NimBLERemoteCharacteristic::getDescriptors(bool refresh) {
|
std::vector<NimBLERemoteDescriptor*>* NimBLERemoteCharacteristic::getDescriptors(bool refresh) {
|
||||||
if(refresh) {
|
if(refresh) {
|
||||||
removeDescriptors();
|
deleteDescriptors();
|
||||||
}
|
|
||||||
|
|
||||||
if(m_descriptorVector.empty()) {
|
|
||||||
if (!retrieveDescriptors()) {
|
if (!retrieveDescriptors()) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Error: Failed to get descriptors");
|
NIMBLE_LOGE(LOG_TAG, "Error: Failed to get descriptors");
|
||||||
}
|
}
|
||||||
|
@ -340,16 +336,28 @@ NimBLEUUID NimBLERemoteCharacteristic::getUUID() {
|
||||||
} // getUUID
|
} // getUUID
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the value of the remote characteristic.
|
||||||
|
* @return The value of the remote characteristic.
|
||||||
|
*/
|
||||||
|
std::string NimBLERemoteCharacteristic::getValue(time_t *timestamp) {
|
||||||
|
portENTER_CRITICAL(&m_valMux);
|
||||||
|
std::string value = m_value;
|
||||||
|
if(timestamp != nullptr) {
|
||||||
|
*timestamp = m_timestamp;
|
||||||
|
}
|
||||||
|
portEXIT_CRITICAL(&m_valMux);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read an unsigned 16 bit value
|
* @brief Read an unsigned 16 bit value
|
||||||
* @return The unsigned 16 bit value.
|
* @return The unsigned 16 bit value.
|
||||||
*/
|
*/
|
||||||
uint16_t NimBLERemoteCharacteristic::readUInt16() {
|
uint16_t NimBLERemoteCharacteristic::readUInt16() {
|
||||||
std::string value = readValue();
|
return readValue<uint16_t>();
|
||||||
if (value.length() >= 2) {
|
|
||||||
return *(uint16_t*)(value.data());
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
} // readUInt16
|
} // readUInt16
|
||||||
|
|
||||||
|
|
||||||
|
@ -358,11 +366,7 @@ uint16_t NimBLERemoteCharacteristic::readUInt16() {
|
||||||
* @return the unsigned 32 bit value.
|
* @return the unsigned 32 bit value.
|
||||||
*/
|
*/
|
||||||
uint32_t NimBLERemoteCharacteristic::readUInt32() {
|
uint32_t NimBLERemoteCharacteristic::readUInt32() {
|
||||||
std::string value = readValue();
|
return readValue<uint32_t>();
|
||||||
if (value.length() >= 4) {
|
|
||||||
return *(uint32_t*)(value.data());
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
} // readUInt32
|
} // readUInt32
|
||||||
|
|
||||||
|
|
||||||
|
@ -371,49 +375,52 @@ uint32_t NimBLERemoteCharacteristic::readUInt32() {
|
||||||
* @return The value as a byte
|
* @return The value as a byte
|
||||||
*/
|
*/
|
||||||
uint8_t NimBLERemoteCharacteristic::readUInt8() {
|
uint8_t NimBLERemoteCharacteristic::readUInt8() {
|
||||||
std::string value = readValue();
|
return readValue<uint8_t>();
|
||||||
if (value.length() >= 1) {
|
|
||||||
return (uint8_t)value[0];
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
} // readUInt8
|
} // readUInt8
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read a float value.
|
||||||
|
* @return the float value.
|
||||||
|
*/
|
||||||
|
float NimBLERemoteCharacteristic::readFloat() {
|
||||||
|
return readValue<float>();
|
||||||
|
} // readFloat
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the value of the remote characteristic.
|
* @brief Read the value of the remote characteristic.
|
||||||
* @return The value of the remote characteristic.
|
* @return The value of the remote characteristic.
|
||||||
*/
|
*/
|
||||||
std::string NimBLERemoteCharacteristic::readValue() {
|
std::string NimBLERemoteCharacteristic::readValue(time_t *timestamp) {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> readValue(): uuid: %s, handle: %d 0x%.2x",
|
NIMBLE_LOGD(LOG_TAG, ">> readValue(): uuid: %s, handle: %d 0x%.2x",
|
||||||
getUUID().toString().c_str(), getHandle(), getHandle());
|
getUUID().toString().c_str(), getHandle(), getHandle());
|
||||||
|
|
||||||
int rc = 0;
|
|
||||||
int retryCount = 1;
|
|
||||||
// Clear the value before reading.
|
|
||||||
m_value = "";
|
|
||||||
|
|
||||||
NimBLEClient* pClient = getRemoteService()->getClient();
|
NimBLEClient* pClient = getRemoteService()->getClient();
|
||||||
|
std::string value;
|
||||||
|
|
||||||
// Check to see that we are connected.
|
|
||||||
if (!pClient->isConnected()) {
|
if (!pClient->isConnected()) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Disconnected");
|
NIMBLE_LOGE(LOG_TAG, "Disconnected");
|
||||||
return "";
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
int rc = 0;
|
||||||
m_semaphoreReadCharEvt.take("readValue");
|
int retryCount = 1;
|
||||||
|
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(),0, &value};
|
||||||
|
|
||||||
|
do {
|
||||||
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
|
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
|
||||||
NimBLERemoteCharacteristic::onReadCB,
|
NimBLERemoteCharacteristic::onReadCB,
|
||||||
this);
|
&taskData);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Error: Failed to read characteristic; rc=%d, %s",
|
NIMBLE_LOGE(LOG_TAG, "Error: Failed to read characteristic; rc=%d, %s",
|
||||||
rc, NimBLEUtils::returnCodeToString(rc));
|
rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
m_semaphoreReadCharEvt.give(0);
|
return value;
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = m_semaphoreReadCharEvt.wait("readValue");
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
rc = taskData.rc;
|
||||||
|
|
||||||
switch(rc){
|
switch(rc){
|
||||||
case 0:
|
case 0:
|
||||||
case BLE_HS_EDONE:
|
case BLE_HS_EDONE:
|
||||||
|
@ -431,12 +438,21 @@ std::string NimBLERemoteCharacteristic::readValue() {
|
||||||
break;
|
break;
|
||||||
/* Else falls through. */
|
/* Else falls through. */
|
||||||
default:
|
default:
|
||||||
return "";
|
NIMBLE_LOGE(LOG_TAG, "<< readValue rc=%d", rc);
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
} while(rc != 0 && retryCount--);
|
} while(rc != 0 && retryCount--);
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< readValue(): length: %d", m_value.length());
|
portENTER_CRITICAL(&m_valMux);
|
||||||
return m_value;
|
m_value = value;
|
||||||
|
m_timestamp = time(nullptr);
|
||||||
|
if(timestamp != nullptr) {
|
||||||
|
*timestamp = m_timestamp;
|
||||||
|
}
|
||||||
|
portEXIT_CRITICAL(&m_valMux);
|
||||||
|
|
||||||
|
NIMBLE_LOGD(LOG_TAG, "<< readValue length: %d rc=%d", value.length(), rc);
|
||||||
|
return value;
|
||||||
} // readValue
|
} // readValue
|
||||||
|
|
||||||
|
|
||||||
|
@ -448,31 +464,91 @@ int NimBLERemoteCharacteristic::onReadCB(uint16_t conn_handle,
|
||||||
const struct ble_gatt_error *error,
|
const struct ble_gatt_error *error,
|
||||||
struct ble_gatt_attr *attr, void *arg)
|
struct ble_gatt_attr *attr, void *arg)
|
||||||
{
|
{
|
||||||
NimBLERemoteCharacteristic* characteristic = (NimBLERemoteCharacteristic*)arg;
|
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
|
||||||
|
NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)pTaskData->pATT;
|
||||||
uint16_t conn_id = characteristic->getRemoteService()->getClient()->getConnId();
|
uint16_t conn_id = characteristic->getRemoteService()->getClient()->getConnId();
|
||||||
|
|
||||||
// Make sure the read is for this client
|
|
||||||
if(conn_id != 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);
|
||||||
|
|
||||||
if(error->status == 0) {
|
std::string *strBuf = (std::string*)pTaskData->buf;
|
||||||
if(attr) {
|
int rc = error->status;
|
||||||
NIMBLE_LOGD(LOG_TAG, "Got %d bytes", attr->om->om_len);
|
|
||||||
|
|
||||||
characteristic->m_value += std::string((char*) attr->om->om_data, attr->om->om_len);
|
if(rc == 0) {
|
||||||
|
if(attr) {
|
||||||
|
if(((*strBuf).length() + attr->om->om_len) > BLE_ATT_ATTR_MAX_LEN) {
|
||||||
|
rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||||
|
} else {
|
||||||
|
NIMBLE_LOGD(LOG_TAG, "Got %d bytes", attr->om->om_len);
|
||||||
|
(*strBuf) += std::string((char*) attr->om->om_data, attr->om->om_len);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Read complete release semaphore and let the app can continue.
|
}
|
||||||
characteristic->m_semaphoreReadCharEvt.give(error->status);
|
|
||||||
return 0;
|
pTaskData->rc = rc;
|
||||||
|
xTaskNotifyGive(pTaskData->task);
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Register for notifications.
|
* @brief Subscribe or unsubscribe for notifications or indications.
|
||||||
|
* @param [in] uint16_t val 0x00 to unsubscribe, 0x01 for notifications, 0x02 for indications.
|
||||||
|
* @param [in] notifyCallback A callback to be invoked for a notification. If NULL is provided then no callback
|
||||||
|
* is performed for notifications.
|
||||||
|
* @return true if successful.
|
||||||
|
*/
|
||||||
|
bool NimBLERemoteCharacteristic::setNotify(uint16_t val, bool response, notify_callback notifyCallback) {
|
||||||
|
NIMBLE_LOGD(LOG_TAG, ">> setNotify(): %s, %02x", toString().c_str(), val);
|
||||||
|
|
||||||
|
NimBLERemoteDescriptor* desc = getDescriptor(NimBLEUUID((uint16_t)0x2902));
|
||||||
|
if(desc == nullptr) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "<< setNotify(): Could not get descriptor");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_notifyCallback = notifyCallback;
|
||||||
|
|
||||||
|
NIMBLE_LOGD(LOG_TAG, "<< setNotify()");
|
||||||
|
|
||||||
|
return desc->writeValue((uint8_t *)&val, 2, response);
|
||||||
|
} // setNotify
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Subscribe for notifications or indications.
|
||||||
|
* @param [in] bool if true, subscribe for notifications, false subscribe for indications.
|
||||||
|
* @param [in] bool if true, require a write response from the descriptor write operation.
|
||||||
|
* @param [in] notifyCallback A callback to be invoked for a notification. If NULL is provided then no callback
|
||||||
|
* is performed for notifications.
|
||||||
|
* @return true if successful.
|
||||||
|
*/
|
||||||
|
bool NimBLERemoteCharacteristic::subscribe(bool notifications, bool response, notify_callback notifyCallback) {
|
||||||
|
if(notifications) {
|
||||||
|
return setNotify(0x01, response, notifyCallback);
|
||||||
|
} else {
|
||||||
|
return setNotify(0x02, response, notifyCallback);
|
||||||
|
}
|
||||||
|
} // subscribe
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unsubscribe for notifications or indications.
|
||||||
|
* @param [in] bool if true, require a write response from the descriptor write operation.
|
||||||
|
* @return true if successful.
|
||||||
|
*/
|
||||||
|
bool NimBLERemoteCharacteristic::unsubscribe(bool response) {
|
||||||
|
return setNotify(0x00, response);
|
||||||
|
} // unsubscribe
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief backward-compatibility method for subscribe/unsubscribe notifications/indications
|
||||||
* @param [in] notifyCallback A callback to be invoked for a notification. If NULL is provided then we are
|
* @param [in] notifyCallback A callback to be invoked for a notification. If NULL is provided then we are
|
||||||
* unregistering for notifications.
|
* unregistering for notifications.
|
||||||
* @param [in] bool if true, register for notifications, false register for indications.
|
* @param [in] bool if true, register for notifications, false register for indications.
|
||||||
|
@ -480,46 +556,54 @@ int NimBLERemoteCharacteristic::onReadCB(uint16_t conn_handle,
|
||||||
* @return true if successful.
|
* @return true if successful.
|
||||||
*/
|
*/
|
||||||
bool NimBLERemoteCharacteristic::registerForNotify(notify_callback notifyCallback, bool notifications, bool response) {
|
bool NimBLERemoteCharacteristic::registerForNotify(notify_callback notifyCallback, bool notifications, bool response) {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> registerForNotify(): %s", toString().c_str());
|
bool success;
|
||||||
|
|
||||||
m_notifyCallback = notifyCallback; // Save the notification callback.
|
|
||||||
|
|
||||||
uint8_t val[] = {0x01, 0x00};
|
|
||||||
|
|
||||||
NimBLERemoteDescriptor* desc = getDescriptor(NimBLEUUID((uint16_t)0x2902));
|
|
||||||
if(desc == nullptr)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if(notifyCallback != nullptr) {
|
if(notifyCallback != nullptr) {
|
||||||
if(!notifications){
|
success = subscribe(notifications, response, notifyCallback);
|
||||||
val[0] = 0x02;
|
} else {
|
||||||
|
success = unsubscribe(response);
|
||||||
}
|
}
|
||||||
}
|
return success;
|
||||||
|
|
||||||
else if (notifyCallback == nullptr){
|
|
||||||
val[0] = 0x00;
|
|
||||||
}
|
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< registerForNotify()");
|
|
||||||
|
|
||||||
return desc->writeValue(val, 2, response);
|
|
||||||
} // registerForNotify
|
} // registerForNotify
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Delete the descriptors in the descriptor vector.
|
* @brief Delete the descriptors in the descriptor vector.
|
||||||
* We maintain a vector called m_descriptorVector 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 deleting
|
||||||
* them. This method does just that.
|
* them. This method does just that.
|
||||||
* @return N/A.
|
* @return N/A.
|
||||||
*/
|
*/
|
||||||
void NimBLERemoteCharacteristic::removeDescriptors() {
|
void NimBLERemoteCharacteristic::deleteDescriptors() {
|
||||||
// Iterate through all the descriptors releasing their storage and erasing them from the vector.
|
NIMBLE_LOGD(LOG_TAG, ">> deleteDescriptors");
|
||||||
|
|
||||||
for(auto &it: m_descriptorVector) {
|
for(auto &it: m_descriptorVector) {
|
||||||
delete it;
|
delete it;
|
||||||
}
|
}
|
||||||
m_descriptorVector.clear();
|
m_descriptorVector.clear();
|
||||||
} // removeCharacteristics
|
NIMBLE_LOGD(LOG_TAG, "<< deleteDescriptors");
|
||||||
|
} // deleteDescriptors
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete descriptor by UUID
|
||||||
|
* @param [in] uuid The UUID of the descriptor to be deleted.
|
||||||
|
* @return Number of services left.
|
||||||
|
*/
|
||||||
|
size_t NimBLERemoteCharacteristic::deleteDescriptor(const NimBLEUUID &uuid) {
|
||||||
|
NIMBLE_LOGD(LOG_TAG, ">> deleteDescriptor");
|
||||||
|
|
||||||
|
for(auto it = m_descriptorVector.begin(); it != m_descriptorVector.end(); ++it) {
|
||||||
|
if((*it)->getUUID() == uuid) {
|
||||||
|
delete *it;
|
||||||
|
m_descriptorVector.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NIMBLE_LOGD(LOG_TAG, "<< deleteDescriptor");
|
||||||
|
|
||||||
|
return m_descriptorVector.size();
|
||||||
|
} // deleteDescriptor
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -559,19 +643,6 @@ bool NimBLERemoteCharacteristic::writeValue(const std::string &newValue, bool re
|
||||||
} // writeValue
|
} // writeValue
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Write the new value for the characteristic.
|
|
||||||
*
|
|
||||||
* This is a convenience function. Many BLE characteristics are a single byte of data.
|
|
||||||
* @param [in] newValue The new byte value to write.
|
|
||||||
* @param [in] response Whether we require a response from the write.
|
|
||||||
* @return false if not connected or cant perform write for some reason.
|
|
||||||
*/
|
|
||||||
bool NimBLERemoteCharacteristic::writeValue(uint8_t newValue, bool response) {
|
|
||||||
return writeValue(&newValue, 1, response);
|
|
||||||
} // writeValue
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Write the new value for the characteristic from a data buffer.
|
* @brief Write the new value for the characteristic from a data buffer.
|
||||||
* @param [in] data A pointer to a data buffer.
|
* @param [in] data A pointer to a data buffer.
|
||||||
|
@ -584,47 +655,45 @@ bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length,
|
||||||
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 retryCount = 1;
|
|
||||||
uint16_t mtu;
|
|
||||||
|
|
||||||
// Check to see that we are connected.
|
|
||||||
if (!pClient->isConnected()) {
|
if (!pClient->isConnected()) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Disconnected");
|
NIMBLE_LOGE(LOG_TAG, "Disconnected");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mtu = ble_att_mtu(pClient->getConnId()) - 3;
|
int rc = 0;
|
||||||
|
int retryCount = 1;
|
||||||
|
uint16_t mtu = ble_att_mtu(pClient->getConnId()) - 3;
|
||||||
|
|
||||||
// Check if the data length is longer than we can write in 1 connection event.
|
// Check if the data length is longer than we can write in one connection event.
|
||||||
// If so we must do a long write which requires a response.
|
// If so we must do a long write which requires a response.
|
||||||
if(length <= mtu && !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 {
|
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
|
||||||
m_semaphoreWriteCharEvt.take("writeValue");
|
|
||||||
|
|
||||||
|
do {
|
||||||
if(length > mtu) {
|
if(length > mtu) {
|
||||||
NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length);
|
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);
|
&taskData);
|
||||||
} 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);
|
&taskData);
|
||||||
}
|
}
|
||||||
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();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = m_semaphoreWriteCharEvt.wait("writeValue");
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
rc = taskData.rc;
|
||||||
|
|
||||||
switch(rc){
|
switch(rc){
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -644,6 +713,7 @@ bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length,
|
||||||
break;
|
break;
|
||||||
/* Else falls through. */
|
/* Else falls through. */
|
||||||
default:
|
default:
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "<< writeValue, rc: %d", rc);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} while(rc != 0 && retryCount--);
|
} while(rc != 0 && retryCount--);
|
||||||
|
@ -661,59 +731,21 @@ int NimBLERemoteCharacteristic::onWriteCB(uint16_t conn_handle,
|
||||||
const struct ble_gatt_error *error,
|
const struct ble_gatt_error *error,
|
||||||
struct ble_gatt_attr *attr, void *arg)
|
struct ble_gatt_attr *attr, void *arg)
|
||||||
{
|
{
|
||||||
NimBLERemoteCharacteristic* characteristic = (NimBLERemoteCharacteristic*)arg;
|
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
|
||||||
|
NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)pTaskData->pATT;
|
||||||
|
|
||||||
// Make sure the discovery is for this device
|
|
||||||
if(characteristic->getRemoteService()->getClient()->getConnId() != conn_handle){
|
if(characteristic->getRemoteService()->getClient()->getConnId() != conn_handle){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
characteristic->m_semaphoreWriteCharEvt.give(error->status);
|
pTaskData->rc = error->status;
|
||||||
|
xTaskNotifyGive(pTaskData->task);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Read raw data from remote characteristic as hex bytes
|
|
||||||
* @return uint8_t pointer to the data read.
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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() {
|
|
||||||
for (auto &it: m_descriptorVector) {
|
|
||||||
it->releaseSemaphores();
|
|
||||||
}
|
|
||||||
m_semaphoreWriteCharEvt.give(1);
|
|
||||||
m_semaphoreGetDescEvt.give(1);
|
|
||||||
m_semaphoreReadCharEvt.give(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
#endif /* CONFIG_BT_ENABLED */
|
||||||
|
|
|
@ -32,6 +32,12 @@ class NimBLERemoteDescriptor;
|
||||||
typedef void (*notify_callback)(NimBLERemoteCharacteristic* pBLERemoteCharacteristic,
|
typedef void (*notify_callback)(NimBLERemoteCharacteristic* pBLERemoteCharacteristic,
|
||||||
uint8_t* pData, size_t length, bool isNotify);
|
uint8_t* pData, size_t length, bool isNotify);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const NimBLEUUID *uuid;
|
||||||
|
void *task_data;
|
||||||
|
} desc_filter_t;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A model of a remote %BLE characteristic.
|
* @brief A model of a remote %BLE characteristic.
|
||||||
*/
|
*/
|
||||||
|
@ -50,26 +56,54 @@ public:
|
||||||
std::vector<NimBLERemoteDescriptor*>::iterator end();
|
std::vector<NimBLERemoteDescriptor*>::iterator end();
|
||||||
NimBLERemoteDescriptor* getDescriptor(const NimBLEUUID &uuid);
|
NimBLERemoteDescriptor* getDescriptor(const NimBLEUUID &uuid);
|
||||||
std::vector<NimBLERemoteDescriptor*>* getDescriptors(bool refresh = false);
|
std::vector<NimBLERemoteDescriptor*>* getDescriptors(bool refresh = false);
|
||||||
|
void deleteDescriptors();
|
||||||
|
size_t deleteDescriptor(const NimBLEUUID &uuid);
|
||||||
uint16_t getHandle();
|
uint16_t getHandle();
|
||||||
uint16_t getDefHandle();
|
uint16_t getDefHandle();
|
||||||
NimBLEUUID getUUID();
|
NimBLEUUID getUUID();
|
||||||
std::string readValue();
|
std::string readValue(time_t *timestamp = nullptr);
|
||||||
uint8_t readUInt8();
|
|
||||||
uint16_t readUInt16();
|
template<typename T>
|
||||||
uint32_t readUInt32();
|
T readValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
|
||||||
bool registerForNotify(notify_callback _callback,
|
std::string value = readValue(timestamp);
|
||||||
|
if(!skipSizeCheck && value.size() < sizeof(T)) return T();
|
||||||
|
const char *pData = value.data();
|
||||||
|
return *((T *)pData);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t readUInt8() __attribute__ ((deprecated("Use template readValue<uint8_t>()")));
|
||||||
|
uint16_t readUInt16() __attribute__ ((deprecated("Use template readValue<uint16_t>()")));
|
||||||
|
uint32_t readUInt32() __attribute__ ((deprecated("Use template readValue<uint32_t>()")));
|
||||||
|
float readFloat() __attribute__ ((deprecated("Use template readValue<float>()")));
|
||||||
|
std::string getValue(time_t *timestamp = nullptr);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
|
||||||
|
std::string value = getValue(timestamp);
|
||||||
|
if(!skipSizeCheck && value.size() < sizeof(T)) return T();
|
||||||
|
const char *pData = value.data();
|
||||||
|
return *((T *)pData);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool subscribe(bool notifications = true,
|
||||||
|
bool response = true,
|
||||||
|
notify_callback notifyCallback = nullptr);
|
||||||
|
bool unsubscribe(bool response = true);
|
||||||
|
bool registerForNotify(notify_callback notifyCallback,
|
||||||
bool notifications = true,
|
bool notifications = true,
|
||||||
bool response = true);
|
bool response = true)
|
||||||
|
__attribute__ ((deprecated("Use subscribe()/unsubscribe()")));
|
||||||
bool writeValue(const uint8_t* data,
|
bool writeValue(const uint8_t* data,
|
||||||
size_t length,
|
size_t length,
|
||||||
bool response = false);
|
bool response = false);
|
||||||
bool writeValue(const std::string &newValue,
|
bool writeValue(const std::string &newValue,
|
||||||
bool response = false);
|
bool response = false);
|
||||||
bool writeValue(uint8_t newValue,
|
template<typename T>
|
||||||
bool response = false);
|
bool writeValue(const T &s, bool response = false) {
|
||||||
|
return writeValue((uint8_t*)&s, sizeof(T), response);
|
||||||
|
}
|
||||||
|
|
||||||
std::string toString();
|
std::string toString();
|
||||||
uint8_t* readRawData();
|
|
||||||
size_t getDataLength();
|
|
||||||
NimBLERemoteService* getRemoteService();
|
NimBLERemoteService* getRemoteService();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -81,13 +115,12 @@ private:
|
||||||
friend class NimBLERemoteDescriptor;
|
friend class NimBLERemoteDescriptor;
|
||||||
|
|
||||||
// Private member functions
|
// Private member functions
|
||||||
void removeDescriptors();
|
bool setNotify(uint16_t val, bool response = true, notify_callback notifyCallback = nullptr);
|
||||||
bool retrieveDescriptors(const NimBLEUUID *uuid_filter = nullptr);
|
bool retrieveDescriptors(const NimBLEUUID *uuid_filter = nullptr);
|
||||||
static int onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error,
|
static int onReadCB(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,
|
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);
|
||||||
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,
|
||||||
void *arg);
|
void *arg);
|
||||||
|
@ -98,13 +131,10 @@ private:
|
||||||
uint16_t m_handle;
|
uint16_t m_handle;
|
||||||
uint16_t m_defHandle;
|
uint16_t m_defHandle;
|
||||||
NimBLERemoteService* m_pRemoteService;
|
NimBLERemoteService* m_pRemoteService;
|
||||||
FreeRTOS::Semaphore m_semaphoreGetDescEvt = FreeRTOS::Semaphore("GetDescEvt");
|
|
||||||
FreeRTOS::Semaphore m_semaphoreReadCharEvt = FreeRTOS::Semaphore("ReadCharEvt");
|
|
||||||
FreeRTOS::Semaphore m_semaphoreWriteCharEvt = FreeRTOS::Semaphore("WriteCharEvt");
|
|
||||||
std::string m_value;
|
std::string m_value;
|
||||||
uint8_t* m_rawData;
|
|
||||||
size_t m_dataLen;
|
|
||||||
notify_callback m_notifyCallback;
|
notify_callback m_notifyCallback;
|
||||||
|
time_t m_timestamp;
|
||||||
|
portMUX_TYPE m_valMux;
|
||||||
|
|
||||||
// We maintain a vector of descriptors owned by this characteristic.
|
// We maintain a vector of descriptors owned by this characteristic.
|
||||||
std::vector<NimBLERemoteDescriptor*> m_descriptorVector;
|
std::vector<NimBLERemoteDescriptor*> m_descriptorVector;
|
||||||
|
|
|
@ -45,9 +45,9 @@ NimBLERemoteDescriptor::NimBLERemoteDescriptor(NimBLERemoteCharacteristic* pRemo
|
||||||
m_uuid = nullptr;
|
m_uuid = nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_handle = dsc->handle;
|
m_handle = dsc->handle;
|
||||||
m_pRemoteCharacteristic = pRemoteCharacteristic;
|
m_pRemoteCharacteristic = pRemoteCharacteristic;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -78,96 +78,6 @@ NimBLEUUID NimBLERemoteDescriptor::getUUID() {
|
||||||
} // getUUID
|
} // getUUID
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Callback for Descriptor read operation.
|
|
||||||
* @return 0 or error code.
|
|
||||||
*/
|
|
||||||
int NimBLERemoteDescriptor::onReadCB(uint16_t conn_handle,
|
|
||||||
const struct ble_gatt_error *error,
|
|
||||||
struct ble_gatt_attr *attr, void *arg)
|
|
||||||
{
|
|
||||||
NimBLERemoteDescriptor* desc = (NimBLERemoteDescriptor*)arg;
|
|
||||||
uint16_t conn_id = desc->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId();
|
|
||||||
|
|
||||||
// Make sure the discovery is for this device
|
|
||||||
if(conn_id != conn_handle){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
|
|
||||||
|
|
||||||
if(error->status == 0){
|
|
||||||
if(attr){
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "Got %d bytes", attr->om->om_len);
|
|
||||||
|
|
||||||
desc->m_value += std::string((char*) attr->om->om_data, attr->om->om_len);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read complete release semaphore and let the app can continue.
|
|
||||||
desc->m_semaphoreReadDescrEvt.give(error->status);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::string NimBLERemoteDescriptor::readValue() {
|
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> Descriptor readValue: %s", toString().c_str());
|
|
||||||
|
|
||||||
int rc = 0;
|
|
||||||
int retryCount = 1;
|
|
||||||
// Clear the value before reading.
|
|
||||||
m_value = "";
|
|
||||||
|
|
||||||
NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
|
|
||||||
|
|
||||||
// Check to see that we are connected.
|
|
||||||
if (!pClient->isConnected()) {
|
|
||||||
NIMBLE_LOGE(LOG_TAG, "Disconnected");
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
m_semaphoreReadDescrEvt.take("ReadDescriptor");
|
|
||||||
|
|
||||||
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
|
|
||||||
NimBLERemoteDescriptor::onReadCB,
|
|
||||||
this);
|
|
||||||
if (rc != 0) {
|
|
||||||
NIMBLE_LOGE(LOG_TAG, "Error: Failed to read descriptor; rc=%d, %s",
|
|
||||||
rc, NimBLEUtils::returnCodeToString(rc));
|
|
||||||
m_semaphoreReadDescrEvt.give(0);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = m_semaphoreReadDescrEvt.wait("ReadDescriptor");
|
|
||||||
|
|
||||||
switch(rc){
|
|
||||||
case 0:
|
|
||||||
case BLE_HS_EDONE:
|
|
||||||
rc = 0;
|
|
||||||
break;
|
|
||||||
// Descriptor is not long-readable, return with what we have.
|
|
||||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
|
|
||||||
NIMBLE_LOGI(LOG_TAG, "Attribute not long");
|
|
||||||
rc = 0;
|
|
||||||
break;
|
|
||||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
|
|
||||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR):
|
|
||||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC):
|
|
||||||
if (retryCount && pClient->secureConnection())
|
|
||||||
break;
|
|
||||||
/* Else falls through. */
|
|
||||||
default:
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
} while(rc != 0 && retryCount--);
|
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< Descriptor readValue(): length: %d", m_value.length());
|
|
||||||
return m_value;
|
|
||||||
} // readValue
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t NimBLERemoteDescriptor::readUInt8() {
|
uint8_t NimBLERemoteDescriptor::readUInt8() {
|
||||||
std::string value = readValue();
|
std::string value = readValue();
|
||||||
if (value.length() >= 1) {
|
if (value.length() >= 1) {
|
||||||
|
@ -195,6 +105,100 @@ uint32_t NimBLERemoteDescriptor::readUInt32() {
|
||||||
} // readUInt32
|
} // readUInt32
|
||||||
|
|
||||||
|
|
||||||
|
std::string NimBLERemoteDescriptor::readValue() {
|
||||||
|
NIMBLE_LOGD(LOG_TAG, ">> Descriptor readValue: %s", toString().c_str());
|
||||||
|
|
||||||
|
NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
|
||||||
|
std::string value;
|
||||||
|
|
||||||
|
if (!pClient->isConnected()) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Disconnected");
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rc = 0;
|
||||||
|
int retryCount = 1;
|
||||||
|
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(),0, &value};
|
||||||
|
|
||||||
|
do {
|
||||||
|
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
|
||||||
|
NimBLERemoteDescriptor::onReadCB,
|
||||||
|
&taskData);
|
||||||
|
if (rc != 0) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Error: Failed to read descriptor; rc=%d, %s",
|
||||||
|
rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
rc = taskData.rc;
|
||||||
|
|
||||||
|
switch(rc){
|
||||||
|
case 0:
|
||||||
|
case BLE_HS_EDONE:
|
||||||
|
rc = 0;
|
||||||
|
break;
|
||||||
|
// Descriptor is not long-readable, return with what we have.
|
||||||
|
case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
|
||||||
|
NIMBLE_LOGI(LOG_TAG, "Attribute not long");
|
||||||
|
rc = 0;
|
||||||
|
break;
|
||||||
|
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
|
||||||
|
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR):
|
||||||
|
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC):
|
||||||
|
if (retryCount && pClient->secureConnection())
|
||||||
|
break;
|
||||||
|
/* Else falls through. */
|
||||||
|
default:
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
} while(rc != 0 && retryCount--);
|
||||||
|
|
||||||
|
NIMBLE_LOGD(LOG_TAG, "<< Descriptor readValue(): length: %d rc=%d", value.length(), rc);
|
||||||
|
return value;
|
||||||
|
} // readValue
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback for Descriptor read operation.
|
||||||
|
* @return 0 or error code.
|
||||||
|
*/
|
||||||
|
int NimBLERemoteDescriptor::onReadCB(uint16_t conn_handle,
|
||||||
|
const struct ble_gatt_error *error,
|
||||||
|
struct ble_gatt_attr *attr, void *arg)
|
||||||
|
{
|
||||||
|
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
|
||||||
|
NimBLERemoteDescriptor* desc = (NimBLERemoteDescriptor*)pTaskData->pATT;
|
||||||
|
uint16_t conn_id = desc->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId();
|
||||||
|
|
||||||
|
if(conn_id != conn_handle){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
NIMBLE_LOGD(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
|
||||||
|
|
||||||
|
std::string *strBuf = (std::string*)pTaskData->buf;
|
||||||
|
int rc = error->status;
|
||||||
|
|
||||||
|
if(rc == 0) {
|
||||||
|
if(attr) {
|
||||||
|
if(((*strBuf).length() + attr->om->om_len) > BLE_ATT_ATTR_MAX_LEN) {
|
||||||
|
rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||||
|
} else {
|
||||||
|
NIMBLE_LOGD(LOG_TAG, "Got %d bytes", attr->om->om_len);
|
||||||
|
(*strBuf) += std::string((char*) attr->om->om_data, attr->om->om_len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pTaskData->rc = rc;
|
||||||
|
xTaskNotifyGive(pTaskData->task);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return a string representation of this BLE Remote Descriptor.
|
* @brief Return a string representation of this BLE Remote Descriptor.
|
||||||
* @retun A string representation of this BLE Remote Descriptor.
|
* @retun A string representation of this BLE Remote Descriptor.
|
||||||
|
@ -218,16 +222,17 @@ int NimBLERemoteDescriptor::onWriteCB(uint16_t conn_handle,
|
||||||
const struct ble_gatt_error *error,
|
const struct ble_gatt_error *error,
|
||||||
struct ble_gatt_attr *attr, void *arg)
|
struct ble_gatt_attr *attr, void *arg)
|
||||||
{
|
{
|
||||||
NimBLERemoteDescriptor* descriptor = (NimBLERemoteDescriptor*)arg;
|
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
|
||||||
|
NimBLERemoteDescriptor* descriptor = (NimBLERemoteDescriptor*)pTaskData->pATT;
|
||||||
|
|
||||||
// Make sure the discovery is for this device
|
|
||||||
if(descriptor->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId() != conn_handle){
|
if(descriptor->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId() != conn_handle){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
NIMBLE_LOGD(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);
|
||||||
|
|
||||||
descriptor->m_semaphoreDescWrite.give(error->status);
|
pTaskData->rc = error->status;
|
||||||
|
xTaskNotifyGive(pTaskData->task);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -245,17 +250,15 @@ bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool
|
||||||
|
|
||||||
NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
|
NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
|
||||||
|
|
||||||
int rc = 0;
|
|
||||||
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()) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Disconnected");
|
NIMBLE_LOGE(LOG_TAG, "Disconnected");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mtu = ble_att_mtu(pClient->getConnId()) - 3;
|
int rc = 0;
|
||||||
|
int retryCount = 1;
|
||||||
|
uint16_t mtu = ble_att_mtu(pClient->getConnId()) - 3;
|
||||||
|
|
||||||
// Check if the data length is longer than we can write in 1 connection event.
|
// 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 so we must do a long write which requires a response.
|
||||||
|
@ -264,29 +267,29 @@ bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool
|
||||||
return (rc == 0);
|
return (rc == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
|
||||||
m_semaphoreDescWrite.take("WriteDescriptor");
|
|
||||||
|
|
||||||
|
do {
|
||||||
if(length > mtu) {
|
if(length > mtu) {
|
||||||
NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length);
|
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,
|
||||||
NimBLERemoteDescriptor::onWriteCB,
|
NimBLERemoteDescriptor::onWriteCB,
|
||||||
this);
|
&taskData);
|
||||||
} else {
|
} 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);
|
&taskData);
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = m_semaphoreDescWrite.wait("WriteDescriptor");
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
rc = taskData.rc;
|
||||||
|
|
||||||
switch(rc) {
|
switch(rc) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -325,23 +328,5 @@ bool NimBLERemoteDescriptor::writeValue(const std::string &newValue, bool respon
|
||||||
} // writeValue
|
} // writeValue
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Write a byte value to the Descriptor.
|
|
||||||
* @param [in] The single byte to write.
|
|
||||||
* @param [in] True if we expect a response.
|
|
||||||
*/
|
|
||||||
bool NimBLERemoteDescriptor::writeValue(uint8_t newValue, bool response) {
|
|
||||||
return writeValue(&newValue, 1, response);
|
|
||||||
} // writeValue
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief In the event of an error this is called to make sure we don't block.
|
|
||||||
*/
|
|
||||||
void NimBLERemoteDescriptor::releaseSemaphores() {
|
|
||||||
m_semaphoreDescWrite.give(1);
|
|
||||||
m_semaphoreReadDescrEvt.give(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
#endif /* CONFIG_BT_ENABLED */
|
||||||
|
|
|
@ -31,15 +31,26 @@ public:
|
||||||
uint16_t getHandle();
|
uint16_t getHandle();
|
||||||
NimBLERemoteCharacteristic* getRemoteCharacteristic();
|
NimBLERemoteCharacteristic* getRemoteCharacteristic();
|
||||||
NimBLEUUID getUUID();
|
NimBLEUUID getUUID();
|
||||||
std::string readValue(void);
|
std::string readValue();
|
||||||
uint8_t readUInt8(void);
|
|
||||||
uint16_t readUInt16(void);
|
template<typename T>
|
||||||
uint32_t readUInt32(void);
|
T readValue(bool skipSizeCheck = false) {
|
||||||
|
std::string value = readValue();
|
||||||
|
if(!skipSizeCheck && value.size() < sizeof(T)) return T();
|
||||||
|
const char *pData = value.data();
|
||||||
|
return *((T *)pData);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t readUInt8() __attribute__ ((deprecated));
|
||||||
|
uint16_t readUInt16() __attribute__ ((deprecated));
|
||||||
|
uint32_t readUInt32() __attribute__ ((deprecated));
|
||||||
std::string toString(void);
|
std::string toString(void);
|
||||||
bool writeValue(const uint8_t* data, size_t length, 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(const std::string &newValue, bool response = false);
|
||||||
bool writeValue(uint8_t newValue, bool response = false);
|
template<typename T>
|
||||||
|
bool writeValue(const T &s, bool response = false) {
|
||||||
|
return writeValue((uint8_t*)&s, sizeof(T), response);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class NimBLERemoteCharacteristic;
|
friend class NimBLERemoteCharacteristic;
|
||||||
|
@ -50,16 +61,10 @@ private:
|
||||||
struct ble_gatt_attr *attr, void *arg);
|
struct ble_gatt_attr *attr, void *arg);
|
||||||
static int onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error,
|
static int onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||||
struct ble_gatt_attr *attr, void *arg);
|
struct ble_gatt_attr *attr, void *arg);
|
||||||
void releaseSemaphores();
|
|
||||||
|
|
||||||
uint16_t m_handle;
|
uint16_t m_handle;
|
||||||
NimBLEUUID m_uuid;
|
NimBLEUUID m_uuid;
|
||||||
std::string m_value;
|
|
||||||
NimBLERemoteCharacteristic* m_pRemoteCharacteristic;
|
NimBLERemoteCharacteristic* m_pRemoteCharacteristic;
|
||||||
FreeRTOS::Semaphore m_semaphoreReadDescrEvt = FreeRTOS::Semaphore("ReadDescrEvt");
|
|
||||||
FreeRTOS::Semaphore m_semaphoreDescWrite = FreeRTOS::Semaphore("WriteDescEvt");
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||||
|
|
|
@ -58,7 +58,7 @@ NimBLERemoteService::NimBLERemoteService(NimBLEClient* pClient, const struct ble
|
||||||
* Also release any semaphores they may be holding.
|
* Also release any semaphores they may be holding.
|
||||||
*/
|
*/
|
||||||
NimBLERemoteService::~NimBLERemoteService() {
|
NimBLERemoteService::~NimBLERemoteService() {
|
||||||
removeCharacteristics();
|
deleteCharacteristics();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -118,17 +118,15 @@ NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const NimBLEU
|
||||||
* @param [in] bool value to indicate if the current vector should be cleared and
|
* @param [in] bool value to indicate if the current vector should be cleared and
|
||||||
* subsequently all characteristics for this service retrieved from the peripheral.
|
* subsequently all characteristics for this service retrieved from the peripheral.
|
||||||
* If false the vector will be returned with the currently stored characteristics,
|
* 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
|
* If true it will retrieve all characteristics of this service from the peripheral
|
||||||
* from the peripheral.
|
* and return the vector with all characteristics for this service.
|
||||||
* @return a pointer to the vector of descriptors for this characteristic.
|
* @return a pointer to the vector of descriptors for this characteristic.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
std::vector<NimBLERemoteCharacteristic*>* NimBLERemoteService::getCharacteristics(bool refresh) {
|
std::vector<NimBLERemoteCharacteristic*>* NimBLERemoteService::getCharacteristics(bool refresh) {
|
||||||
if(refresh) {
|
if(refresh) {
|
||||||
removeCharacteristics();
|
deleteCharacteristics();
|
||||||
}
|
|
||||||
|
|
||||||
if(m_characteristicVector.empty()) {
|
|
||||||
if (!retrieveCharacteristics()) {
|
if (!retrieveCharacteristics()) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Error: Failed to get characteristics");
|
NIMBLE_LOGE(LOG_TAG, "Error: Failed to get characteristics");
|
||||||
}
|
}
|
||||||
|
@ -150,43 +148,34 @@ int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle,
|
||||||
NIMBLE_LOGD(LOG_TAG,"Characteristic Discovered >> status: %d handle: %d",
|
NIMBLE_LOGD(LOG_TAG,"Characteristic Discovered >> status: %d handle: %d",
|
||||||
error->status, (error->status == 0) ? chr->val_handle : -1);
|
error->status, (error->status == 0) ? chr->val_handle : -1);
|
||||||
|
|
||||||
NimBLERemoteService *service = (NimBLERemoteService*)arg;
|
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
|
||||||
int rc=0;
|
NimBLERemoteService *service = (NimBLERemoteService*)pTaskData->pATT;
|
||||||
|
|
||||||
// Make sure the discovery is for this device
|
// Make sure the discovery is for this device
|
||||||
if(service->getClient()->getConnId() != conn_handle){
|
if(service->getClient()->getConnId() != conn_handle){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (error->status) {
|
if(error->status == 0) {
|
||||||
case 0: {
|
|
||||||
// Found a service - add it to the vector
|
// Found a service - add it to the vector
|
||||||
NimBLERemoteCharacteristic* pRemoteCharacteristic = new NimBLERemoteCharacteristic(service, chr);
|
NimBLERemoteCharacteristic* pRemoteCharacteristic = new NimBLERemoteCharacteristic(service, chr);
|
||||||
service->m_characteristicVector.push_back(pRemoteCharacteristic);
|
service->m_characteristicVector.push_back(pRemoteCharacteristic);
|
||||||
break;
|
return 0;
|
||||||
}
|
}
|
||||||
case BLE_HS_EDONE:{
|
|
||||||
/** All characteristics in this service discovered; start discovering
|
if(error->status == BLE_HS_EDONE) {
|
||||||
* characteristics in the next service.
|
pTaskData->rc = 0;
|
||||||
*/
|
} else {
|
||||||
service->m_semaphoreGetCharEvt.give(0);
|
NIMBLE_LOGE(LOG_TAG, "characteristicDiscCB() rc=%d %s",
|
||||||
rc = 0;
|
error->status,
|
||||||
break;
|
NimBLEUtils::returnCodeToString(error->status));
|
||||||
|
pTaskData->rc = error->status;
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
rc = error->status;
|
xTaskNotifyGive(pTaskData->task);
|
||||||
break;
|
|
||||||
}
|
NIMBLE_LOGD(LOG_TAG,"<< Characteristic Discovered");
|
||||||
if (rc != 0) {
|
return error->status;
|
||||||
/* Error; abort discovery. */
|
|
||||||
// pass non-zero to semaphore on error to indicate an error finding characteristics
|
|
||||||
// release memory from any characteristics we created
|
|
||||||
//service->removeCharacteristics(); --this will now be done when we clear services on returning with error
|
|
||||||
NIMBLE_LOGE(LOG_TAG, "characteristicDiscCB() rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
||||||
service->m_semaphoreGetCharEvt.give(1);
|
|
||||||
}
|
|
||||||
NIMBLE_LOGD(LOG_TAG,"<< Characteristic Discovered. status: %d", rc);
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -199,32 +188,31 @@ 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;
|
||||||
//removeCharacteristics(); // Forget any previous characteristics.
|
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
|
||||||
|
|
||||||
m_semaphoreGetCharEvt.take("retrieveCharacteristics");
|
|
||||||
|
|
||||||
if(uuid_filter == nullptr) {
|
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);
|
&taskData);
|
||||||
} else {
|
} else {
|
||||||
rc = ble_gattc_disc_chrs_by_uuid(m_pClient->getConnId(),
|
rc = ble_gattc_disc_chrs_by_uuid(m_pClient->getConnId(),
|
||||||
m_startHandle,
|
m_startHandle,
|
||||||
m_endHandle,
|
m_endHandle,
|
||||||
&uuid_filter->getNative()->u,
|
&uuid_filter->getNative()->u,
|
||||||
NimBLERemoteService::characteristicDiscCB,
|
NimBLERemoteService::characteristicDiscCB,
|
||||||
this);
|
&taskData);
|
||||||
}
|
}
|
||||||
|
|
||||||
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_semaphoreGetCharEvt.give();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_semaphoreGetCharEvt.wait("retrieveCharacteristics") == 0){
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
|
||||||
|
if(taskData.rc == 0){
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristics()");
|
NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristics()");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -316,12 +304,36 @@ bool NimBLERemoteService::setValue(const NimBLEUUID &characteristicUuid, const s
|
||||||
* them. This method does just that.
|
* them. This method does just that.
|
||||||
* @return N/A.
|
* @return N/A.
|
||||||
*/
|
*/
|
||||||
void NimBLERemoteService::removeCharacteristics() {
|
void NimBLERemoteService::deleteCharacteristics() {
|
||||||
|
NIMBLE_LOGD(LOG_TAG, ">> deleteCharacteristics");
|
||||||
for(auto &it: m_characteristicVector) {
|
for(auto &it: m_characteristicVector) {
|
||||||
delete it;
|
delete it;
|
||||||
}
|
}
|
||||||
m_characteristicVector.clear(); // Clear the vector
|
m_characteristicVector.clear();
|
||||||
} // removeCharacteristics
|
NIMBLE_LOGD(LOG_TAG, "<< deleteCharacteristics");
|
||||||
|
} // deleteCharacteristics
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete characteristic by UUID
|
||||||
|
* @param [in] uuid The UUID of the characteristic to be cleared.
|
||||||
|
* @return Number of characteristics left.
|
||||||
|
*/
|
||||||
|
size_t NimBLERemoteService::deleteCharacteristic(const NimBLEUUID &uuid) {
|
||||||
|
NIMBLE_LOGD(LOG_TAG, ">> deleteCharacteristic");
|
||||||
|
|
||||||
|
for(auto it = m_characteristicVector.begin(); it != m_characteristicVector.end(); ++it) {
|
||||||
|
if((*it)->getUUID() == uuid) {
|
||||||
|
delete *it;
|
||||||
|
m_characteristicVector.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NIMBLE_LOGD(LOG_TAG, "<< deleteCharacteristic");
|
||||||
|
|
||||||
|
return m_characteristicVector.size();
|
||||||
|
} // deleteCharacteristic
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -352,16 +364,5 @@ std::string NimBLERemoteService::toString() {
|
||||||
} // toString
|
} // toString
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief called when an error occurrs and we need to release the semaphores to resume operations.
|
|
||||||
* Will release all characteristic and subsequently all descriptor semaphores for this service.
|
|
||||||
*/
|
|
||||||
void NimBLERemoteService::releaseSemaphores() {
|
|
||||||
for(auto &it: m_characteristicVector) {
|
|
||||||
it->releaseSemaphores();
|
|
||||||
}
|
|
||||||
m_semaphoreGetCharEvt.give(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
#endif /* CONFIG_BT_ENABLED */
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
|
|
||||||
#include "NimBLEClient.h"
|
#include "NimBLEClient.h"
|
||||||
#include "NimBLEUUID.h"
|
#include "NimBLEUUID.h"
|
||||||
#include "FreeRTOS.h"
|
|
||||||
#include "NimBLERemoteCharacteristic.h"
|
#include "NimBLERemoteCharacteristic.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -43,6 +42,8 @@ public:
|
||||||
std::vector<NimBLERemoteCharacteristic*>::iterator end();
|
std::vector<NimBLERemoteCharacteristic*>::iterator end();
|
||||||
NimBLERemoteCharacteristic* getCharacteristic(const char* uuid);
|
NimBLERemoteCharacteristic* getCharacteristic(const char* uuid);
|
||||||
NimBLERemoteCharacteristic* getCharacteristic(const NimBLEUUID &uuid);
|
NimBLERemoteCharacteristic* getCharacteristic(const NimBLEUUID &uuid);
|
||||||
|
void deleteCharacteristics();
|
||||||
|
size_t deleteCharacteristic(const NimBLEUUID &uuid);
|
||||||
NimBLEClient* getClient(void);
|
NimBLEClient* getClient(void);
|
||||||
uint16_t getHandle();
|
uint16_t getHandle();
|
||||||
NimBLEUUID getUUID(void);
|
NimBLEUUID getUUID(void);
|
||||||
|
@ -70,7 +71,6 @@ private:
|
||||||
uint16_t getStartHandle();
|
uint16_t getStartHandle();
|
||||||
uint16_t getEndHandle();
|
uint16_t getEndHandle();
|
||||||
void releaseSemaphores();
|
void releaseSemaphores();
|
||||||
void removeCharacteristics();
|
|
||||||
|
|
||||||
// Properties
|
// Properties
|
||||||
|
|
||||||
|
@ -78,7 +78,6 @@ private:
|
||||||
std::vector<NimBLERemoteCharacteristic*> m_characteristicVector;
|
std::vector<NimBLERemoteCharacteristic*> m_characteristicVector;
|
||||||
|
|
||||||
NimBLEClient* m_pClient;
|
NimBLEClient* m_pClient;
|
||||||
FreeRTOS::Semaphore m_semaphoreGetCharEvt = FreeRTOS::Semaphore("GetCharEvt");
|
|
||||||
NimBLEUUID m_uuid;
|
NimBLEUUID m_uuid;
|
||||||
uint16_t m_startHandle;
|
uint16_t m_startHandle;
|
||||||
uint16_t m_endHandle;
|
uint16_t m_endHandle;
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||||
|
|
||||||
#include "NimBLEScan.h"
|
#include "NimBLEScan.h"
|
||||||
#include "NimBLEUtils.h"
|
|
||||||
#include "NimBLEDevice.h"
|
#include "NimBLEDevice.h"
|
||||||
#include "NimBLELog.h"
|
#include "NimBLELog.h"
|
||||||
|
|
||||||
|
@ -26,41 +25,12 @@
|
||||||
|
|
||||||
static const char* LOG_TAG = "NimBLEScan";
|
static const char* LOG_TAG = "NimBLEScan";
|
||||||
|
|
||||||
/*
|
|
||||||
* Scanning filter policy
|
|
||||||
* NO_WL:
|
|
||||||
* Scanner processes all advertising packets (white list not used) except
|
|
||||||
* directed, connectable advertising packets not sent to the scanner.
|
|
||||||
* USE_WL:
|
|
||||||
* Scanner processes advertisements from white list only. A connectable,
|
|
||||||
* directed advertisment is ignored unless it contains scanners address.
|
|
||||||
* NO_WL_INITA:
|
|
||||||
* Scanner process all advertising packets (white list not used). A
|
|
||||||
* connectable, directed advertisement shall not be ignored if the InitA
|
|
||||||
* is a resolvable private address.
|
|
||||||
* USE_WL_INITA:
|
|
||||||
* Scanner process advertisements from white list only. A connectable,
|
|
||||||
* directed advertisement shall not be ignored if the InitA is a
|
|
||||||
* resolvable private address.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//#define BLE_HCI_SCAN_FILT_NO_WL (0)
|
|
||||||
//#define BLE_HCI_SCAN_FILT_USE_WL (1)
|
|
||||||
//#define BLE_HCI_SCAN_FILT_NO_WL_INITA (2)
|
|
||||||
//#define BLE_HCI_SCAN_FILT_USE_WL_INITA (3)
|
|
||||||
//#define BLE_HCI_SCAN_FILT_MAX (3)
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Scan constuctor.
|
* @brief Scan constuctor.
|
||||||
*/
|
*/
|
||||||
NimBLEScan::NimBLEScan() {
|
NimBLEScan::NimBLEScan() {
|
||||||
uint8_t own_addr_type;
|
m_own_addr_type = 0;
|
||||||
if(ble_hs_id_infer_auto(0, &own_addr_type) !=0){
|
|
||||||
NIMBLE_LOGE(LOG_TAG, "error determining address type\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_own_addr_type = own_addr_type;
|
|
||||||
m_scan_params.filter_policy = BLE_HCI_SCAN_FILT_NO_WL;
|
m_scan_params.filter_policy = BLE_HCI_SCAN_FILT_NO_WL;
|
||||||
m_scan_params.passive = 1; // If set, don’t send scan requests to advertisers (i.e., don’t request additional advertising data).
|
m_scan_params.passive = 1; // If set, don’t send scan requests to advertisers (i.e., don’t request additional advertising data).
|
||||||
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)
|
||||||
|
@ -70,6 +40,7 @@ NimBLEScan::NimBLEScan() {
|
||||||
m_pAdvertisedDeviceCallbacks = nullptr;
|
m_pAdvertisedDeviceCallbacks = nullptr;
|
||||||
m_stopped = true;
|
m_stopped = true;
|
||||||
m_wantDuplicates = false;
|
m_wantDuplicates = false;
|
||||||
|
m_pTaskData = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -101,14 +72,6 @@ NimBLEScan::NimBLEScan() {
|
||||||
|
|
||||||
NimBLEAddress advertisedAddress(event->disc.addr);
|
NimBLEAddress advertisedAddress(event->disc.addr);
|
||||||
|
|
||||||
// Print advertisement data
|
|
||||||
// print_adv_fields(&fields);
|
|
||||||
|
|
||||||
// If we are not scanning, nothing to do with the extra results.
|
|
||||||
if (pScan->m_stopped) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Examine our list of ignored addresses and stop processing if we don't want to see it or are already connected
|
// Examine our list of ignored addresses and stop processing if we don't want to see it or are already connected
|
||||||
if(NimBLEDevice::isIgnored(advertisedAddress)) {
|
if(NimBLEDevice::isIgnored(advertisedAddress)) {
|
||||||
NIMBLE_LOGI(LOG_TAG, "Ignoring device: address: %s", advertisedAddress.toString().c_str());
|
NIMBLE_LOGI(LOG_TAG, "Ignoring device: address: %s", advertisedAddress.toString().c_str());
|
||||||
|
@ -131,7 +94,6 @@ NimBLEScan::NimBLEScan() {
|
||||||
advertisedDevice = new NimBLEAdvertisedDevice();
|
advertisedDevice = new NimBLEAdvertisedDevice();
|
||||||
advertisedDevice->setAddressType(event->disc.addr.type);
|
advertisedDevice->setAddressType(event->disc.addr.type);
|
||||||
advertisedDevice->setAddress(advertisedAddress);
|
advertisedDevice->setAddress(advertisedAddress);
|
||||||
//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_advertisedDevicesVector.push_back(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());
|
||||||
|
@ -143,16 +105,21 @@ NimBLEScan::NimBLEScan() {
|
||||||
advertisedDevice->parseAdvertisement(&fields);
|
advertisedDevice->parseAdvertisement(&fields);
|
||||||
advertisedDevice->setScan(pScan);
|
advertisedDevice->setScan(pScan);
|
||||||
advertisedDevice->setAdvertisementResult(event->disc.data, event->disc.length_data);
|
advertisedDevice->setAdvertisementResult(event->disc.data, event->disc.length_data);
|
||||||
|
advertisedDevice->m_timestamp = time(nullptr);
|
||||||
|
|
||||||
if (pScan->m_pAdvertisedDeviceCallbacks) {
|
if (pScan->m_pAdvertisedDeviceCallbacks) {
|
||||||
|
if(pScan->m_wantDuplicates || !advertisedDevice->m_callbackSent) {
|
||||||
// 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 || event->disc.event_type == BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) {
|
if(pScan->m_scan_params.passive || event->disc.event_type == BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) {
|
||||||
|
advertisedDevice->m_callbackSent = true;
|
||||||
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) {
|
||||||
|
advertisedDevice->m_callbackSent = true;
|
||||||
pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
|
pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
|
||||||
}
|
}
|
||||||
//m_pAdvertisedDeviceCallbacks->onResult(*advertisedDevice);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -166,7 +133,11 @@ NimBLEScan::NimBLEScan() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pScan->m_stopped = true;
|
pScan->m_stopped = true;
|
||||||
pScan->m_semaphoreScanEnd.give();
|
if(pScan->m_pTaskData != nullptr) {
|
||||||
|
pScan->m_pTaskData->rc = event->disc_complete.reason;
|
||||||
|
xTaskNotifyGive(pScan->m_pTaskData->task);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,13 +162,59 @@ void NimBLEScan::setActiveScan(bool active) {
|
||||||
} // setActiveScan
|
} // setActiveScan
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set whether or not the BLE controller should only report results
|
||||||
|
* from devices it has not already seen.
|
||||||
|
* @param [in] active If true, scanned devices will only be reported once.
|
||||||
|
* @details The controller has a limited buffer and will start reporting
|
||||||
|
* dupicate devices once the limit is reached.
|
||||||
|
*/
|
||||||
|
void NimBLEScan::setDuplicateFilter(bool active) {
|
||||||
|
m_scan_params.filter_duplicates = active;
|
||||||
|
} // setDuplicateFilter
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set whether or not the BLE controller only report scan results
|
||||||
|
* from devices advertising in limited discovery mode, i.e. directed advertising.
|
||||||
|
* @param [in] active If true, only limited discovery devices will be in scan results.
|
||||||
|
*/
|
||||||
|
void NimBLEScan::setLimitedOnly(bool active) {
|
||||||
|
m_scan_params.limited = active;
|
||||||
|
} // setLimited
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the scan filter policy.
|
||||||
|
* @param [in] filter Can be one of:
|
||||||
|
* BLE_HCI_SCAN_FILT_NO_WL (0)
|
||||||
|
* Scanner processes all advertising packets (white list not used) except
|
||||||
|
* directed, connectable advertising packets not sent to the scanner.
|
||||||
|
* BLE_HCI_SCAN_FILT_USE_WL (1)
|
||||||
|
* Scanner processes advertisements from white list only. A connectable,
|
||||||
|
* directed advertisment is ignored unless it contains scanners address.
|
||||||
|
* BLE_HCI_SCAN_FILT_NO_WL_INITA (2)
|
||||||
|
* Scanner process all advertising packets (white list not used). A
|
||||||
|
* connectable, directed advertisement shall not be ignored if the InitA
|
||||||
|
* is a resolvable private address.
|
||||||
|
* BLE_HCI_SCAN_FILT_USE_WL_INITA (3)
|
||||||
|
* Scanner process advertisements from white list only. A connectable,
|
||||||
|
* directed advertisement shall not be ignored if the InitA is a
|
||||||
|
* resolvable private address.
|
||||||
|
*/
|
||||||
|
void NimBLEScan::setFilterPolicy(uint8_t filter) {
|
||||||
|
m_scan_params.filter_policy = filter;
|
||||||
|
} // setFilterPolicy
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the call backs to be invoked.
|
* @brief Set the call backs to be invoked.
|
||||||
* @param [in] pAdvertisedDeviceCallbacks Call backs to be invoked.
|
* @param [in] pAdvertisedDeviceCallbacks Call backs to be invoked.
|
||||||
* @param [in] wantDuplicates True if we wish to be called back with duplicates. Default is false.
|
* @param [in] wantDuplicates True if we wish to be called back with duplicates. Default is false.
|
||||||
*/
|
*/
|
||||||
void NimBLEScan::setAdvertisedDeviceCallbacks(NimBLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks/*, bool wantDuplicates*/) {
|
void NimBLEScan::setAdvertisedDeviceCallbacks(NimBLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks,
|
||||||
//m_wantDuplicates = wantDuplicates;
|
bool wantDuplicates) {
|
||||||
|
m_wantDuplicates = wantDuplicates;
|
||||||
m_pAdvertisedDeviceCallbacks = pAdvertisedDeviceCallbacks;
|
m_pAdvertisedDeviceCallbacks = pAdvertisedDeviceCallbacks;
|
||||||
} // setAdvertisedDeviceCallbacks
|
} // setAdvertisedDeviceCallbacks
|
||||||
|
|
||||||
|
@ -248,7 +265,6 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul
|
||||||
}
|
}
|
||||||
|
|
||||||
m_stopped = false;
|
m_stopped = false;
|
||||||
m_semaphoreScanEnd.take("start");
|
|
||||||
|
|
||||||
// Save the callback to be invoked when the scan completes.
|
// Save the callback to be invoked when the scan completes.
|
||||||
m_scanCompleteCB = scanCompleteCB;
|
m_scanCompleteCB = scanCompleteCB;
|
||||||
|
@ -274,7 +290,7 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul
|
||||||
rc = ble_gap_disc(m_own_addr_type, duration, &m_scan_params,
|
rc = ble_gap_disc(m_own_addr_type, duration, &m_scan_params,
|
||||||
NimBLEScan::handleGapEvent, this);
|
NimBLEScan::handleGapEvent, this);
|
||||||
if(rc == BLE_HS_EBUSY) {
|
if(rc == BLE_HS_EBUSY) {
|
||||||
vTaskDelay(2);
|
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
} while(rc == BLE_HS_EBUSY);
|
} while(rc == BLE_HS_EBUSY);
|
||||||
|
|
||||||
|
@ -282,7 +298,6 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul
|
||||||
NIMBLE_LOGE(LOG_TAG, "Error initiating GAP discovery procedure; rc=%d, %s",
|
NIMBLE_LOGE(LOG_TAG, "Error initiating GAP discovery procedure; rc=%d, %s",
|
||||||
rc, NimBLEUtils::returnCodeToString(rc));
|
rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
m_stopped = true;
|
m_stopped = true;
|
||||||
m_semaphoreScanEnd.give();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,9 +312,18 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul
|
||||||
* @return The BLEScanResults.
|
* @return The BLEScanResults.
|
||||||
*/
|
*/
|
||||||
NimBLEScanResults NimBLEScan::start(uint32_t duration, bool is_continue) {
|
NimBLEScanResults NimBLEScan::start(uint32_t duration, bool is_continue) {
|
||||||
if(start(duration, nullptr, is_continue)) {
|
if(duration == 0) {
|
||||||
m_semaphoreScanEnd.wait("start"); // Wait for the semaphore to release.
|
NIMBLE_LOGW(LOG_TAG, "Blocking scan called with duration = forever");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ble_task_data_t taskData = {nullptr, xTaskGetCurrentTaskHandle(),0, nullptr};
|
||||||
|
m_pTaskData = &taskData;
|
||||||
|
|
||||||
|
if(start(duration, nullptr, is_continue)) {
|
||||||
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pTaskData = nullptr;
|
||||||
return m_scanResults;
|
return m_scanResults;
|
||||||
} // start
|
} // start
|
||||||
|
|
||||||
|
@ -308,13 +332,13 @@ NimBLEScanResults NimBLEScan::start(uint32_t duration, bool is_continue) {
|
||||||
* @brief Stop an in progress scan.
|
* @brief Stop an in progress scan.
|
||||||
* @return N/A.
|
* @return N/A.
|
||||||
*/
|
*/
|
||||||
void NimBLEScan::stop() {
|
bool NimBLEScan::stop() {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> stop()");
|
NIMBLE_LOGD(LOG_TAG, ">> stop()");
|
||||||
|
|
||||||
int rc = ble_gap_disc_cancel();
|
int rc = ble_gap_disc_cancel();
|
||||||
if (rc != 0 && rc != BLE_HS_EALREADY) {
|
if (rc != 0 && rc != BLE_HS_EALREADY) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Failed to cancel scan; rc=%d\n", rc);
|
NIMBLE_LOGE(LOG_TAG, "Failed to cancel scan; rc=%d\n", rc);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_stopped = true;
|
m_stopped = true;
|
||||||
|
@ -323,9 +347,12 @@ void NimBLEScan::stop() {
|
||||||
m_scanCompleteCB(m_scanResults);
|
m_scanCompleteCB(m_scanResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_semaphoreScanEnd.give();
|
if(m_pTaskData != nullptr) {
|
||||||
|
xTaskNotifyGive(m_pTaskData->task);
|
||||||
|
}
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< stop()");
|
NIMBLE_LOGD(LOG_TAG, "<< stop()");
|
||||||
|
return true;
|
||||||
} // stop
|
} // stop
|
||||||
|
|
||||||
|
|
||||||
|
@ -349,7 +376,6 @@ void NimBLEScan::erase(const NimBLEAddress &address) {
|
||||||
*/
|
*/
|
||||||
void NimBLEScan::onHostReset() {
|
void NimBLEScan::onHostReset() {
|
||||||
m_stopped = true;
|
m_stopped = true;
|
||||||
m_semaphoreScanEnd.give();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||||
|
|
||||||
#include "NimBLEAdvertisedDevice.h"
|
#include "NimBLEAdvertisedDevice.h"
|
||||||
#include "FreeRTOS.h"
|
#include "NimBLEUtils.h"
|
||||||
|
|
||||||
#include "host/ble_gap.h"
|
#include "host/ble_gap.h"
|
||||||
|
|
||||||
|
@ -62,11 +62,14 @@ class NimBLEScan {
|
||||||
public:
|
public:
|
||||||
bool start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResults), bool is_continue = false);
|
bool start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResults), bool is_continue = false);
|
||||||
NimBLEScanResults start(uint32_t duration, bool is_continue = false);
|
NimBLEScanResults start(uint32_t duration, bool is_continue = false);
|
||||||
void setAdvertisedDeviceCallbacks(NimBLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks/*, bool wantDuplicates = false*/);
|
void setAdvertisedDeviceCallbacks(NimBLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks, bool wantDuplicates = false);
|
||||||
void setActiveScan(bool active);
|
void setActiveScan(bool active);
|
||||||
void setInterval(uint16_t intervalMSecs);
|
void setInterval(uint16_t intervalMSecs);
|
||||||
void setWindow(uint16_t windowMSecs);
|
void setWindow(uint16_t windowMSecs);
|
||||||
void stop();
|
void setDuplicateFilter(bool active);
|
||||||
|
void setLimitedOnly(bool active);
|
||||||
|
void setFilterPolicy(uint8_t filter);
|
||||||
|
bool stop();
|
||||||
void clearResults();
|
void clearResults();
|
||||||
NimBLEScanResults getResults();
|
NimBLEScanResults getResults();
|
||||||
void erase(const NimBLEAddress &address);
|
void erase(const NimBLEAddress &address);
|
||||||
|
@ -85,8 +88,8 @@ private:
|
||||||
bool m_stopped;
|
bool m_stopped;
|
||||||
bool m_wantDuplicates;
|
bool m_wantDuplicates;
|
||||||
NimBLEScanResults m_scanResults;
|
NimBLEScanResults m_scanResults;
|
||||||
FreeRTOS::Semaphore m_semaphoreScanEnd = FreeRTOS::Semaphore("ScanEnd");
|
|
||||||
uint32_t m_duration;
|
uint32_t m_duration;
|
||||||
|
ble_task_data_t *m_pTaskData;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||||
|
|
|
@ -19,8 +19,6 @@
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
|
||||||
#include "NimBLEServer.h"
|
#include "NimBLEServer.h"
|
||||||
#include "NimBLE2902.h"
|
|
||||||
#include "NimBLEUtils.h"
|
|
||||||
#include "NimBLEDevice.h"
|
#include "NimBLEDevice.h"
|
||||||
#include "NimBLELog.h"
|
#include "NimBLELog.h"
|
||||||
|
|
||||||
|
@ -32,51 +30,46 @@ static NimBLEServerCallbacks defaultCallbacks;
|
||||||
* @brief Construct a %BLE Server
|
* @brief Construct a %BLE Server
|
||||||
*
|
*
|
||||||
* This class is not designed to be individually instantiated. Instead one should create a server by asking
|
* This class is not designed to be individually instantiated. Instead one should create a server by asking
|
||||||
* the BLEDevice class.
|
* the NimBLEDevice class.
|
||||||
*/
|
*/
|
||||||
NimBLEServer::NimBLEServer() {
|
NimBLEServer::NimBLEServer() {
|
||||||
m_connId = BLE_HS_CONN_HANDLE_NONE;
|
// m_svcChgChrHdl = 0xffff; // Future Use
|
||||||
m_svcChgChrHdl = 0xffff;
|
|
||||||
m_pServerCallbacks = &defaultCallbacks;
|
m_pServerCallbacks = &defaultCallbacks;
|
||||||
m_gattsStarted = false;
|
m_gattsStarted = false;
|
||||||
} // BLEServer
|
m_advertiseOnDisconnect = true;
|
||||||
|
} // NimBLEServer
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a %BLE Service.
|
* @brief Create a %BLE Service.
|
||||||
*
|
|
||||||
* With a %BLE server, we can host one or more services. Invoking this function causes the creation of a definition
|
|
||||||
* of a new service. Every service must have a unique UUID.
|
|
||||||
* @param [in] uuid The UUID of the new service.
|
* @param [in] uuid The UUID of the new service.
|
||||||
* @return A reference to the new service object.
|
* @return A reference to the new service object.
|
||||||
*/
|
*/
|
||||||
NimBLEService* NimBLEServer::createService(const char* uuid) {
|
NimBLEService* NimBLEServer::createService(const char* uuid) {
|
||||||
return createService(NimBLEUUID(uuid));
|
return createService(NimBLEUUID(uuid));
|
||||||
}
|
} // createService
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a %BLE Service.
|
* @brief Create a %BLE Service.
|
||||||
*
|
|
||||||
* With a %BLE server, we can host one or more services. Invoking this function causes the creation of a definition
|
|
||||||
* of a new service. Every service must have a unique UUID.
|
|
||||||
* @param [in] uuid The UUID of the new service.
|
* @param [in] uuid The UUID of the new service.
|
||||||
* @param [in] numHandles The maximum number of handles associated with this service.
|
* @param [in] numHandles The maximum number of handles associated with this service.
|
||||||
* @param [in] inst_id With multiple services with the same UUID we need to provide inst_id value different for each service.
|
* @param [in] inst_id if we have multiple services with the same UUID we need
|
||||||
|
* to provide inst_id value different for each service.
|
||||||
* @return A reference to the new service object.
|
* @return A reference to the new service object.
|
||||||
*/
|
*/
|
||||||
NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid, uint32_t numHandles, uint8_t inst_id) {
|
NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid, uint32_t numHandles, uint8_t inst_id) {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> createService - %s", uuid.toString().c_str());
|
NIMBLE_LOGD(LOG_TAG, ">> createService - %s", uuid.toString().c_str());
|
||||||
|
// TODO: add functionality to use inst_id for multiple services with same uuid
|
||||||
|
(void)inst_id;
|
||||||
// Check that a service with the supplied UUID does not already exist.
|
// Check that a service with the supplied UUID does not already exist.
|
||||||
if (m_serviceMap.getByUUID(uuid) != nullptr) {
|
if(getServiceByUUID(uuid) != nullptr) {
|
||||||
NIMBLE_LOGW(LOG_TAG, "<< Attempt to create a new service with uuid %s but a service with that UUID already exists.",
|
NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s",
|
||||||
uuid.toString().c_str());
|
std::string(uuid).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
NimBLEService* pService = new NimBLEService(uuid, numHandles, this);
|
NimBLEService* pService = new NimBLEService(uuid, numHandles, this);
|
||||||
pService->m_instId = inst_id;
|
m_svcVec.push_back(pService); // Save a reference to this service being on this server.
|
||||||
m_serviceMap.setByUUID(uuid, pService); // Save a reference to this service being on this server.
|
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< createService");
|
NIMBLE_LOGD(LOG_TAG, "<< createService");
|
||||||
return pService;
|
return pService;
|
||||||
|
@ -89,8 +82,8 @@ NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid, uint32_t numH
|
||||||
* @return A reference to the service object.
|
* @return A reference to the service object.
|
||||||
*/
|
*/
|
||||||
NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid) {
|
NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid) {
|
||||||
return m_serviceMap.getByUUID(uuid);
|
return getServiceByUUID(NimBLEUUID(uuid));
|
||||||
}
|
} // getServiceByUUID
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,8 +92,13 @@ NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid) {
|
||||||
* @return A reference to the service object.
|
* @return A reference to the service object.
|
||||||
*/
|
*/
|
||||||
NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID &uuid) {
|
NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID &uuid) {
|
||||||
return m_serviceMap.getByUUID(uuid);
|
for (auto &it : m_svcVec) {
|
||||||
|
if (it->getUUID() == uuid) {
|
||||||
|
return it;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
} // getServiceByUUID
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -109,18 +107,8 @@ NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID &uuid) {
|
||||||
* @return An advertising object.
|
* @return An advertising object.
|
||||||
*/
|
*/
|
||||||
NimBLEAdvertising* NimBLEServer::getAdvertising() {
|
NimBLEAdvertising* NimBLEServer::getAdvertising() {
|
||||||
return BLEDevice::getAdvertising();
|
return NimBLEDevice::getAdvertising();
|
||||||
}
|
} // getAdvertising
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Retrieve the connection id of the last connected client.
|
|
||||||
* @todo Not very useful, should refactor or remove.
|
|
||||||
* @return Client connection id.
|
|
||||||
*/
|
|
||||||
uint16_t NimBLEServer::getConnId() {
|
|
||||||
return m_connId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -143,6 +131,8 @@ void NimBLEServer::start() {
|
||||||
#if CONFIG_LOG_DEFAULT_LEVEL > 3 || (ARDUINO_ARCH_ESP32 && CORE_DEBUG_LEVEL >= 4)
|
#if CONFIG_LOG_DEFAULT_LEVEL > 3 || (ARDUINO_ARCH_ESP32 && CORE_DEBUG_LEVEL >= 4)
|
||||||
ble_gatts_show_local();
|
ble_gatts_show_local();
|
||||||
#endif
|
#endif
|
||||||
|
/*** Future use ***
|
||||||
|
* TODO: implement service changed handling
|
||||||
|
|
||||||
ble_uuid16_t svc = {BLE_UUID_TYPE_16, 0x1801};
|
ble_uuid16_t svc = {BLE_UUID_TYPE_16, 0x1801};
|
||||||
ble_uuid16_t chr = {BLE_UUID_TYPE_16, 0x2a05};
|
ble_uuid16_t chr = {BLE_UUID_TYPE_16, 0x2a05};
|
||||||
|
@ -155,36 +145,25 @@ void NimBLEServer::start() {
|
||||||
}
|
}
|
||||||
|
|
||||||
NIMBLE_LOGI(LOG_TAG, "Service changed characterisic handle: %d", m_svcChgChrHdl);
|
NIMBLE_LOGI(LOG_TAG, "Service changed characterisic handle: %d", m_svcChgChrHdl);
|
||||||
|
*/
|
||||||
// Build a map of characteristics with Notify / Indicate capabilities for event handling
|
// Build a vector of characteristics with Notify / Indicate capabilities for event handling
|
||||||
uint8_t numSvcs = m_serviceMap.getRegisteredServiceCount();
|
for(auto &svc : m_svcVec) {
|
||||||
NimBLEService* pService = m_serviceMap.getFirst();
|
for(auto &chr : svc->m_chrVec) {
|
||||||
|
|
||||||
for(int i = 0; i < numSvcs; i++) {
|
|
||||||
uint8_t numChrs = pService->m_characteristicMap.getSize();
|
|
||||||
NimBLECharacteristic* pChr = pService->m_characteristicMap.getFirst();
|
|
||||||
|
|
||||||
if(pChr != nullptr) {
|
|
||||||
for( int d = 0; d < numChrs; d++) {
|
|
||||||
// if Notify / Indicate is enabled but we didn't create the descriptor
|
// if Notify / Indicate is enabled but we didn't create the descriptor
|
||||||
// we do it now.
|
// we do it now.
|
||||||
if((pChr->m_properties & BLE_GATT_CHR_F_INDICATE) ||
|
if((chr->m_properties & BLE_GATT_CHR_F_INDICATE) ||
|
||||||
(pChr->m_properties & BLE_GATT_CHR_F_NOTIFY)) {
|
(chr->m_properties & BLE_GATT_CHR_F_NOTIFY)) {
|
||||||
|
|
||||||
if(nullptr == pChr->getDescriptorByUUID("2902")) {
|
if(nullptr == chr->getDescriptorByUUID(uint16_t(0x2902))) {
|
||||||
pChr->createDescriptor("2902");
|
chr->createDescriptor(uint16_t(0x2902));
|
||||||
}
|
}
|
||||||
m_notifyChrMap.insert(std::pair<uint16_t, NimBLECharacteristic*>
|
m_notifyChrVec.push_back(chr);
|
||||||
(pChr->getHandle(), pChr));
|
|
||||||
}
|
|
||||||
pChr = pService->m_characteristicMap.getNext();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pService = m_serviceMap.getNext();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_gattsStarted = true;
|
m_gattsStarted = true;
|
||||||
}
|
} // start
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -202,17 +181,26 @@ int NimBLEServer::disconnect(uint16_t connId, uint8_t reason) {
|
||||||
NimBLEUtils::returnCodeToString(rc));
|
NimBLEUtils::returnCodeToString(rc));
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< disconnect()");
|
NIMBLE_LOGD(LOG_TAG, "<< disconnect()");
|
||||||
}
|
return rc;
|
||||||
|
} // disconnect
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the server to automatically start advertising when a client disconnects.
|
||||||
|
* @param [in] bool true == advertise, false == don't advertise.
|
||||||
|
*/
|
||||||
|
void NimBLEServer::advertiseOnDisconnect(bool aod) {
|
||||||
|
m_advertiseOnDisconnect = aod;
|
||||||
|
} // advertiseOnDisconnect
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return the number of connected clients.
|
* @brief Return the number of connected clients.
|
||||||
* @return The number of connected clients.
|
* @return The number of connected clients.
|
||||||
*/
|
*/
|
||||||
uint32_t NimBLEServer::getConnectedCount() {
|
size_t NimBLEServer::getConnectedCount() {
|
||||||
return m_connectedServersMap.size();
|
return m_connectedPeersVec.size();
|
||||||
} // getConnectedCount
|
} // getConnectedCount
|
||||||
|
|
||||||
|
|
||||||
|
@ -236,15 +224,12 @@ uint32_t NimBLEServer::getConnectedCount() {
|
||||||
case BLE_GAP_EVENT_CONNECT: {
|
case BLE_GAP_EVENT_CONNECT: {
|
||||||
if (event->connect.status != 0) {
|
if (event->connect.status != 0) {
|
||||||
/* Connection failed; resume advertising */
|
/* Connection failed; resume advertising */
|
||||||
NIMBLE_LOGC(LOG_TAG, "Connection failed");
|
NIMBLE_LOGE(LOG_TAG, "Connection failed");
|
||||||
NimBLEDevice::startAdvertising();
|
NimBLEDevice::startAdvertising();
|
||||||
server->m_connId = BLE_HS_CONN_HANDLE_NONE;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
server->m_connId = event->connect.conn_handle;
|
server->m_connectedPeersVec.push_back(event->connect.conn_handle);
|
||||||
server->addPeerDevice((void*)server, false, server->m_connId);
|
|
||||||
|
|
||||||
ble_gap_conn_desc desc;
|
|
||||||
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
|
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
|
||||||
assert(rc == 0);
|
assert(rc == 0);
|
||||||
|
|
||||||
|
@ -271,10 +256,15 @@ uint32_t NimBLEServer::getConnectedCount() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
server->removePeerDevice(event->disconnect.conn.conn_handle, false);
|
server->m_connectedPeersVec.erase(std::remove(server->m_connectedPeersVec.begin(),
|
||||||
server->m_connId = BLE_HS_CONN_HANDLE_NONE;
|
server->m_connectedPeersVec.end(),
|
||||||
|
event->disconnect.conn.conn_handle),
|
||||||
|
server->m_connectedPeersVec.end());
|
||||||
server->m_pServerCallbacks->onDisconnect(server);
|
server->m_pServerCallbacks->onDisconnect(server);
|
||||||
|
|
||||||
|
if(server->m_advertiseOnDisconnect) {
|
||||||
|
server->startAdvertising();
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} // BLE_GAP_EVENT_DISCONNECT
|
} // BLE_GAP_EVENT_DISCONNECT
|
||||||
|
|
||||||
|
@ -283,9 +273,23 @@ uint32_t NimBLEServer::getConnectedCount() {
|
||||||
"val_handle=%d\n",
|
"val_handle=%d\n",
|
||||||
event->subscribe.cur_notify, event->subscribe.attr_handle);
|
event->subscribe.cur_notify, event->subscribe.attr_handle);
|
||||||
|
|
||||||
auto it = server->m_notifyChrMap.find(event->subscribe.attr_handle);
|
for(auto &it : server->m_notifyChrVec) {
|
||||||
if(it != server->m_notifyChrMap.cend()) {
|
if(it->getHandle() == event->subscribe.attr_handle) {
|
||||||
(*it).second->setSubscribe(event);
|
if((it->getProperties() & BLE_GATT_CHR_F_READ_AUTHEN) ||
|
||||||
|
(it->getProperties() & BLE_GATT_CHR_F_READ_AUTHOR) ||
|
||||||
|
(it->getProperties() & BLE_GATT_CHR_F_READ_ENC))
|
||||||
|
{
|
||||||
|
rc = ble_gap_conn_find(event->subscribe.conn_handle, &desc);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
if(!desc.sec_state.encrypted) {
|
||||||
|
NimBLEDevice::startSecurity(event->subscribe.conn_handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it->setSubscribe(event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -295,15 +299,19 @@ uint32_t NimBLEServer::getConnectedCount() {
|
||||||
NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d",
|
NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d",
|
||||||
event->mtu.conn_handle,
|
event->mtu.conn_handle,
|
||||||
event->mtu.value);
|
event->mtu.value);
|
||||||
server->updatePeerMTU(event->mtu.conn_handle, event->mtu.value);
|
|
||||||
return 0;
|
return 0;
|
||||||
} // BLE_GAP_EVENT_MTU
|
} // BLE_GAP_EVENT_MTU
|
||||||
|
|
||||||
case BLE_GAP_EVENT_NOTIFY_TX: {
|
case BLE_GAP_EVENT_NOTIFY_TX: {
|
||||||
if(event->notify_tx.indication && event->notify_tx.status != 0) {
|
if(event->notify_tx.indication && event->notify_tx.status != 0) {
|
||||||
auto it = server->m_notifyChrMap.find(event->notify_tx.attr_handle);
|
for(auto &it : server->m_notifyChrVec) {
|
||||||
if(it != server->m_notifyChrMap.cend()) {
|
if(it->getHandle() == event->notify_tx.attr_handle) {
|
||||||
(*it).second->m_semaphoreConfEvt.give(event->notify_tx.status);
|
if(it->m_pTaskData != nullptr) {
|
||||||
|
it->m_pTaskData->rc = event->notify_tx.status;
|
||||||
|
xTaskNotifyGive(it->m_pTaskData->task);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,7 +341,7 @@ uint32_t NimBLEServer::getConnectedCount() {
|
||||||
} // BLE_GAP_EVENT_REPEAT_PAIRING
|
} // BLE_GAP_EVENT_REPEAT_PAIRING
|
||||||
|
|
||||||
case BLE_GAP_EVENT_ENC_CHANGE: {
|
case BLE_GAP_EVENT_ENC_CHANGE: {
|
||||||
rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc);
|
rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc);
|
||||||
if(rc != 0) {
|
if(rc != 0) {
|
||||||
return BLE_ATT_ERR_INVALID_HANDLE;
|
return BLE_ATT_ERR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
@ -349,7 +357,7 @@ uint32_t NimBLEServer::getConnectedCount() {
|
||||||
} // BLE_GAP_EVENT_ENC_CHANGE
|
} // BLE_GAP_EVENT_ENC_CHANGE
|
||||||
|
|
||||||
case BLE_GAP_EVENT_PASSKEY_ACTION: {
|
case BLE_GAP_EVENT_PASSKEY_ACTION: {
|
||||||
struct ble_sm_io pkey = {0};
|
struct ble_sm_io pkey = {0,0};
|
||||||
|
|
||||||
if (event->passkey.params.action == BLE_SM_IOACT_DISP) {
|
if (event->passkey.params.action == BLE_SM_IOACT_DISP) {
|
||||||
pkey.action = event->passkey.params.action;
|
pkey.action = event->passkey.params.action;
|
||||||
|
@ -416,7 +424,7 @@ uint32_t NimBLEServer::getConnectedCount() {
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< handleGATTServerEvent");
|
NIMBLE_LOGD(LOG_TAG, "<< handleGATTServerEvent");
|
||||||
return 0;
|
return 0;
|
||||||
} // handleGATTServerEvent
|
} // handleGapEvent
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -437,18 +445,6 @@ void NimBLEServer::setCallbacks(NimBLEServerCallbacks* pCallbacks) {
|
||||||
} // setCallbacks
|
} // setCallbacks
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Remove service
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
void BLEServer::removeService(BLEService* service) {
|
|
||||||
service->stop();
|
|
||||||
service->executeDelete();
|
|
||||||
m_serviceMap.removeService(service);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Start advertising.
|
* @brief Start advertising.
|
||||||
*
|
*
|
||||||
|
@ -456,9 +452,7 @@ void BLEServer::removeService(BLEService* service) {
|
||||||
* retrieving the advertising object and invoking start upon it.
|
* retrieving the advertising object and invoking start upon it.
|
||||||
*/
|
*/
|
||||||
void NimBLEServer::startAdvertising() {
|
void NimBLEServer::startAdvertising() {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> startAdvertising");
|
|
||||||
NimBLEDevice::startAdvertising();
|
NimBLEDevice::startAdvertising();
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< startAdvertising");
|
|
||||||
} // startAdvertising
|
} // startAdvertising
|
||||||
|
|
||||||
|
|
||||||
|
@ -466,38 +460,43 @@ void NimBLEServer::startAdvertising() {
|
||||||
* @brief Stop advertising.
|
* @brief Stop advertising.
|
||||||
*/
|
*/
|
||||||
void NimBLEServer::stopAdvertising() {
|
void NimBLEServer::stopAdvertising() {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> stopAdvertising");
|
|
||||||
NimBLEDevice::stopAdvertising();
|
NimBLEDevice::stopAdvertising();
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< stopAdvertising");
|
|
||||||
} // startAdvertising
|
} // startAdvertising
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow to connect GATT server to peer device
|
* @brief Get the MTU of the client.
|
||||||
* Probably can be used in ANCS for iPhone
|
* @returns The client MTU or 0 if not found/connected.
|
||||||
*/
|
*/
|
||||||
/*
|
uint16_t NimBLEServer::getPeerMTU(uint16_t conn_id) {
|
||||||
bool BLEServer::connect(BLEAddress address) {
|
return ble_att_mtu(conn_id);
|
||||||
esp_bd_addr_t addr;
|
} //getPeerMTU
|
||||||
memcpy(&addr, address.getNative(), 6);
|
|
||||||
// Perform the open connection request against the target BLE Server.
|
|
||||||
m_semaphoreOpenEvt.take("connect");
|
/**
|
||||||
esp_err_t errRc = ::esp_ble_gatts_open(
|
* Update connection parameters can be called only after connection has been established
|
||||||
getGattsIf(),
|
*/
|
||||||
addr, // address
|
void NimBLEServer::updateConnParams(uint16_t conn_handle,
|
||||||
1 // direct connection
|
uint16_t minInterval, uint16_t maxInterval,
|
||||||
);
|
uint16_t latency, uint16_t timeout)
|
||||||
if (errRc != ESP_OK) {
|
{
|
||||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_open: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
ble_gap_upd_params params;
|
||||||
return false;
|
|
||||||
|
params.latency = latency;
|
||||||
|
params.itvl_max = maxInterval; // max_int = 0x20*1.25ms = 40ms
|
||||||
|
params.itvl_min = minInterval; // min_int = 0x10*1.25ms = 20ms
|
||||||
|
params.supervision_timeout = timeout; // timeout = 400*10ms = 4000ms
|
||||||
|
params.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; // Minimum length of connection event in 0.625ms units
|
||||||
|
params.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; // Maximum length of connection event in 0.625ms units
|
||||||
|
|
||||||
|
int rc = ble_gap_update_params(conn_handle, ¶ms);
|
||||||
|
if(rc != 0) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
}
|
}
|
||||||
|
} // updateConnParams
|
||||||
|
|
||||||
uint32_t rc = m_semaphoreOpenEvt.wait("connect"); // Wait for the connection to complete.
|
|
||||||
ESP_LOGD(LOG_TAG, "<< connect(), rc=%d", rc==ESP_GATT_OK);
|
|
||||||
return rc == ESP_GATT_OK;
|
|
||||||
} // connect
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
/** Default callback handlers */
|
||||||
|
|
||||||
void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer) {
|
void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer) {
|
||||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onConnect(): Default");
|
NIMBLE_LOGD("NimBLEServerCallbacks", "onConnect(): Default");
|
||||||
|
@ -534,80 +533,6 @@ bool NimBLEServerCallbacks::onConfirmPIN(uint32_t pin){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* multi connect support */
|
|
||||||
void NimBLEServer::updatePeerMTU(uint16_t conn_id, uint16_t mtu) {
|
|
||||||
const std::map<uint16_t, conn_status_t>::iterator it = m_connectedServersMap.find(conn_id);
|
|
||||||
if (it != m_connectedServersMap.end()) {
|
|
||||||
it->second.mtu = mtu;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<uint16_t, conn_status_t> NimBLEServer::getPeerDevices() {
|
|
||||||
return m_connectedServersMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the MTU of the client.
|
|
||||||
* @returns The client MTU or 0 if not found/connected.
|
|
||||||
*/
|
|
||||||
uint16_t NimBLEServer::getPeerMTU(uint16_t conn_id) {
|
|
||||||
auto it = m_connectedServersMap.find(conn_id);
|
|
||||||
if(it != m_connectedServersMap.cend()) {
|
|
||||||
return (*it).second.mtu;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NimBLEServer::addPeerDevice(void* peer, bool _client, uint16_t conn_id) {
|
|
||||||
conn_status_t status = {
|
|
||||||
.peer_device = peer,
|
|
||||||
.connected = true,
|
|
||||||
.mtu = 23
|
|
||||||
};
|
|
||||||
|
|
||||||
m_connectedServersMap.insert(std::pair<uint16_t, conn_status_t>(conn_id, status));
|
|
||||||
}
|
|
||||||
|
|
||||||
void NimBLEServer::removePeerDevice(uint16_t conn_id, bool _client) {
|
|
||||||
m_connectedServersMap.erase(conn_id);
|
|
||||||
}
|
|
||||||
/* multi connect support */
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update connection parameters can be called only after connection has been established
|
|
||||||
*/
|
|
||||||
void NimBLEServer::updateConnParams(uint16_t conn_handle,
|
|
||||||
uint16_t minInterval, uint16_t maxInterval,
|
|
||||||
uint16_t latency, uint16_t timeout,
|
|
||||||
uint16_t minConnTime, uint16_t maxConnTime)
|
|
||||||
{
|
|
||||||
ble_gap_upd_params params;
|
|
||||||
|
|
||||||
params.latency = latency;
|
|
||||||
params.itvl_max = maxInterval; // max_int = 0x20*1.25ms = 40ms
|
|
||||||
params.itvl_min = minInterval; // min_int = 0x10*1.25ms = 20ms
|
|
||||||
params.supervision_timeout = timeout; // timeout = 400*10ms = 4000ms
|
|
||||||
params.min_ce_len = minConnTime; // Minimum length of connection event in 0.625ms units
|
|
||||||
params.max_ce_len = maxConnTime; // Maximum length of connection event in 0.625ms units
|
|
||||||
|
|
||||||
int rc = ble_gap_update_params(conn_handle, ¶ms);
|
|
||||||
if(rc != 0) {
|
|
||||||
NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Don't think this is needed
|
|
||||||
|
|
||||||
void NimBLEServer::onHostReset() {
|
|
||||||
for(auto it = m_notifyChrMap.cbegin(); it != m_notifyChrMap.cend(); ++it) {
|
|
||||||
(*it).second->m_semaphoreConfEvt.give(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
#endif // CONFIG_BT_ENABLED
|
#endif // CONFIG_BT_ENABLED
|
||||||
|
|
|
@ -20,101 +20,58 @@
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
|
||||||
|
#include "NimBLEUtils.h"
|
||||||
#include "NimBLEAddress.h"
|
#include "NimBLEAddress.h"
|
||||||
#include "NimBLEUUID.h"
|
|
||||||
#include "NimBLEAdvertising.h"
|
#include "NimBLEAdvertising.h"
|
||||||
#include "NimBLEService.h"
|
#include "NimBLEService.h"
|
||||||
#include "NimBLESecurity.h"
|
#include "NimBLESecurity.h"
|
||||||
#include "FreeRTOS.h"
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
class NimBLEService;
|
class NimBLEService;
|
||||||
class NimBLECharacteristic;
|
class NimBLECharacteristic;
|
||||||
class NimBLEServerCallbacks;
|
class NimBLEServerCallbacks;
|
||||||
|
|
||||||
/* TODO possibly refactor this struct */
|
|
||||||
typedef struct {
|
|
||||||
void *peer_device; // peer device BLEClient or BLEServer - maybe its better to have 2 structures or union here
|
|
||||||
bool connected; // do we need it?
|
|
||||||
uint16_t mtu; // every peer device negotiate own mtu
|
|
||||||
} conn_status_t;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A data structure that manages the %BLE servers owned by a BLE server.
|
|
||||||
*/
|
|
||||||
class NimBLEServiceMap {
|
|
||||||
public:
|
|
||||||
// NimBLEService* getByHandle(uint16_t handle);
|
|
||||||
NimBLEService* getByUUID(const char* uuid);
|
|
||||||
NimBLEService* getByUUID(const NimBLEUUID &uuid, uint8_t inst_id = 0);
|
|
||||||
// void setByHandle(uint16_t handle, NimBLEService* service);
|
|
||||||
void setByUUID(const char* uuid, NimBLEService* service);
|
|
||||||
void setByUUID(const NimBLEUUID &uuid, NimBLEService* service);
|
|
||||||
std::string toString();
|
|
||||||
NimBLEService* getFirst();
|
|
||||||
NimBLEService* getNext();
|
|
||||||
void removeService(NimBLEService *service);
|
|
||||||
int getRegisteredServiceCount();
|
|
||||||
|
|
||||||
private:
|
|
||||||
// std::map<uint16_t, NimBLEService*> m_handleMap;
|
|
||||||
std::map<NimBLEService*, std::string> m_uuidMap;
|
|
||||||
std::map<NimBLEService*, std::string>::iterator m_iterator;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The model of a %BLE server.
|
* @brief The model of a %BLE server.
|
||||||
*/
|
*/
|
||||||
class NimBLEServer {
|
class NimBLEServer {
|
||||||
public:
|
public:
|
||||||
uint32_t getConnectedCount();
|
size_t getConnectedCount();
|
||||||
NimBLEService* createService(const char* uuid);
|
NimBLEService* createService(const char* uuid);
|
||||||
NimBLEService* createService(const NimBLEUUID &uuid, uint32_t numHandles=15, uint8_t inst_id=0);
|
NimBLEService* createService(const NimBLEUUID &uuid, uint32_t numHandles=15,
|
||||||
|
uint8_t inst_id=0);
|
||||||
NimBLEAdvertising* getAdvertising();
|
NimBLEAdvertising* getAdvertising();
|
||||||
void setCallbacks(NimBLEServerCallbacks* pCallbacks);
|
void setCallbacks(NimBLEServerCallbacks* pCallbacks);
|
||||||
void startAdvertising();
|
void startAdvertising();
|
||||||
void stopAdvertising();
|
void stopAdvertising();
|
||||||
void start();
|
void start();
|
||||||
// void removeService(BLEService* service);
|
|
||||||
NimBLEService* getServiceByUUID(const char* uuid);
|
NimBLEService* getServiceByUUID(const char* uuid);
|
||||||
NimBLEService* getServiceByUUID(const NimBLEUUID &uuid);
|
NimBLEService* getServiceByUUID(const NimBLEUUID &uuid);
|
||||||
int disconnect(uint16_t connID, uint8_t reason = BLE_ERR_REM_USER_CONN_TERM);
|
int disconnect(uint16_t connID,
|
||||||
// bool connect(BLEAddress address);
|
uint8_t reason = BLE_ERR_REM_USER_CONN_TERM);
|
||||||
void updateConnParams(uint16_t conn_handle,
|
void updateConnParams(uint16_t conn_handle,
|
||||||
uint16_t minInterval, uint16_t maxInterval,
|
uint16_t minInterval, uint16_t maxInterval,
|
||||||
uint16_t latency, uint16_t timeout,
|
uint16_t latency, uint16_t timeout);
|
||||||
uint16_t minConnTime=0, uint16_t maxConnTime=0);
|
|
||||||
|
|
||||||
/* multi connection support */
|
|
||||||
std::map<uint16_t, conn_status_t> getPeerDevices();
|
|
||||||
void addPeerDevice(void* peer, bool is_client, uint16_t conn_id);
|
|
||||||
void removePeerDevice(uint16_t conn_id, bool client);
|
|
||||||
NimBLEServer* getServerByConnId(uint16_t conn_id);
|
|
||||||
void updatePeerMTU(uint16_t connId, uint16_t mtu);
|
|
||||||
uint16_t getPeerMTU(uint16_t conn_id);
|
uint16_t getPeerMTU(uint16_t conn_id);
|
||||||
uint16_t getConnId();
|
std::vector<uint16_t> getPeerDevices();
|
||||||
|
void advertiseOnDisconnect(bool);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NimBLEServer();
|
NimBLEServer();
|
||||||
//friend class BLEService;
|
|
||||||
friend class NimBLECharacteristic;
|
friend class NimBLECharacteristic;
|
||||||
friend class NimBLEDevice;
|
friend class NimBLEDevice;
|
||||||
friend class NimBLEAdvertising;
|
friend class NimBLEAdvertising;
|
||||||
// void onHostReset();
|
|
||||||
// BLEAdvertising m_bleAdvertising;
|
|
||||||
uint16_t m_connId;
|
|
||||||
uint16_t m_svcChgChrHdl;
|
|
||||||
bool m_gattsStarted;
|
bool m_gattsStarted;
|
||||||
|
bool m_advertiseOnDisconnect;
|
||||||
std::map<uint16_t, conn_status_t> m_connectedServersMap;
|
|
||||||
std::map<uint16_t, NimBLECharacteristic*> m_notifyChrMap;
|
|
||||||
|
|
||||||
NimBLEServiceMap m_serviceMap;
|
|
||||||
NimBLEServerCallbacks* m_pServerCallbacks;
|
NimBLEServerCallbacks* m_pServerCallbacks;
|
||||||
|
std::vector<uint16_t> m_connectedPeersVec;
|
||||||
|
|
||||||
|
// uint16_t m_svcChgChrHdl; // Future use
|
||||||
|
|
||||||
|
std::vector<NimBLEService*> m_svcVec;
|
||||||
|
std::vector<NimBLECharacteristic*> m_notifyChrVec;
|
||||||
|
|
||||||
static int handleGapEvent(struct ble_gap_event *event, void *arg);
|
static int handleGapEvent(struct ble_gap_event *event, void *arg);
|
||||||
}; // NimBLEServer
|
}; // NimBLEServer
|
||||||
|
@ -149,7 +106,7 @@ public:
|
||||||
virtual bool onSecurityRequest(); //{return true;}
|
virtual bool onSecurityRequest(); //{return true;}
|
||||||
virtual void onAuthenticationComplete(ble_gap_conn_desc* desc);//{};
|
virtual void onAuthenticationComplete(ble_gap_conn_desc* desc);//{};
|
||||||
virtual bool onConfirmPIN(uint32_t pin);//{return true;}
|
virtual bool onConfirmPIN(uint32_t pin);//{return true;}
|
||||||
}; // BLEServerCallbacks
|
}; // NimBLEServerCallbacks
|
||||||
|
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
|
|
@ -32,9 +32,10 @@ static const char* LOG_TAG = "NimBLEService"; // Tag for logging.
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Construct an instance of the BLEService
|
* @brief Construct an instance of the NimBLEService
|
||||||
* @param [in] uuid The UUID of the service.
|
* @param [in] uuid The UUID of the service.
|
||||||
* @param [in] numHandles The maximum number of handles associated with the service.
|
* @param [in] numHandles The maximum number of handles associated with the service.
|
||||||
|
* @param [in] a pointer to the server instance that this service belongs to.
|
||||||
*/
|
*/
|
||||||
NimBLEService::NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer)
|
NimBLEService::NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer)
|
||||||
: NimBLEService(NimBLEUUID(uuid), numHandles, pServer) {
|
: NimBLEService(NimBLEUUID(uuid), numHandles, pServer) {
|
||||||
|
@ -45,6 +46,7 @@ NimBLEService::NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer
|
||||||
* @brief Construct an instance of the BLEService
|
* @brief Construct an instance of the BLEService
|
||||||
* @param [in] uuid The UUID of the service.
|
* @param [in] uuid The UUID of the service.
|
||||||
* @param [in] numHandles The maximum number of handles associated with the service.
|
* @param [in] numHandles The maximum number of handles associated with the service.
|
||||||
|
* @param [in] a pointer to the server instance that this service belongs to.
|
||||||
*/
|
*/
|
||||||
NimBLEService::NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLEServer* pServer) {
|
NimBLEService::NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLEServer* pServer) {
|
||||||
m_uuid = uuid;
|
m_uuid = uuid;
|
||||||
|
@ -59,10 +61,22 @@ NimBLEService::NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLE
|
||||||
* @return N/A.
|
* @return N/A.
|
||||||
*/
|
*/
|
||||||
void NimBLEService::dump() {
|
void NimBLEService::dump() {
|
||||||
NIMBLE_LOGD(LOG_TAG, "Service: uuid:%s, handle: 0x%.2x",
|
NIMBLE_LOGD(LOG_TAG, "Service: uuid:%s, handle: 0x%2x",
|
||||||
m_uuid.toString().c_str(),
|
m_uuid.toString().c_str(),
|
||||||
m_handle);
|
m_handle);
|
||||||
NIMBLE_LOGD(LOG_TAG, "Characteristics:\n%s", m_characteristicMap.toString().c_str());
|
|
||||||
|
std::string res;
|
||||||
|
int count = 0;
|
||||||
|
char hex[5];
|
||||||
|
for (auto &it: m_chrVec) {
|
||||||
|
if (count > 0) {res += "\n";}
|
||||||
|
snprintf(hex, sizeof(hex), "%04x", it->getHandle());
|
||||||
|
count++;
|
||||||
|
res += "handle: 0x";
|
||||||
|
res += hex;
|
||||||
|
res += ", uuid: " + std::string(it->getUUID());
|
||||||
|
}
|
||||||
|
NIMBLE_LOGD(LOG_TAG, "Characteristics:\n%s", res.c_str());
|
||||||
} // dump
|
} // dump
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,10 +90,9 @@ NimBLEUUID NimBLEService::getUUID() {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Start the service.
|
* @brief Builds the database of characteristics/descriptors for the service
|
||||||
* Here we wish to start the service which means that we will respond to partner requests about it.
|
* and registers it with the NimBLE stack.
|
||||||
* Starting a service also means that we can create the corresponding characteristics.
|
* @return bool success/failure .
|
||||||
* @return Start the service.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool NimBLEService::start() {
|
bool NimBLEService::start() {
|
||||||
|
@ -96,7 +109,7 @@ bool NimBLEService::start() {
|
||||||
svc[0].uuid = &m_uuid.getNative()->u;
|
svc[0].uuid = &m_uuid.getNative()->u;
|
||||||
svc[0].includes = NULL;
|
svc[0].includes = NULL;
|
||||||
|
|
||||||
uint8_t numChrs = m_characteristicMap.getSize();
|
size_t numChrs = m_chrVec.size();
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG,"Adding %d characteristics for service %s", numChrs, toString().c_str());
|
NIMBLE_LOGD(LOG_TAG,"Adding %d characteristics for service %s", numChrs, toString().c_str());
|
||||||
|
|
||||||
|
@ -107,16 +120,17 @@ bool NimBLEService::start() {
|
||||||
// of the characteristics for the service. We create 1 extra and set it to null
|
// of the characteristics for the service. We create 1 extra and set it to null
|
||||||
// for this purpose.
|
// for this purpose.
|
||||||
pChr_a = new ble_gatt_chr_def[numChrs+1];
|
pChr_a = new ble_gatt_chr_def[numChrs+1];
|
||||||
NimBLECharacteristic* pCharacteristic = m_characteristicMap.getFirst();
|
NimBLECharacteristic* pCharacteristic = *m_chrVec.begin();
|
||||||
|
|
||||||
for(uint8_t i=0; i < numChrs; i++) {
|
for(uint8_t i=0; i < numChrs;) {
|
||||||
uint8_t numDscs = pCharacteristic->m_descriptorMap.getSize();
|
uint8_t numDscs = pCharacteristic->m_dscVec.size();
|
||||||
if(numDscs) {
|
if(numDscs) {
|
||||||
// skip 2902 as it's automatically created by NimBLE
|
// skip 2902 as it's automatically created by NimBLE
|
||||||
// if Indicate or Notify flags are set
|
// if Indicate or Notify flags are set
|
||||||
if(((pCharacteristic->m_properties & BLE_GATT_CHR_F_INDICATE) ||
|
if(((pCharacteristic->m_properties & BLE_GATT_CHR_F_INDICATE) ||
|
||||||
(pCharacteristic->m_properties & BLE_GATT_CHR_F_NOTIFY)) &&
|
(pCharacteristic->m_properties & BLE_GATT_CHR_F_NOTIFY)) &&
|
||||||
pCharacteristic->getDescriptorByUUID("2902") != nullptr) {
|
pCharacteristic->getDescriptorByUUID("2902") != nullptr)
|
||||||
|
{
|
||||||
numDscs--;
|
numDscs--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,12 +141,12 @@ bool NimBLEService::start() {
|
||||||
// Must have last descriptor uuid = 0 so we have to create 1 extra
|
// Must have last descriptor uuid = 0 so we have to create 1 extra
|
||||||
//NIMBLE_LOGD(LOG_TAG, "Adding %d descriptors", numDscs);
|
//NIMBLE_LOGD(LOG_TAG, "Adding %d descriptors", numDscs);
|
||||||
pDsc_a = new ble_gatt_dsc_def[numDscs+1];
|
pDsc_a = new ble_gatt_dsc_def[numDscs+1];
|
||||||
NimBLEDescriptor* pDescriptor = pCharacteristic->m_descriptorMap.getFirst();
|
NimBLEDescriptor* pDescriptor = *pCharacteristic->m_dscVec.begin();
|
||||||
for(uint8_t d=0; d < numDscs;) {
|
for(uint8_t d=0; d < numDscs;) {
|
||||||
// skip 2902
|
// skip 2902
|
||||||
if(pDescriptor->m_uuid.equals(NimBLEUUID((uint16_t)0x2902))) {
|
if(pDescriptor->m_uuid == NimBLEUUID(uint16_t(0x2902))) {
|
||||||
//NIMBLE_LOGD(LOG_TAG, "Skipped 0x2902");
|
//NIMBLE_LOGD(LOG_TAG, "Skipped 0x2902");
|
||||||
pDescriptor = pCharacteristic->m_descriptorMap.getNext();
|
pDescriptor = *(pCharacteristic->m_dscVec.begin()+d+1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
pDsc_a[d].uuid = &pDescriptor->m_uuid.getNative()->u;
|
pDsc_a[d].uuid = &pDescriptor->m_uuid.getNative()->u;
|
||||||
|
@ -140,8 +154,8 @@ bool NimBLEService::start() {
|
||||||
pDsc_a[d].min_key_size = 0;
|
pDsc_a[d].min_key_size = 0;
|
||||||
pDsc_a[d].access_cb = NimBLEDescriptor::handleGapEvent;
|
pDsc_a[d].access_cb = NimBLEDescriptor::handleGapEvent;
|
||||||
pDsc_a[d].arg = pDescriptor;
|
pDsc_a[d].arg = pDescriptor;
|
||||||
pDescriptor = pCharacteristic->m_descriptorMap.getNext();
|
|
||||||
d++;
|
d++;
|
||||||
|
pDescriptor = *(pCharacteristic->m_dscVec.begin() + d);
|
||||||
}
|
}
|
||||||
|
|
||||||
pDsc_a[numDscs].uuid = NULL;
|
pDsc_a[numDscs].uuid = NULL;
|
||||||
|
@ -154,7 +168,8 @@ bool NimBLEService::start() {
|
||||||
pChr_a[i].flags = pCharacteristic->m_properties;
|
pChr_a[i].flags = pCharacteristic->m_properties;
|
||||||
pChr_a[i].min_key_size = 0;
|
pChr_a[i].min_key_size = 0;
|
||||||
pChr_a[i].val_handle = &pCharacteristic->m_handle;
|
pChr_a[i].val_handle = &pCharacteristic->m_handle;
|
||||||
pCharacteristic = m_characteristicMap.getNext();
|
i++;
|
||||||
|
pCharacteristic = *(m_chrVec.begin() + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
pChr_a[numChrs].uuid = NULL;
|
pChr_a[numChrs].uuid = NULL;
|
||||||
|
@ -182,21 +197,6 @@ bool NimBLEService::start() {
|
||||||
} // start
|
} // start
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the handle associated with this service.
|
|
||||||
* @param [in] handle The handle associated with the service.
|
|
||||||
*/
|
|
||||||
void NimBLEService::setHandle(uint16_t handle) {
|
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> setHandle - Handle=0x%.2x, service UUID=%s)", handle, getUUID().toString().c_str());
|
|
||||||
if (m_handle != NULL_HANDLE) {
|
|
||||||
NIMBLE_LOGE(LOG_TAG, "!!! Handle is already set %.2x", m_handle);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_handle = handle;
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< setHandle");
|
|
||||||
} // setHandle
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the handle associated with this service.
|
* @brief Get the handle associated with this service.
|
||||||
* @return The handle associated with this service.
|
* @return The handle associated with this service.
|
||||||
|
@ -206,34 +206,6 @@ uint16_t NimBLEService::getHandle() {
|
||||||
} // getHandle
|
} // getHandle
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Add a characteristic to the service.
|
|
||||||
* @param [in] pCharacteristic A pointer to the characteristic to be added.
|
|
||||||
*/
|
|
||||||
void NimBLEService::addCharacteristic(NimBLECharacteristic* pCharacteristic) {
|
|
||||||
// We maintain a mapping of characteristics owned by this service. These are managed by the
|
|
||||||
// BLECharacteristicMap class instance found in m_characteristicMap. We add the characteristic
|
|
||||||
// to the map and then ask the service to add the characteristic at the BLE level (ESP-IDF).
|
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> addCharacteristic()");
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "Adding characteristic: uuid=%s to service: %s",
|
|
||||||
pCharacteristic->getUUID().toString().c_str(),
|
|
||||||
toString().c_str());
|
|
||||||
|
|
||||||
// Check that we don't add the same characteristic twice.
|
|
||||||
if (m_characteristicMap.getByUUID(pCharacteristic->getUUID()) != nullptr) {
|
|
||||||
NIMBLE_LOGW(LOG_TAG, "<< Adding a new characteristic with the same UUID as a previous one");
|
|
||||||
//return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remember this characteristic in our map of characteristics. At this point, we can lookup by UUID
|
|
||||||
// but not by handle. The handle is allocated to us on the ESP_GATTS_ADD_CHAR_EVT.
|
|
||||||
m_characteristicMap.setByUUID(pCharacteristic, pCharacteristic->getUUID());
|
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< addCharacteristic()");
|
|
||||||
} // addCharacteristic
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a new BLE Characteristic associated with this service.
|
* @brief Create a new BLE Characteristic associated with this service.
|
||||||
* @param [in] uuid - The UUID of the characteristic.
|
* @param [in] uuid - The UUID of the characteristic.
|
||||||
|
@ -253,8 +225,15 @@ NimBLECharacteristic* NimBLEService::createCharacteristic(const char* uuid, uint
|
||||||
*/
|
*/
|
||||||
NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid, uint32_t properties) {
|
NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid, uint32_t properties) {
|
||||||
NimBLECharacteristic* pCharacteristic = new NimBLECharacteristic(uuid, properties, this);
|
NimBLECharacteristic* pCharacteristic = new NimBLECharacteristic(uuid, properties, this);
|
||||||
addCharacteristic(pCharacteristic);
|
// Check that we don't add the same characteristic twice.
|
||||||
//pCharacteristic->executeCreate(this);
|
if (getCharacteristic(uuid) != nullptr) {
|
||||||
|
NIMBLE_LOGW(LOG_TAG, "<< Adding a duplicate characteristic with UUID: %s",
|
||||||
|
std::string(uuid).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remember this characteristic in our vector of characteristics.
|
||||||
|
m_chrVec.push_back(pCharacteristic);
|
||||||
|
|
||||||
return pCharacteristic;
|
return pCharacteristic;
|
||||||
} // createCharacteristic
|
} // createCharacteristic
|
||||||
|
|
||||||
|
@ -265,7 +244,13 @@ NimBLECharacteristic* NimBLEService::getCharacteristic(const char* uuid) {
|
||||||
|
|
||||||
|
|
||||||
NimBLECharacteristic* NimBLEService::getCharacteristic(const NimBLEUUID &uuid) {
|
NimBLECharacteristic* NimBLEService::getCharacteristic(const NimBLEUUID &uuid) {
|
||||||
return m_characteristicMap.getByUUID(uuid);
|
for (auto &it : m_chrVec) {
|
||||||
|
if (it->getUUID() == uuid) {
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,37 +20,14 @@
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
|
||||||
#include "NimBLECharacteristic.h"
|
|
||||||
#include "NimBLEServer.h"
|
#include "NimBLEServer.h"
|
||||||
|
#include "NimBLECharacteristic.h"
|
||||||
#include "NimBLEUUID.h"
|
#include "NimBLEUUID.h"
|
||||||
#include "FreeRTOS.h"
|
|
||||||
|
|
||||||
|
|
||||||
class NimBLEServer;
|
class NimBLEServer;
|
||||||
class NimBLECharacteristic;
|
class NimBLECharacteristic;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A data mapping used to manage the set of %BLE characteristics known to the server.
|
|
||||||
*/
|
|
||||||
class NimBLECharacteristicMap {
|
|
||||||
public:
|
|
||||||
void setByUUID(NimBLECharacteristic* pCharacteristic, const char* uuid);
|
|
||||||
void setByUUID(NimBLECharacteristic* pCharacteristic, const NimBLEUUID &uuid);
|
|
||||||
void setByHandle(uint16_t handle, NimBLECharacteristic* pCharacteristic);
|
|
||||||
NimBLECharacteristic* getByUUID(const char* uuid);
|
|
||||||
NimBLECharacteristic* getByUUID(const NimBLEUUID &uuid);
|
|
||||||
NimBLECharacteristic* getByHandle(uint16_t handle);
|
|
||||||
NimBLECharacteristic* getFirst();
|
|
||||||
NimBLECharacteristic* getNext();
|
|
||||||
uint8_t getSize();
|
|
||||||
std::string toString();
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::map<NimBLECharacteristic*, std::string> m_uuidMap;
|
|
||||||
std::map<uint16_t, NimBLECharacteristic*> m_handleMap;
|
|
||||||
std::map<NimBLECharacteristic*, std::string>::iterator m_iterator;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The model of a %BLE service.
|
* @brief The model of a %BLE service.
|
||||||
|
@ -59,11 +36,13 @@ private:
|
||||||
class NimBLEService {
|
class NimBLEService {
|
||||||
public:
|
public:
|
||||||
NimBLECharacteristic* createCharacteristic(const char* uuid,
|
NimBLECharacteristic* createCharacteristic(const char* uuid,
|
||||||
uint32_t properties = NIMBLE_PROPERTY::READ |
|
uint32_t properties =
|
||||||
|
NIMBLE_PROPERTY::READ |
|
||||||
NIMBLE_PROPERTY::WRITE);
|
NIMBLE_PROPERTY::WRITE);
|
||||||
|
|
||||||
NimBLECharacteristic* createCharacteristic(const NimBLEUUID &uuid,
|
NimBLECharacteristic* createCharacteristic(const NimBLEUUID &uuid,
|
||||||
uint32_t properties = NIMBLE_PROPERTY::READ |
|
uint32_t properties =
|
||||||
|
NIMBLE_PROPERTY::READ |
|
||||||
NIMBLE_PROPERTY::WRITE);
|
NIMBLE_PROPERTY::WRITE);
|
||||||
|
|
||||||
void dump();
|
void dump();
|
||||||
|
@ -72,27 +51,24 @@ public:
|
||||||
NimBLEUUID getUUID();
|
NimBLEUUID getUUID();
|
||||||
NimBLEServer* getServer();
|
NimBLEServer* getServer();
|
||||||
bool start();
|
bool start();
|
||||||
// void stop();
|
|
||||||
std::string toString();
|
std::string toString();
|
||||||
uint16_t getHandle();
|
uint16_t getHandle();
|
||||||
uint8_t m_instId = 0;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer);
|
NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer);
|
||||||
NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLEServer* pServer);
|
NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLEServer* pServer);
|
||||||
|
|
||||||
friend class NimBLEServer;
|
friend class NimBLEServer;
|
||||||
friend class NimBLEDevice;
|
friend class NimBLEDevice;
|
||||||
|
|
||||||
void addCharacteristic(NimBLECharacteristic* pCharacteristic);
|
|
||||||
|
|
||||||
NimBLECharacteristicMap m_characteristicMap;
|
|
||||||
uint16_t m_handle;
|
uint16_t m_handle;
|
||||||
NimBLEServer* m_pServer = nullptr;
|
NimBLEServer* m_pServer;
|
||||||
NimBLEUUID m_uuid;
|
NimBLEUUID m_uuid;
|
||||||
|
|
||||||
uint16_t m_numHandles;
|
uint16_t m_numHandles;
|
||||||
void setHandle(uint16_t handle);
|
|
||||||
}; // BLEService
|
std::vector<NimBLECharacteristic*> m_chrVec;
|
||||||
|
|
||||||
|
}; // NimBLEService
|
||||||
|
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
|
|
@ -1,145 +0,0 @@
|
||||||
/*
|
|
||||||
* NimBLEService.cpp
|
|
||||||
*
|
|
||||||
* Created: on March 7, 2020
|
|
||||||
* Author H2zero
|
|
||||||
*
|
|
||||||
* Originally:
|
|
||||||
*
|
|
||||||
* BLEServiceMap.cpp
|
|
||||||
*
|
|
||||||
* Created on: Jun 22, 2017
|
|
||||||
* Author: kolban
|
|
||||||
*/
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
|
|
||||||
#include "NimBLEService.h"
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the service by UUID.
|
|
||||||
* @param [in] UUID The UUID to look up the service.
|
|
||||||
* @return The characteristic.
|
|
||||||
*/
|
|
||||||
NimBLEService* NimBLEServiceMap::getByUUID(const char* uuid) {
|
|
||||||
return getByUUID(NimBLEUUID(uuid));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the service by UUID.
|
|
||||||
* @param [in] UUID The UUID to look up the service.
|
|
||||||
* @return The characteristic.
|
|
||||||
*/
|
|
||||||
NimBLEService* NimBLEServiceMap::getByUUID(const NimBLEUUID &uuid, uint8_t inst_id) {
|
|
||||||
for (auto &myPair : m_uuidMap) {
|
|
||||||
if (myPair.first->getUUID().equals(uuid)) {
|
|
||||||
return myPair.first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//return m_uuidMap.at(uuid.toString());
|
|
||||||
return nullptr;
|
|
||||||
} // getByUUID
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the service by handle.
|
|
||||||
* @param [in] handle The handle to look up the service.
|
|
||||||
* @return The service.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
NimBLEService* NimBLEServiceMap::getByHandle(uint16_t handle) {
|
|
||||||
return m_handleMap.at(handle);
|
|
||||||
} // getByHandle
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the service by UUID.
|
|
||||||
* @param [in] uuid The uuid of the service.
|
|
||||||
* @param [in] characteristic The service to cache.
|
|
||||||
* @return N/A.
|
|
||||||
*/
|
|
||||||
void NimBLEServiceMap::setByUUID(const NimBLEUUID &uuid, NimBLEService* service) {
|
|
||||||
m_uuidMap.insert(std::pair<NimBLEService*, std::string>(service, uuid.toString()));
|
|
||||||
} // setByUUID
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the service by handle.
|
|
||||||
* @param [in] handle The handle of the service.
|
|
||||||
* @param [in] service The service to cache.
|
|
||||||
* @return N/A.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
void NimBLEServiceMap::setByHandle(uint16_t handle, NimBLEService* service) {
|
|
||||||
m_handleMap.insert(std::pair<uint16_t, NimBLEService*>(handle, service));
|
|
||||||
} // setByHandle
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return a string representation of the service map.
|
|
||||||
* @return A string representation of the service map.
|
|
||||||
*/
|
|
||||||
std::string NimBLEServiceMap::toString() {
|
|
||||||
std::string res;
|
|
||||||
//char hex[5];
|
|
||||||
for (auto &myPair: m_uuidMap) {
|
|
||||||
// res += "handle: 0x";
|
|
||||||
// snprintf(hex, sizeof(hex), "%04x", myPair.first);
|
|
||||||
// res += hex;
|
|
||||||
res += ", uuid: " + myPair.second + "\n";
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
} // toString
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the first service in the map.
|
|
||||||
* @return The first service in the map.
|
|
||||||
*/
|
|
||||||
NimBLEService* NimBLEServiceMap::getFirst() {
|
|
||||||
m_iterator = m_uuidMap.begin();
|
|
||||||
if (m_iterator == m_uuidMap.end()) return nullptr;
|
|
||||||
NimBLEService* pRet = m_iterator->first;
|
|
||||||
m_iterator++;
|
|
||||||
return pRet;
|
|
||||||
} // getFirst
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the next service in the map.
|
|
||||||
* @return The next service in the map.
|
|
||||||
*/
|
|
||||||
NimBLEService* NimBLEServiceMap::getNext() {
|
|
||||||
if (m_iterator == m_uuidMap.end()) return nullptr;
|
|
||||||
NimBLEService* pRet = m_iterator->first;
|
|
||||||
m_iterator++;
|
|
||||||
return pRet;
|
|
||||||
} // getNext
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Removes service from maps.
|
|
||||||
* @return N/A.
|
|
||||||
*/
|
|
||||||
void NimBLEServiceMap::removeService(NimBLEService* service) {
|
|
||||||
//m_handleMap.erase(service->getHandle());
|
|
||||||
m_uuidMap.erase(service);
|
|
||||||
} // removeService
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the amount of registered services
|
|
||||||
* @return amount of registered services
|
|
||||||
*/
|
|
||||||
int NimBLEServiceMap::getRegisteredServiceCount(){
|
|
||||||
//return m_handleMap.size();
|
|
||||||
return m_uuidMap.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
|
@ -502,10 +502,15 @@ void print_bytes(const uint8_t *bytes, int len)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
MODLOG_DFLT(DEBUG, "%s0x%02x", i != 0 ? ":" : "", bytes[i]);
|
MODLOG_DFLT(ERROR, "%s0x%02x", i != 0 ? ":" : "", bytes[i]);
|
||||||
|
if(i % 30 == 0){
|
||||||
|
MODLOG_DFLT(ERROR, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MODLOG_DFLT(ERROR, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
void print_mbuf(const struct os_mbuf *om)
|
void print_mbuf(const struct os_mbuf *om)
|
||||||
{
|
{
|
||||||
int colon;
|
int colon;
|
||||||
|
|
|
@ -13,6 +13,20 @@
|
||||||
|
|
||||||
#include "host/ble_gap.h"
|
#include "host/ble_gap.h"
|
||||||
|
|
||||||
|
/**** FIX COMPILATION ****/
|
||||||
|
#undef min
|
||||||
|
#undef max
|
||||||
|
/**************************/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void *pATT;
|
||||||
|
TaskHandle_t task;
|
||||||
|
int rc;
|
||||||
|
std::string *buf;
|
||||||
|
} ble_task_data_t;
|
||||||
|
|
||||||
extern "C"{
|
extern "C"{
|
||||||
char *addr_str(const void *addr);
|
char *addr_str(const void *addr);
|
||||||
void print_conn_desc(const struct ble_gap_conn_desc *desc);
|
void print_conn_desc(const struct ble_gap_conn_desc *desc);
|
||||||
|
|
|
@ -1,143 +0,0 @@
|
||||||
/*
|
|
||||||
* NimNimBLEValue.cpp
|
|
||||||
*
|
|
||||||
* Created: on March 6, 2020
|
|
||||||
* Author H2zero
|
|
||||||
*
|
|
||||||
* Originally:
|
|
||||||
*
|
|
||||||
* BLEValue.cpp
|
|
||||||
*
|
|
||||||
* Created on: Jul 17, 2017
|
|
||||||
* Author: kolban
|
|
||||||
*/
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
|
|
||||||
#include "NimBLEValue.h"
|
|
||||||
#include "NimBLELog.h"
|
|
||||||
|
|
||||||
static const char* LOG_TAG="NimBLEValue";
|
|
||||||
|
|
||||||
NimBLEValue::NimBLEValue() {
|
|
||||||
m_accumulation = "";
|
|
||||||
m_value = "";
|
|
||||||
m_readOffset = 0;
|
|
||||||
} // NimBLEValue
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Add a message part to the accumulation.
|
|
||||||
* The accumulation is a growing set of data that is added to until a commit or cancel.
|
|
||||||
* @param [in] part A message part being added.
|
|
||||||
*/
|
|
||||||
void NimBLEValue::addPart(const std::string &part) {
|
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> addPart: length=%d", part.length());
|
|
||||||
m_accumulation += part;
|
|
||||||
} // addPart
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Add a message part to the accumulation.
|
|
||||||
* The accumulation is a growing set of data that is added to until a commit or cancel.
|
|
||||||
* @param [in] pData A message part being added.
|
|
||||||
* @param [in] length The number of bytes being added.
|
|
||||||
*/
|
|
||||||
void NimBLEValue::addPart(const uint8_t* pData, size_t length) {
|
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> addPart: length=%d", length);
|
|
||||||
m_accumulation += std::string((char*) pData, length);
|
|
||||||
} // addPart
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Cancel the current accumulation.
|
|
||||||
*/
|
|
||||||
void NimBLEValue::cancel() {
|
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> cancel");
|
|
||||||
m_accumulation = "";
|
|
||||||
m_readOffset = 0;
|
|
||||||
} // cancel
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Commit the current accumulation.
|
|
||||||
* When writing a value, we may find that we write it in "parts" meaning that the writes come in in pieces
|
|
||||||
* of the overall message. After the last part has been received, we may perform a commit which means that
|
|
||||||
* we now have the complete message and commit the change as a unit.
|
|
||||||
*/
|
|
||||||
void NimBLEValue::commit() {
|
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> commit");
|
|
||||||
// If there is nothing to commit, do nothing.
|
|
||||||
if (m_accumulation.length() == 0) return;
|
|
||||||
setValue(m_accumulation);
|
|
||||||
m_accumulation = "";
|
|
||||||
m_readOffset = 0;
|
|
||||||
} // commit
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get a pointer to the data.
|
|
||||||
* @return A pointer to the data.
|
|
||||||
*/
|
|
||||||
uint8_t* NimBLEValue::getData() {
|
|
||||||
return (uint8_t*) m_value.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the length of the data in bytes.
|
|
||||||
* @return The length of the data in bytes.
|
|
||||||
*/
|
|
||||||
size_t NimBLEValue::getLength() {
|
|
||||||
return m_value.length();
|
|
||||||
} // getLength
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the read offset.
|
|
||||||
* @return The read offset into the read.
|
|
||||||
*/
|
|
||||||
uint16_t NimBLEValue::getReadOffset() {
|
|
||||||
return m_readOffset;
|
|
||||||
} // getReadOffset
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the current value.
|
|
||||||
*/
|
|
||||||
std::string NimBLEValue::getValue() {
|
|
||||||
return m_value;
|
|
||||||
} // getValue
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the read offset
|
|
||||||
* @param [in] readOffset The offset into the read.
|
|
||||||
*/
|
|
||||||
void NimBLEValue::setReadOffset(uint16_t readOffset) {
|
|
||||||
m_readOffset = readOffset;
|
|
||||||
} // setReadOffset
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the current value.
|
|
||||||
*/
|
|
||||||
void NimBLEValue::setValue(const std::string &value) {
|
|
||||||
m_value = value;
|
|
||||||
} // setValue
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the current value.
|
|
||||||
* @param [in] pData The data for the current value.
|
|
||||||
* @param [in] The length of the new current value.
|
|
||||||
*/
|
|
||||||
void NimBLEValue::setValue(const uint8_t* pData, size_t length) {
|
|
||||||
m_value = std::string((char*) pData, length);
|
|
||||||
} // setValue
|
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
#endif // CONFIG_BT_ENABLED
|
|
|
@ -1,52 +0,0 @@
|
||||||
/*
|
|
||||||
* NimBLEValue.h
|
|
||||||
*
|
|
||||||
* Created: on March 6, 2020
|
|
||||||
* Author H2zero
|
|
||||||
*
|
|
||||||
* Originally:
|
|
||||||
*
|
|
||||||
* BLEValue.h
|
|
||||||
*
|
|
||||||
* Created on: Jul 17, 2017
|
|
||||||
* Author: kolban
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MAIN_BLEVALUE_H_
|
|
||||||
#define MAIN_BLEVALUE_H_
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The model of a %BLE value.
|
|
||||||
*/
|
|
||||||
class NimBLEValue {
|
|
||||||
public:
|
|
||||||
NimBLEValue();
|
|
||||||
void addPart(const std::string &part);
|
|
||||||
void addPart(const uint8_t* pData, size_t length);
|
|
||||||
void cancel();
|
|
||||||
void commit();
|
|
||||||
uint8_t* getData();
|
|
||||||
size_t getLength();
|
|
||||||
uint16_t getReadOffset();
|
|
||||||
std::string getValue();
|
|
||||||
void setReadOffset(uint16_t readOffset);
|
|
||||||
void setValue(const std::string &value);
|
|
||||||
void setValue(const uint8_t* pData, size_t length);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string m_accumulation;
|
|
||||||
uint16_t m_readOffset;
|
|
||||||
std::string m_value;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
#endif // CONFIG_BT_ENABLED
|
|
||||||
#endif /* MAIN_BLEVALUE_H_ */
|
|
|
@ -19,6 +19,9 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef H_BLE_HS_PVCY_
|
||||||
|
#define H_BLE_HS_PVCY_
|
||||||
|
|
||||||
#include "host/ble_hs.h"
|
#include "host/ble_hs.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -26,15 +29,45 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
||||||
/* Called to configure local(own) privacy (RPA) when using host based privacy. In
|
|
||||||
* Host based privacy as controller is not aware of RPA, we do it via
|
#define NIMBLE_HOST_DISABLE_PRIVACY 0x00
|
||||||
* 'BLE_ADDR_RANDOM' addr_type route.
|
#define NIMBLE_HOST_ENABLE_RPA 0x01
|
||||||
|
#define NIMBLE_HOST_ENABLE_NRPA 0x02
|
||||||
|
|
||||||
|
/* Called to configure local(own) privacy (RPA/NRPA) when using Host based privacy.
|
||||||
|
* In Host based privacy, as controller is not aware of RPA/NRPA address is in use,
|
||||||
|
* we do it through 'BLE_ADDR_RANDOM (0x01)' addr_type route. This is necessary
|
||||||
|
* so as to set the private address as random address in controller.
|
||||||
|
* Remember to configure `BLE_SM_PAIR_KEY_DIST_ID` in our & their
|
||||||
|
* key distributions for using RPA. For NRPA part of privacy it is not
|
||||||
|
* necessary to configure key distributions in host, as anyway NRPA is non-resolvable.
|
||||||
|
* Please call this API once host-controller are synced as we set the private
|
||||||
|
* (RPA/NRPA) address using host-controller HCI commands.
|
||||||
*
|
*
|
||||||
* @param enable RPA when enable is not 0
|
* To give brief information on how to use this feature,
|
||||||
* disable RPA otherwise
|
* please refer to following steps while using RPA feature:
|
||||||
|
*
|
||||||
|
* 1. Include "host/ble_hs_pvcy.h".
|
||||||
|
* 2. Set own_addr_type to `BLE_OWN_ADDR_RANDOM`.
|
||||||
|
* 3. Add `BLE_SM_PAIR_KEY_DIST_ID` to key distribution in
|
||||||
|
* `ble_hs_cfg.sm_our_key_dist` & `ble_hs_cfg.sm_their_key_dist`.
|
||||||
|
* 4. Call `ble_hs_pvcy_rpa_config(1)` in Host-Controller sync callback.
|
||||||
|
*
|
||||||
|
* In case of NRPA, steps 1, 2 and calling ble_hs_pvcy_rpa_config(2) will
|
||||||
|
* suffice.
|
||||||
|
*
|
||||||
|
* @param enable RPA when param = 1 (NIMBLE_HOST_ENABLE_RPA)
|
||||||
|
* enable NRPA when param = 2 (NIMBLE_HOST_ENABLE_NRPA)
|
||||||
|
* disable privacy when param = 0 (NIMBLE_HOST_DISABLE_PRIVACY)
|
||||||
*
|
*
|
||||||
* @return return 0 when successful.
|
* @return return 0 when successful.
|
||||||
* return appropriate error code otherwise
|
* return appropriate error code otherwise
|
||||||
*/
|
*/
|
||||||
int ble_hs_pvcy_rpa_config(uint8_t enable);
|
int ble_hs_pvcy_rpa_config(uint8_t enable);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -332,6 +332,8 @@ static inline void net_buf_simple_restore(struct os_mbuf *buf,
|
||||||
|
|
||||||
static inline void sys_memcpy_swap(void *dst, const void *src, size_t length)
|
static inline void sys_memcpy_swap(void *dst, const void *src, size_t length)
|
||||||
{
|
{
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wpointer-arith"
|
||||||
__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");
|
||||||
|
@ -341,6 +343,7 @@ static inline void sys_memcpy_swap(void *dst, const void *src, size_t length)
|
||||||
for (; length > 0; length--) {
|
for (; length > 0; length--) {
|
||||||
*((u8_t *)dst++) = *((u8_t *)src--);
|
*((u8_t *)dst++) = *((u8_t *)src--);
|
||||||
}
|
}
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
}
|
}
|
||||||
|
|
||||||
#define popcount(x) __builtin_popcount(x)
|
#define popcount(x) __builtin_popcount(x)
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
pkg.name: nimble/host/mesh
|
|
||||||
pkg.description: Bluetooth Mesh
|
|
||||||
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
|
||||||
pkg.homepage: "http://mynewt.apache.org/"
|
|
||||||
pkg.keywords:
|
|
||||||
- ble
|
|
||||||
- bluetooth
|
|
||||||
- mesh
|
|
||||||
|
|
||||||
pkg.deps:
|
|
||||||
- "@apache-mynewt-core/kernel/os"
|
|
||||||
- "@apache-mynewt-core/util/mem"
|
|
||||||
- "@apache-mynewt-core/crypto/tinycrypt"
|
|
||||||
- nimble
|
|
||||||
- nimble/host
|
|
||||||
|
|
||||||
pkg.deps.BLE_MESH_SHELL:
|
|
||||||
- "@apache-mynewt-core/sys/shell"
|
|
||||||
|
|
||||||
pkg.deps.BLE_MESH_SETTINGS:
|
|
||||||
- "@apache-mynewt-core/encoding/base64"
|
|
||||||
- "@apache-mynewt-core/sys/config"
|
|
||||||
|
|
||||||
pkg.req_apis:
|
|
||||||
- log
|
|
||||||
- stats
|
|
||||||
|
|
||||||
pkg.init:
|
|
||||||
bt_mesh_register_gatt: 'MYNEWT_VAL(BLE_MESH_SYSINIT_STAGE)'
|
|
||||||
ble_mesh_shell_init: 'MYNEWT_VAL(BLE_MESH_SYSINIT_STAGE_SHELL)'
|
|
|
@ -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,
|
||||||
|
|
|
@ -36,6 +36,7 @@ void ble_hs_id_rnd_reset(void);
|
||||||
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
||||||
bool ble_hs_is_rpa(uint8_t *addr, uint8_t addr_type);
|
bool ble_hs_is_rpa(uint8_t *addr, uint8_t addr_type);
|
||||||
int ble_hs_id_set_pseudo_rnd(const uint8_t *);
|
int ble_hs_id_set_pseudo_rnd(const uint8_t *);
|
||||||
|
int ble_hs_id_set_nrpa_rnd(void);
|
||||||
#endif
|
#endif
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -61,7 +61,7 @@ struct ble_hs_dev_records {
|
||||||
|
|
||||||
/* Add a device to the resolving list */
|
/* Add a device to the resolving list */
|
||||||
int ble_hs_resolv_list_add(uint8_t *cmdbuf);
|
int ble_hs_resolv_list_add(uint8_t *cmdbuf);
|
||||||
int ble_hs_gen_own_rpa_random(void);
|
int ble_hs_gen_own_private_rnd(void);
|
||||||
uint8_t *ble_hs_get_rpa_local(void);
|
uint8_t *ble_hs_get_rpa_local(void);
|
||||||
|
|
||||||
/* Remove a device from the resolving list */
|
/* Remove a device from the resolving list */
|
||||||
|
@ -71,6 +71,8 @@ void ble_hs_resolv_list_clear_all(void);
|
||||||
|
|
||||||
/* Address resolution enable command */
|
/* Address resolution enable command */
|
||||||
void ble_hs_resolv_enable(bool);
|
void ble_hs_resolv_enable(bool);
|
||||||
|
void ble_hs_resolv_nrpa_enable(void);
|
||||||
|
void ble_hs_resolv_nrpa_disable(void);
|
||||||
|
|
||||||
/* Finds 'addr' in resolving list. Doesnt check if address resolution enabled */
|
/* Finds 'addr' in resolving list. Doesnt check if address resolution enabled */
|
||||||
struct ble_hs_resolv_entry *
|
struct ble_hs_resolv_entry *
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,540 +0,0 @@
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
syscfg.defs:
|
|
||||||
BLE_MESH_PROV:
|
|
||||||
description: >
|
|
||||||
Enable provisioning. It is automatically enabled whenever
|
|
||||||
BLE_MESH_PB_ADV or BLE_MESH_PB_GATT is set.
|
|
||||||
value: 1
|
|
||||||
|
|
||||||
BLE_MESH_PB_ADV:
|
|
||||||
description: >
|
|
||||||
Enable this option to allow the device to be provisioned over
|
|
||||||
the advertising bearer.
|
|
||||||
value: 1
|
|
||||||
|
|
||||||
BLE_MESH_PROXY:
|
|
||||||
description: >
|
|
||||||
Enable proxy. This is automatically set whenever BLE_MESH_PB_GATT or
|
|
||||||
BLE_MESH_GATT_PROXY is set.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_PB_GATT:
|
|
||||||
description: >
|
|
||||||
Enable this option to allow the device to be provisioned over
|
|
||||||
the GATT bearer.
|
|
||||||
value: 1
|
|
||||||
|
|
||||||
BLE_MESH_GATT_PROXY:
|
|
||||||
description: >
|
|
||||||
This option enables support for the Mesh GATT Proxy Service,
|
|
||||||
i.e. the ability to act as a proxy between a Mesh GATT Client
|
|
||||||
and a Mesh network.
|
|
||||||
value: 1
|
|
||||||
|
|
||||||
BLE_MESH_NODE_ID_TIMEOUT:
|
|
||||||
description: >
|
|
||||||
This option determines for how long the local node advertises
|
|
||||||
using Node Identity. The given value is in seconds. The
|
|
||||||
specification limits this to 60 seconds, and implies that to
|
|
||||||
be the appropriate value as well, so just leaving this as the
|
|
||||||
default is the safest option.
|
|
||||||
value: 60
|
|
||||||
|
|
||||||
BLE_MESH_PROXY_FILTER_SIZE:
|
|
||||||
descryption: >
|
|
||||||
This option specifies how many Proxy Filter entries the local
|
|
||||||
node supports.
|
|
||||||
value: 1
|
|
||||||
|
|
||||||
BLE_MESH_SUBNET_COUNT:
|
|
||||||
description: >
|
|
||||||
This option specifies how many subnets a Mesh network can
|
|
||||||
participate in at the same time.
|
|
||||||
value: 1
|
|
||||||
|
|
||||||
BLE_MESH_APP_KEY_COUNT:
|
|
||||||
description: >
|
|
||||||
This option specifies how many application keys the device can
|
|
||||||
store per network.
|
|
||||||
value: 1
|
|
||||||
|
|
||||||
BLE_MESH_MODEL_KEY_COUNT:
|
|
||||||
description: >
|
|
||||||
This option specifies how many application keys each model can
|
|
||||||
at most be bound to.
|
|
||||||
value: 1
|
|
||||||
|
|
||||||
BLE_MESH_MODEL_GROUP_COUNT:
|
|
||||||
description: >
|
|
||||||
This option specifies how many group addresses each model can
|
|
||||||
at most be subscribed to.
|
|
||||||
value: 1
|
|
||||||
|
|
||||||
BLE_MESH_LABEL_COUNT:
|
|
||||||
description: >
|
|
||||||
This option specifies how many Label UUIDs can be stored.
|
|
||||||
value: 1
|
|
||||||
|
|
||||||
BLE_MESH_CRPL:
|
|
||||||
description: >
|
|
||||||
This options specifies the maximum capacity of the replay
|
|
||||||
protection list. This option is similar to the network message
|
|
||||||
cache size, but has a different purpose.
|
|
||||||
value: 10
|
|
||||||
|
|
||||||
BLE_MESH_ADV_TASK_PRIO:
|
|
||||||
description: >
|
|
||||||
Advertising task prio (FIXME)
|
|
||||||
type: task_priority
|
|
||||||
value: 9
|
|
||||||
|
|
||||||
BLE_MESH_MSG_CACHE_SIZE:
|
|
||||||
description: >
|
|
||||||
Number of messages that are cached for the network. This description
|
|
||||||
prevent unnecessary decryption operations and unnecessary
|
|
||||||
relays. This option is similar to the replay protection list,
|
|
||||||
but has a different purpose.
|
|
||||||
value: 10
|
|
||||||
|
|
||||||
BLE_MESH_ADV_BUF_COUNT:
|
|
||||||
description: >
|
|
||||||
Number of advertising buffers available. This should be chosen
|
|
||||||
based on what kind of features the local node shoule have. E.g.
|
|
||||||
a relay will perform better the more buffers it has. Another
|
|
||||||
thing to consider is outgoing segmented messages. There must
|
|
||||||
be at least three more advertising buffers than the maximum
|
|
||||||
supported outgoing segment count (BT_MESH_TX_SEG_MAX).
|
|
||||||
value: 6
|
|
||||||
|
|
||||||
BLE_MESH_IVU_DIVIDER:
|
|
||||||
description: >
|
|
||||||
When the IV Update state enters Normal operation or IV Update
|
|
||||||
in Progress, we need to keep track of how many hours has passed
|
|
||||||
in the state, since the specification requires us to remain in
|
|
||||||
the state at least for 96 hours (Update in Progress has an
|
|
||||||
additional upper limit of 144 hours).
|
|
||||||
|
|
||||||
In order to fulfil the above requirement, even if the node might
|
|
||||||
be powered off once in a while, we need to store persistently
|
|
||||||
how many hours the node has been in the state. This doesn't
|
|
||||||
necessarily need to happen every hour (thanks to the flexible
|
|
||||||
duration range). The exact cadence will depend a lot on the
|
|
||||||
ways that the node will be used and what kind of power source it
|
|
||||||
has.
|
|
||||||
|
|
||||||
Since there is no single optimal answer, this configuration
|
|
||||||
option allows specifying a divider, i.e. how many intervals
|
|
||||||
the 96 hour minimum gets split into. After each interval the
|
|
||||||
duration that the node has been in the current state gets
|
|
||||||
stored to flash. E.g. the default value of 4 means that the
|
|
||||||
state is saved every 24 hours (96 / 4).
|
|
||||||
value: 4
|
|
||||||
|
|
||||||
BLE_MESH_TX_SEG_MSG_COUNT:
|
|
||||||
description: >
|
|
||||||
Maximum number of simultaneous outgoing multi-segment and/or
|
|
||||||
reliable messages.
|
|
||||||
value: 4
|
|
||||||
|
|
||||||
BLE_MESH_RX_SEG_MSG_COUNT:
|
|
||||||
description: >
|
|
||||||
Maximum number of simultaneous incoming multi-segment and/or
|
|
||||||
reliable messages.
|
|
||||||
value: 2
|
|
||||||
|
|
||||||
BLE_MESH_RX_SDU_MAX:
|
|
||||||
description: >
|
|
||||||
Maximum incoming Upper Transport Access PDU length. This
|
|
||||||
determines also how many segments incoming segmented messages
|
|
||||||
can have. Each segment can contain 12 bytes, so this value should
|
|
||||||
be set to a multiple of 12 to avoid wasted memory. The minimum
|
|
||||||
requirement is 2 segments (24 bytes) whereas the maximum supported
|
|
||||||
by the Mesh specification is 32 segments (384 bytes).
|
|
||||||
value: 72
|
|
||||||
|
|
||||||
BLE_MESH_TX_SEG_MAX:
|
|
||||||
description: >
|
|
||||||
Maximum number of segments supported for outgoing messages.
|
|
||||||
This value should typically be fine-tuned based on what
|
|
||||||
models the local node supports, i.e. what's the largest
|
|
||||||
message payload that the node needs to be able to send.
|
|
||||||
This value affects memory and call stack consumption, which
|
|
||||||
is why the default is lower than the maximum that the
|
|
||||||
specification would allow (32 segments).
|
|
||||||
|
|
||||||
The maximum outgoing SDU size is 12 times this number (out of
|
|
||||||
which 4 or 8 bytes is used for the Transport Layer MIC). For
|
|
||||||
example, 5 segments means the maximum SDU size is 60 bytes,
|
|
||||||
which leaves 56 bytes for application layer data using a
|
|
||||||
4-byte MIC and 52 bytes using an 8-byte MIC.
|
|
||||||
|
|
||||||
Be sure to specify a sufficient number of advertising buffers
|
|
||||||
when setting this option to a higher value. There must be at
|
|
||||||
least three more advertising buffers (BT_MESH_ADV_BUF_COUNT)
|
|
||||||
as there are outgoing segments.
|
|
||||||
value: 3
|
|
||||||
|
|
||||||
BLE_MESH_RELAY:
|
|
||||||
description: >
|
|
||||||
Support for acting as a Mesh Relay Node.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_LOW_POWER:
|
|
||||||
description: >
|
|
||||||
Enable this option to be able to act as a Low Power Node.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_LPN_ESTABLISHMENT:
|
|
||||||
description: >
|
|
||||||
Perform the Friendship establishment using low power, with
|
|
||||||
the help of a reduced scan duty cycle. The downside of this
|
|
||||||
is that the node may miss out on messages intended for it
|
|
||||||
until it has successfully set up Friendship with a Friend
|
|
||||||
node.
|
|
||||||
value: 1
|
|
||||||
|
|
||||||
BLE_MESH_LPN_AUTO:
|
|
||||||
description: >
|
|
||||||
Automatically enable LPN functionality once provisioned and start
|
|
||||||
looking for Friend nodes. If this option is disabled LPN mode
|
|
||||||
needs to be manually enabled by calling bt_mesh_lpn_set(true).
|
|
||||||
node.
|
|
||||||
value: 1
|
|
||||||
|
|
||||||
BLE_MESH_LPN_AUTO_TIMEOUT:
|
|
||||||
description: >
|
|
||||||
Time in seconds from the last received message, that the node
|
|
||||||
will wait before starting to look for Friend nodes.
|
|
||||||
value: 15
|
|
||||||
|
|
||||||
BLE_MESH_LPN_RETRY_TIMEOUT:
|
|
||||||
description: >
|
|
||||||
Time in seconds between Friend Requests, if a previous Friend
|
|
||||||
Request did not receive any acceptable Friend Offers.
|
|
||||||
value: 8
|
|
||||||
|
|
||||||
BLE_MESH_LPN_RSSI_FACTOR:
|
|
||||||
description: >
|
|
||||||
The contribution of the RSSI measured by the Friend node used
|
|
||||||
in Friend Offer Delay calculations. 0 = 1, 1 = 1.5, 2 = 2, 3 = 2.5.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_LPN_RECV_WIN_FACTOR:
|
|
||||||
description: >
|
|
||||||
The contribution of the supported Receive Window used in
|
|
||||||
Friend Offer Delay calculations. 0 = 1, 1 = 1.5, 2 = 2, 3 = 2.5.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_LPN_MIN_QUEUE_SIZE:
|
|
||||||
description: >
|
|
||||||
The MinQueueSizeLog field is defined as log_2(N), where N is
|
|
||||||
the minimum number of maximum size Lower Transport PDUs that
|
|
||||||
the Friend node can store in its Friend Queue. As an example,
|
|
||||||
MinQueueSizeLog value 1 gives N = 2, and value 7 gives N = 128.
|
|
||||||
value: 1
|
|
||||||
|
|
||||||
BLE_MESH_LPN_RECV_DELAY:
|
|
||||||
description: >
|
|
||||||
The ReceiveDelay is the time between the Low Power node
|
|
||||||
sending a request and listening for a response. This delay
|
|
||||||
allows the Friend node time to prepare the response. The value
|
|
||||||
is in units of milliseconds.
|
|
||||||
value: 100
|
|
||||||
|
|
||||||
BLE_MESH_LPN_POLL_TIMEOUT:
|
|
||||||
description: >
|
|
||||||
PollTimeout timer is used to measure time between two
|
|
||||||
consecutive requests sent by the Low Power node. If no
|
|
||||||
requests are received by the Friend node before the
|
|
||||||
PollTimeout timer expires, then the friendship is considered
|
|
||||||
terminated. The value is in units of 100 milliseconds, so e.g.
|
|
||||||
a value of 300 means 30 seconds.
|
|
||||||
value: 300
|
|
||||||
|
|
||||||
BLE_MESH_LPN_INIT_POLL_TIMEOUT:
|
|
||||||
description: >
|
|
||||||
The initial value of the PollTimeout timer when Friendship
|
|
||||||
gets established for the first time. After this the timeout
|
|
||||||
will gradually grow toward the actual PollTimeout, doubling
|
|
||||||
in value for each iteration. The value is in units of 100
|
|
||||||
milliseconds, so e.g. a value of 300 means 3 seconds.
|
|
||||||
value: MYNEWT_VAL_BLE_MESH_LPN_POLL_TIMEOUT
|
|
||||||
|
|
||||||
BLE_MESH_LPN_SCAN_LATENCY:
|
|
||||||
description: >
|
|
||||||
Latency in milliseconds that it takes to enable scanning. This
|
|
||||||
is in practice how much time in advance before the Receive Window
|
|
||||||
that scanning is requested to be enabled.
|
|
||||||
value: 10
|
|
||||||
|
|
||||||
BLE_MESH_LPN_GROUPS:
|
|
||||||
description: >
|
|
||||||
Maximum number of groups that the LPN can subscribe to.
|
|
||||||
value: 10
|
|
||||||
|
|
||||||
BLE_MESH_FRIEND:
|
|
||||||
description: >
|
|
||||||
Enable this option to be able to act as a Friend Node.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_FRIEND_RECV_WIN:
|
|
||||||
description: >
|
|
||||||
Receive Window in milliseconds supported by the Friend node.
|
|
||||||
value: 255
|
|
||||||
|
|
||||||
BLE_MESH_FRIEND_QUEUE_SIZE:
|
|
||||||
description: >
|
|
||||||
Minimum number of buffers available to be stored for each
|
|
||||||
local Friend Queue.
|
|
||||||
value: 16
|
|
||||||
|
|
||||||
BLE_MESH_FRIEND_SUB_LIST_SIZE:
|
|
||||||
description: >
|
|
||||||
Size of the Subscription List that can be supported by a
|
|
||||||
Friend node for a Low Power node.
|
|
||||||
value: 3
|
|
||||||
|
|
||||||
BLE_MESH_FRIEND_LPN_COUNT:
|
|
||||||
description: >
|
|
||||||
Number of Low Power Nodes the Friend can have a Friendship
|
|
||||||
with simultaneously.
|
|
||||||
value: 2
|
|
||||||
|
|
||||||
BLE_MESH_FRIEND_SEG_RX:
|
|
||||||
description: >
|
|
||||||
Number of incomplete segment lists that we track for each LPN
|
|
||||||
that we are Friends for. In other words, this determines how
|
|
||||||
many elements we can simultaneously be receiving segmented
|
|
||||||
messages from when the messages are going into the Friend queue.
|
|
||||||
value: 1
|
|
||||||
|
|
||||||
BLE_MESH_CFG_CLI:
|
|
||||||
description: >
|
|
||||||
Enable support for the configuration client model.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_HEALTH_CLI:
|
|
||||||
description: >
|
|
||||||
Enable support for the health client model.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_SHELL:
|
|
||||||
description: >
|
|
||||||
Activate shell module that provides Bluetooth Mesh commands to
|
|
||||||
the console.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_DEBUG:
|
|
||||||
description: >
|
|
||||||
Use this option to enable debug logs for the Bluetooth
|
|
||||||
Mesh functionality.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_DEBUG_NET:
|
|
||||||
description: >
|
|
||||||
Use this option to enable Network layer debug logs for the
|
|
||||||
Bluetooth Mesh functionality.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_DEBUG_TRANS:
|
|
||||||
description: >
|
|
||||||
Use this option to enable Transport layer debug logs for the
|
|
||||||
Bluetooth Mesh functionality.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_DEBUG_BEACON:
|
|
||||||
description: >
|
|
||||||
Use this option to enable Beacon-related debug logs for the
|
|
||||||
Bluetooth Mesh functionality.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_DEBUG_CRYPTO:
|
|
||||||
description: >
|
|
||||||
Use this option to enable cryptographic debug logs for the
|
|
||||||
Bluetooth Mesh functionality.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_DEBUG_PROV:
|
|
||||||
description: >
|
|
||||||
Use this option to enable Provisioning debug logs for the
|
|
||||||
Bluetooth Mesh functionality.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_DEBUG_ACCESS:
|
|
||||||
description: >
|
|
||||||
Use this option to enable Access layer and device composition
|
|
||||||
related debug logs for Bluetooth Mesh.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_DEBUG_MODEL:
|
|
||||||
description: >
|
|
||||||
Use this option to enable debug logs for the Foundation
|
|
||||||
Models.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_DEBUG_ADV:
|
|
||||||
description: >
|
|
||||||
Use this option to enable advertising debug logs for
|
|
||||||
the Bluetooth Mesh functionality.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_DEBUG_LOW_POWER:
|
|
||||||
description: >
|
|
||||||
Use this option to enable Low Power debug logs for the
|
|
||||||
Bluetooth Mesh functionality.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_DEBUG_FRIEND:
|
|
||||||
description: >
|
|
||||||
Use this option to enable Friend debug logs for the
|
|
||||||
Bluetooth Mesh functionality.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_DEBUG_PROXY:
|
|
||||||
description: >
|
|
||||||
Use this option to enable Proxy protocol debug logs.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_DEBUG_SETTINGS:
|
|
||||||
description: >
|
|
||||||
Use this option to enable persistent settings debug logs.
|
|
||||||
value: 1
|
|
||||||
|
|
||||||
BLE_MESH_IV_UPDATE_TEST:
|
|
||||||
description: >
|
|
||||||
This option removes the 96 hour limit of the IV Update
|
|
||||||
Procedure and lets the state be changed at any time.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_TESTING:
|
|
||||||
description: >
|
|
||||||
This option enables testing API.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_DEV_UUID:
|
|
||||||
description: >
|
|
||||||
Device UUID
|
|
||||||
value: ((uint8_t[16]){0x11, 0x22, 0})
|
|
||||||
|
|
||||||
BLE_MESH_SHELL_MODELS:
|
|
||||||
description: >
|
|
||||||
Include implementation of some demo models.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_MESH_OOB_OUTPUT_ACTIONS:
|
|
||||||
description: >
|
|
||||||
Supported Output OOB Actions
|
|
||||||
BT_MESH_NO_OUTPUT = 0,
|
|
||||||
BT_MESH_BLINK = BIT(0)
|
|
||||||
BT_MESH_BEEP = BIT(1)
|
|
||||||
BT_MESH_VIBRATE = BIT(2)
|
|
||||||
BT_MESH_DISPLAY_NUMBER = BIT(3)
|
|
||||||
BT_MESH_DISPLAY_STRING = BIT(4)
|
|
||||||
value: ((BT_MESH_DISPLAY_NUMBER))
|
|
||||||
|
|
||||||
BLE_MESH_OOB_OUTPUT_SIZE:
|
|
||||||
description: >
|
|
||||||
Output OOB size
|
|
||||||
value: 4
|
|
||||||
|
|
||||||
BLE_MESH_OOB_INPUT_ACTIONS:
|
|
||||||
description: >
|
|
||||||
Supported Input OOB Actions
|
|
||||||
BT_MESH_NO_INPUT = 0,
|
|
||||||
BT_MESH_PUSH = BIT(0)
|
|
||||||
BT_MESH_TWIST = BIT(1)
|
|
||||||
BT_MESH_ENTER_NUMBER = BIT(2)
|
|
||||||
BT_MESH_ENTER_STRING = BIT(3)
|
|
||||||
value: ((BT_MESH_NO_INPUT))
|
|
||||||
|
|
||||||
BLE_MESH_OOB_INPUT_SIZE:
|
|
||||||
description: >
|
|
||||||
Input OOB size
|
|
||||||
value: 4
|
|
||||||
|
|
||||||
BLE_MESH_SETTINGS:
|
|
||||||
description: >
|
|
||||||
This option enables Mesh settings storage.
|
|
||||||
value: 1
|
|
||||||
|
|
||||||
BLE_MESH_STORE_TIMEOUT:
|
|
||||||
description: >
|
|
||||||
This value defines in seconds how soon any pending changes
|
|
||||||
are actually written into persistent storage (flash) after
|
|
||||||
a change occurs.
|
|
||||||
value: 2
|
|
||||||
|
|
||||||
BLE_MESH_SEQ_STORE_RATE:
|
|
||||||
description: >
|
|
||||||
This value defines how often the local sequence number gets
|
|
||||||
updated in persistent storage (i.e. flash). E.g. a value of 100
|
|
||||||
means that the sequence number will be stored to flash on every
|
|
||||||
100th increment. If the node sends messages very frequently a
|
|
||||||
higher value makes more sense, whereas if the node sends
|
|
||||||
infrequently a value as low as 0 (update storage for every
|
|
||||||
increment) can make sense. When the stack gets initialized it
|
|
||||||
will add this number to the last stored one, so that it starts
|
|
||||||
off with a value that's guaranteed to be larger than the last
|
|
||||||
one used before power off.
|
|
||||||
value: 128
|
|
||||||
|
|
||||||
BLE_MESH_RPL_STORE_TIMEOUT:
|
|
||||||
description: >
|
|
||||||
This value defines in seconds how soon the RPL gets written to
|
|
||||||
persistent storage after a change occurs. If the node receives
|
|
||||||
messages frequently it may make sense to have this set to a
|
|
||||||
large value, whereas if the RPL gets updated infrequently a
|
|
||||||
value as low as 0 (write immediately) may make sense. Note that
|
|
||||||
if the node operates a security sensitive use case, and there's
|
|
||||||
a risk of sudden power loss, it may be a security vulnerability
|
|
||||||
to set this value to anything else than 0 (a power loss before
|
|
||||||
writing to storage exposes the node to potential message
|
|
||||||
replay attacks).
|
|
||||||
value: 5
|
|
||||||
|
|
||||||
BLE_MESH_DEVICE_NAME:
|
|
||||||
description: >
|
|
||||||
This value defines BLE Mesh device/node name.
|
|
||||||
value: '"nimble-mesh-node"'
|
|
||||||
|
|
||||||
BLE_MESH_SYSINIT_STAGE:
|
|
||||||
description: >
|
|
||||||
Primary sysinit stage for BLE mesh functionality.
|
|
||||||
value: 500
|
|
||||||
|
|
||||||
BLE_MESH_SYSINIT_STAGE_SHELL:
|
|
||||||
description: >
|
|
||||||
Secondary sysinit stage for BLE mesh functionality.
|
|
||||||
value: 1000
|
|
||||||
|
|
||||||
syscfg.vals.BLE_MESH_SHELL:
|
|
||||||
BLE_MESH_CFG_CLI: 1
|
|
||||||
BLE_MESH_HEALTH_CLI: 1
|
|
||||||
BLE_MESH_IV_UPDATE_TEST: 1
|
|
||||||
|
|
||||||
syscfg.vals.BLE_MESH_GATT_PROXY:
|
|
||||||
BLE_MESH_PROXY: 1
|
|
||||||
|
|
||||||
syscfg.vals.BLE_MESH_PB_GATT:
|
|
||||||
BLE_MESH_PROXY: 1
|
|
||||||
BLE_MESH_PROV: 1
|
|
||||||
|
|
||||||
syscfg.vals.BLE_MESH_PB_ADV:
|
|
||||||
BLE_MESH_PROV: 1
|
|
|
@ -1,34 +0,0 @@
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
pkg.name: nimble/host/services/ans
|
|
||||||
pkg.description: Alert Notification Service Server.
|
|
||||||
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
|
||||||
pkg.homepage: "http://mynewt.apache.org/"
|
|
||||||
pkg.keywords:
|
|
||||||
- ble
|
|
||||||
- bluetooth
|
|
||||||
- ans
|
|
||||||
- nimble
|
|
||||||
|
|
||||||
pkg.deps:
|
|
||||||
- nimble/host
|
|
||||||
|
|
||||||
pkg.init:
|
|
||||||
ble_svc_ans_init: 'MYNEWT_VAL(BLE_SVC_ANS_SYSINIT_STAGE)'
|
|
|
@ -1,30 +0,0 @@
|
||||||
# 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.
|
|
||||||
|
|
||||||
syscfg.defs:
|
|
||||||
BLE_SVC_ANS_NEW_ALERT_CAT:
|
|
||||||
description: "Initial supported new alert category bitmask."
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_SVC_ANS_UNR_ALERT_CAT:
|
|
||||||
description: "Initial supported unread alert category bitmask."
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_SVC_ANS_SYSINIT_STAGE:
|
|
||||||
description: >
|
|
||||||
Sysinit stage for the alert notification service.
|
|
||||||
value: 303
|
|
|
@ -1,34 +0,0 @@
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
pkg.name: nimble/host/services/bas
|
|
||||||
pkg.description: Battery Service
|
|
||||||
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
|
||||||
pkg.homepage: "http://mynewt.apache.org/"
|
|
||||||
pkg.keywords:
|
|
||||||
- ble
|
|
||||||
- bluetooth
|
|
||||||
- bas
|
|
||||||
- nimble
|
|
||||||
|
|
||||||
pkg.deps:
|
|
||||||
- nimble/host
|
|
||||||
|
|
||||||
pkg.init:
|
|
||||||
ble_svc_bas_init: 'MYNEWT_VAL(BLE_SVC_BAS_SYSINIT_STAGE)'
|
|
|
@ -1,34 +0,0 @@
|
||||||
# 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.
|
|
||||||
|
|
||||||
syscfg.defs:
|
|
||||||
BLE_SVC_BAS_BATTERY_LEVEL_READ_PERM:
|
|
||||||
description: >
|
|
||||||
Defines permissions for reading "Battery Level" characteristics. Can
|
|
||||||
be zero to allow read without extra permissions or combination of:
|
|
||||||
BLE_GATT_CHR_F_READ_ENC
|
|
||||||
BLE_GATT_CHR_F_READ_AUTHEN
|
|
||||||
BLE_GATT_CHR_F_READ_AUTHOR
|
|
||||||
value: 0
|
|
||||||
BLE_SVC_BAS_BATTERY_LEVEL_NOTIFY_ENABLE:
|
|
||||||
description: >
|
|
||||||
Set to 1 to support notification or 0 to disable it.
|
|
||||||
value: 1
|
|
||||||
BLE_SVC_BAS_SYSINIT_STAGE:
|
|
||||||
description: >
|
|
||||||
Sysinit stage for the battery level service.
|
|
||||||
value: 303
|
|
|
@ -1,34 +0,0 @@
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
pkg.name: nimble/host/services/gap
|
|
||||||
pkg.description: Implements the GAP Service.
|
|
||||||
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
|
||||||
pkg.homepage: "http://mynewt.apache.org/"
|
|
||||||
pkg.keywords:
|
|
||||||
- ble
|
|
||||||
- bluetooth
|
|
||||||
- nimble
|
|
||||||
- gap
|
|
||||||
|
|
||||||
pkg.deps:
|
|
||||||
- nimble/host
|
|
||||||
|
|
||||||
pkg.init:
|
|
||||||
ble_svc_gap_init: 'MYNEWT_VAL(BLE_SVC_GAP_SYSINIT_STAGE)'
|
|
|
@ -1,83 +0,0 @@
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
syscfg.defs:
|
|
||||||
BLE_SVC_GAP_DEVICE_NAME:
|
|
||||||
description: >
|
|
||||||
Default value for "Device Name" characteristics, unless overwritten
|
|
||||||
by application.
|
|
||||||
value: '"nimble"'
|
|
||||||
BLE_SVC_GAP_DEVICE_NAME_WRITE_PERM:
|
|
||||||
description: >
|
|
||||||
Defines permissions for writing "Device Name" characteristics. Can
|
|
||||||
be zero to allow write without extra permissions or combination of:
|
|
||||||
BLE_GATT_CHR_F_WRITE_ENC
|
|
||||||
BLE_GATT_CHR_F_WRITE_AUTHEN
|
|
||||||
BLE_GATT_CHR_F_WRITE_AUTHOR
|
|
||||||
Set to '-1' to make characteristic read only.
|
|
||||||
value: -1
|
|
||||||
BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH:
|
|
||||||
description: Maximum length for "Device Name" characteristics
|
|
||||||
value: 31
|
|
||||||
BLE_SVC_GAP_APPEARANCE:
|
|
||||||
description: 'Device appearance'
|
|
||||||
value: 0
|
|
||||||
BLE_SVC_GAP_APPEARANCE_WRITE_PERM:
|
|
||||||
description: >
|
|
||||||
Defines permissions for writing "Appearance" characteristics. Can
|
|
||||||
be zero to allow write without extra permissions or combination of:
|
|
||||||
BLE_GATT_CHR_F_WRITE_ENC
|
|
||||||
BLE_GATT_CHR_F_WRITE_AUTHEN
|
|
||||||
BLE_GATT_CHR_F_WRITE_AUTHOR
|
|
||||||
Set to '-1' to make characteristic read only.
|
|
||||||
value: -1
|
|
||||||
|
|
||||||
# Setting all values for PPCP to '0' will disable characteristic!
|
|
||||||
BLE_SVC_GAP_PPCP_MIN_CONN_INTERVAL:
|
|
||||||
description: >
|
|
||||||
Value of "minimum connection interval" of PPCP characteristic as
|
|
||||||
defined by Core specification 5.0, Vol 3, Part C, section 12.3.
|
|
||||||
value: 0
|
|
||||||
BLE_SVC_GAP_PPCP_MAX_CONN_INTERVAL:
|
|
||||||
description: >
|
|
||||||
Value of "maximum connection interval" of PPCP characteristic as
|
|
||||||
defined by Core specification 5.0, Vol 3, Part C, section 12.3.
|
|
||||||
value: 0
|
|
||||||
BLE_SVC_GAP_PPCP_SLAVE_LATENCY:
|
|
||||||
description: >
|
|
||||||
Value of "slave latency" of PPCP characteristic as defined by Core
|
|
||||||
specification 5.0, Vol 3, Part C, section 12.3.
|
|
||||||
value: 0
|
|
||||||
BLE_SVC_GAP_PPCP_SUPERVISION_TMO:
|
|
||||||
description: >
|
|
||||||
Value of "connection supervision timeout multiplier" of PPCP
|
|
||||||
characteristic as defined by Core specification 5.0, Vol 3, Part C,
|
|
||||||
section 12.3.
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
BLE_SVC_GAP_CENTRAL_ADDRESS_RESOLUTION:
|
|
||||||
description: >
|
|
||||||
Value of "Central Address Resolution" characteristics, as defined
|
|
||||||
by Core specification 5.0, Vol 3, Part C, section 12.
|
|
||||||
Set to '-1' to disable.
|
|
||||||
value: -1
|
|
||||||
|
|
||||||
BLE_SVC_GAP_SYSINIT_STAGE:
|
|
||||||
description: >
|
|
||||||
Sysinit stage for the GAP BLE service.
|
|
||||||
value: 301
|
|
|
@ -1,34 +0,0 @@
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
pkg.name: nimble/host/services/gatt
|
|
||||||
pkg.description: Implements the GATT service.
|
|
||||||
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
|
||||||
pkg.homepage: "http://mynewt.apache.org/"
|
|
||||||
pkg.keywords:
|
|
||||||
- ble
|
|
||||||
- bluetooth
|
|
||||||
- nimble
|
|
||||||
- gatt
|
|
||||||
|
|
||||||
pkg.deps:
|
|
||||||
- nimble/host
|
|
||||||
|
|
||||||
pkg.init:
|
|
||||||
ble_svc_gatt_init: 'MYNEWT_VAL(BLE_SVC_GATT_SYSINIT_STAGE)'
|
|
|
@ -1,24 +0,0 @@
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
syscfg.defs:
|
|
||||||
BLE_SVC_GATT_SYSINIT_STAGE:
|
|
||||||
description: >
|
|
||||||
Sysinit stage for the GATT BLE service
|
|
||||||
value: 302
|
|
|
@ -1,34 +0,0 @@
|
||||||
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
pkg.name: nimble/host/services/ias
|
|
||||||
pkg.description: Immediate Alert Service Implementation.
|
|
||||||
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
|
||||||
pkg.homepage: "http://mynewt.apache.org/"
|
|
||||||
pkg.keywords:
|
|
||||||
- ble
|
|
||||||
- bluetooth
|
|
||||||
- ias
|
|
||||||
- nimble
|
|
||||||
|
|
||||||
pkg.deps:
|
|
||||||
- nimble/host
|
|
||||||
|
|
||||||
pkg.init:
|
|
||||||
ble_svc_ias_init: 'MYNEWT_VAL(BLE_SVC_IAS_SYSINIT_STAGE)'
|
|
|
@ -1,23 +0,0 @@
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
syscfg.defs:
|
|
||||||
BLE_SVC_IAS_SYSINIT_STAGE:
|
|
||||||
description: >
|
|
||||||
Sysinit stage for the immediate alert BLE service.
|
|
||||||
value: 303
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "sysinit/sysinit.h"
|
||||||
|
#include "host/ble_hs.h"
|
||||||
|
#include "services/ipss/ble_svc_ipss.h"
|
||||||
|
|
||||||
|
static const struct ble_gatt_svc_def ble_svc_ipss_defs[] = {
|
||||||
|
{
|
||||||
|
/*** Service: GATT */
|
||||||
|
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||||
|
.uuid = BLE_UUID16_DECLARE(BLE_SVC_IPSS_UUID16),
|
||||||
|
.characteristics = NULL,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
0, /* No more services. */
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
ble_svc_ipss_init(void)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Ensure this function only gets called by sysinit. */
|
||||||
|
SYSINIT_ASSERT_ACTIVE();
|
||||||
|
|
||||||
|
rc = ble_gatts_count_cfg(ble_svc_ipss_defs);
|
||||||
|
SYSINIT_PANIC_ASSERT(rc == 0);
|
||||||
|
|
||||||
|
rc = ble_gatts_add_svcs(ble_svc_ipss_defs);
|
||||||
|
SYSINIT_PANIC_ASSERT(rc == 0);
|
||||||
|
}
|
|
@ -1,34 +0,0 @@
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
pkg.name: nimble/host/services/lls
|
|
||||||
pkg.description: Link Loss Service Implementation.
|
|
||||||
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
|
||||||
pkg.homepage: "http://mynewt.apache.org/"
|
|
||||||
pkg.keywords:
|
|
||||||
- ble
|
|
||||||
- bluetooth
|
|
||||||
- lls
|
|
||||||
- nimble
|
|
||||||
|
|
||||||
pkg.deps:
|
|
||||||
- nimble/host
|
|
||||||
|
|
||||||
pkg.init:
|
|
||||||
ble_svc_lls_init: 'MYNEWT_VAL(BLE_SVC_LLS_SYSINIT_STAGE)'
|
|
|
@ -1,22 +0,0 @@
|
||||||
# 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.
|
|
||||||
|
|
||||||
syscfg.defs:
|
|
||||||
BLE_SVC_LLS_SYSINIT_STAGE:
|
|
||||||
description: >
|
|
||||||
Sysinit stage for the link loss BLE service.
|
|
||||||
value: 303
|
|
|
@ -1,34 +0,0 @@
|
||||||
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
pkg.name: nimble/host/services/tps
|
|
||||||
pkg.description: Tx Power Service adopted specification.
|
|
||||||
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
|
||||||
pkg.homepage: "http://mynewt.apache.org/"
|
|
||||||
pkg.keywords:
|
|
||||||
- ble
|
|
||||||
- bluetooth
|
|
||||||
- tps
|
|
||||||
- nimble
|
|
||||||
|
|
||||||
pkg.deps:
|
|
||||||
- nimble/host
|
|
||||||
|
|
||||||
pkg.init:
|
|
||||||
ble_svc_tps_init: 'MYNEWT_VAL(BLE_SVC_TPS_SYSINIT_STAGE)'
|
|
|
@ -1,23 +0,0 @@
|
||||||
# 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.
|
|
||||||
|
|
||||||
syscfg.defs:
|
|
||||||
BLE_SVC_TPS_SYSINIT_STAGE:
|
|
||||||
description: >
|
|
||||||
Sysinit stage for the transmit power BLE service.
|
|
||||||
value: 303
|
|
||||||
|
|
|
@ -67,6 +67,37 @@ ble_hs_id_gen_rnd(int nrpa, ble_addr_t *out_addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
||||||
|
/**
|
||||||
|
* Sets the device's pseudo Non Resolvable Private Address when 'Host based
|
||||||
|
* privacy' is in use.
|
||||||
|
*
|
||||||
|
* @return 0 on success;
|
||||||
|
* Appropriate error code if failure.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ble_hs_id_set_nrpa_rnd()
|
||||||
|
{
|
||||||
|
|
||||||
|
ble_addr_t nrpa_addr;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
ble_hs_id_gen_rnd(1, &nrpa_addr);
|
||||||
|
|
||||||
|
ble_hs_lock();
|
||||||
|
|
||||||
|
/* set the NRPA address as pseudo random address in controller */
|
||||||
|
rc = ble_hs_hci_util_set_random_addr(nrpa_addr.val);
|
||||||
|
if (rc != 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(ble_hs_id_rnd, nrpa_addr.val, BLE_DEV_ADDR_LEN);
|
||||||
|
|
||||||
|
done:
|
||||||
|
ble_hs_unlock();
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the device's pseudo RPA address when 'Host based privacy' is in use.
|
* Sets the device's pseudo RPA address when 'Host based privacy' is in use.
|
||||||
* The address type (RPA) is inferred from the most-significant bits. The
|
* The address type (RPA) is inferred from the most-significant bits. The
|
||||||
|
|
|
@ -36,6 +36,7 @@ void ble_hs_id_rnd_reset(void);
|
||||||
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
||||||
bool ble_hs_is_rpa(uint8_t *addr, uint8_t addr_type);
|
bool ble_hs_is_rpa(uint8_t *addr, uint8_t addr_type);
|
||||||
int ble_hs_id_set_pseudo_rnd(const uint8_t *);
|
int ble_hs_id_set_pseudo_rnd(const uint8_t *);
|
||||||
|
int ble_hs_id_set_nrpa_rnd(void);
|
||||||
#endif
|
#endif
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "stats/stats.h"
|
#include "stats/stats.h"
|
||||||
#include "ble_hs_priv.h"
|
#include "ble_hs_priv.h"
|
||||||
#include "ble_hs_resolv_priv.h"
|
#include "ble_hs_resolv_priv.h"
|
||||||
|
#include "host/ble_hs_pvcy.h"
|
||||||
|
|
||||||
static uint8_t ble_hs_pvcy_started;
|
static uint8_t ble_hs_pvcy_started;
|
||||||
static uint8_t ble_hs_pvcy_irk[16];
|
static uint8_t ble_hs_pvcy_irk[16];
|
||||||
|
@ -329,7 +330,7 @@ ble_hs_pvcy_rpa_config(uint8_t enable)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
if (enable != 0) {
|
if (enable != NIMBLE_HOST_DISABLE_PRIVACY) {
|
||||||
rc = ble_hs_pvcy_ensure_started();
|
rc = ble_hs_pvcy_ensure_started();
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -337,8 +338,15 @@ ble_hs_pvcy_rpa_config(uint8_t enable)
|
||||||
|
|
||||||
ble_hs_resolv_enable(true);
|
ble_hs_resolv_enable(true);
|
||||||
|
|
||||||
|
/* Configure NRPA address related flags according to input parameter */
|
||||||
|
if (enable == NIMBLE_HOST_ENABLE_NRPA) {
|
||||||
|
ble_hs_resolv_nrpa_enable();
|
||||||
|
} else {
|
||||||
|
ble_hs_resolv_nrpa_disable();
|
||||||
|
}
|
||||||
|
|
||||||
/* Generate local RPA address and set it in controller */
|
/* Generate local RPA address and set it in controller */
|
||||||
rc = ble_hs_gen_own_rpa_random();
|
rc = ble_hs_gen_own_private_rnd();
|
||||||
} else {
|
} else {
|
||||||
ble_hs_resolv_enable(false);
|
ble_hs_resolv_enable(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,9 @@ struct ble_hs_resolv_data {
|
||||||
struct ble_npl_callout rpa_timer;
|
struct ble_npl_callout rpa_timer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* NRPA bit: Enables NRPA as private address. */
|
||||||
|
static bool nrpa_pvcy;
|
||||||
|
|
||||||
/*** APIs for Peer Device Records.
|
/*** APIs for Peer Device Records.
|
||||||
*
|
*
|
||||||
* These Peer records are necessary to take care of Peers with RPA address when
|
* These Peer records are necessary to take care of Peers with RPA address when
|
||||||
|
@ -305,6 +308,10 @@ is_ble_hs_resolv_enabled(void)
|
||||||
bool
|
bool
|
||||||
ble_host_rpa_enabled(void)
|
ble_host_rpa_enabled(void)
|
||||||
{
|
{
|
||||||
|
if (nrpa_pvcy) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_ble_hs_resolv_enabled() && ble_hs_pvcy_enabled()) {
|
if (is_ble_hs_resolv_enabled() && ble_hs_pvcy_enabled()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -385,12 +392,16 @@ ble_hs_resolv_gen_priv_addr(struct ble_hs_resolv_entry *rl, int local)
|
||||||
addr[2] = ecb.cipher_text[13];
|
addr[2] = ecb.cipher_text[13];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called to generate RPA address and this address is set in controller as
|
/* Called to generate private (RPA/NRPA) address and this address is set in controller as
|
||||||
* Random address. This is necessary in Host based privacy because controller is unaware of RPA
|
* Random address. This is necessary in Host based privacy because controller
|
||||||
* address is being used */
|
* is unaware of private address is being used */
|
||||||
int
|
int
|
||||||
ble_hs_gen_own_rpa_random(void)
|
ble_hs_gen_own_private_rnd(void)
|
||||||
{
|
{
|
||||||
|
if (nrpa_pvcy) {
|
||||||
|
return ble_hs_id_set_nrpa_rnd();
|
||||||
|
}
|
||||||
|
|
||||||
struct ble_hs_resolv_entry *rl = &g_ble_hs_resolv_list[0];
|
struct ble_hs_resolv_entry *rl = &g_ble_hs_resolv_list[0];
|
||||||
|
|
||||||
ble_hs_resolv_gen_priv_addr(rl, 1);
|
ble_hs_resolv_gen_priv_addr(rl, 1);
|
||||||
|
@ -412,12 +423,11 @@ ble_hs_get_rpa_local(void)
|
||||||
static void
|
static void
|
||||||
ble_hs_resolv_rpa_timer_cb(struct ble_npl_event *ev)
|
ble_hs_resolv_rpa_timer_cb(struct ble_npl_event *ev)
|
||||||
{
|
{
|
||||||
if (ble_host_rpa_enabled()) {
|
if (ble_host_rpa_enabled() || (nrpa_pvcy)) {
|
||||||
BLE_HS_LOG(DEBUG, "RPA Timeout; start active adv & scan with new RPA\n");
|
BLE_HS_LOG(DEBUG, "RPA/NRPA Timeout; start active adv & scan with new Private address \n");
|
||||||
|
|
||||||
ble_gap_preempt();
|
ble_gap_preempt();
|
||||||
/* Generate local RPA */
|
/* Generate local private address */
|
||||||
ble_hs_gen_own_rpa_random();
|
ble_hs_gen_own_private_rnd();
|
||||||
ble_npl_callout_reset(&g_ble_hs_resolv_data.rpa_timer,
|
ble_npl_callout_reset(&g_ble_hs_resolv_data.rpa_timer,
|
||||||
(int32_t)g_ble_hs_resolv_data.rpa_tmo);
|
(int32_t)g_ble_hs_resolv_data.rpa_tmo);
|
||||||
ble_gap_preempt_done();
|
ble_gap_preempt_done();
|
||||||
|
@ -595,6 +605,23 @@ ble_hs_resolv_list_clear_all(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by host stack to enable NRPA privacy flag for future reference
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ble_hs_resolv_nrpa_enable(void)
|
||||||
|
{
|
||||||
|
nrpa_pvcy = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by host stack to disable NRPA privacy flag
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ble_hs_resolv_nrpa_disable(void)
|
||||||
|
{
|
||||||
|
nrpa_pvcy = false;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Called to enable or disable address resolution in the host
|
* Called to enable or disable address resolution in the host
|
||||||
*
|
*
|
||||||
|
|
|
@ -61,7 +61,7 @@ struct ble_hs_dev_records {
|
||||||
|
|
||||||
/* Add a device to the resolving list */
|
/* Add a device to the resolving list */
|
||||||
int ble_hs_resolv_list_add(uint8_t *cmdbuf);
|
int ble_hs_resolv_list_add(uint8_t *cmdbuf);
|
||||||
int ble_hs_gen_own_rpa_random(void);
|
int ble_hs_gen_own_private_rnd(void);
|
||||||
uint8_t *ble_hs_get_rpa_local(void);
|
uint8_t *ble_hs_get_rpa_local(void);
|
||||||
|
|
||||||
/* Remove a device from the resolving list */
|
/* Remove a device from the resolving list */
|
||||||
|
@ -71,6 +71,8 @@ void ble_hs_resolv_list_clear_all(void);
|
||||||
|
|
||||||
/* Address resolution enable command */
|
/* Address resolution enable command */
|
||||||
void ble_hs_resolv_enable(bool);
|
void ble_hs_resolv_enable(bool);
|
||||||
|
void ble_hs_resolv_nrpa_enable(void);
|
||||||
|
void ble_hs_resolv_nrpa_disable(void);
|
||||||
|
|
||||||
/* Finds 'addr' in resolving list. Doesnt check if address resolution enabled */
|
/* Finds 'addr' in resolving list. Doesnt check if address resolution enabled */
|
||||||
struct ble_hs_resolv_entry *
|
struct ble_hs_resolv_entry *
|
||||||
|
|
|
@ -239,7 +239,10 @@ ble_uuid_flat(const ble_uuid_t *uuid, void *dst)
|
||||||
break;
|
break;
|
||||||
case BLE_UUID_TYPE_32:
|
case BLE_UUID_TYPE_32:
|
||||||
memcpy(dst, ble_uuid_base, 16);
|
memcpy(dst, ble_uuid_base, 16);
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wpointer-arith"
|
||||||
put_le32(dst + 12, BLE_UUID32(uuid)->value);
|
put_le32(dst + 12, BLE_UUID32(uuid)->value);
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
break;
|
break;
|
||||||
case BLE_UUID_TYPE_128:
|
case BLE_UUID_TYPE_128:
|
||||||
memcpy(dst, BLE_UUID128(uuid)->value, 16);
|
memcpy(dst, BLE_UUID128(uuid)->value, 16);
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
pkg.name: nimble/host/store/config
|
|
||||||
pkg.description: sys/config-based persistence layer for the NimBLE host.
|
|
||||||
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
|
||||||
pkg.homepage: "http://mynewt.apache.org/"
|
|
||||||
pkg.keywords:
|
|
||||||
- ble
|
|
||||||
- bluetooth
|
|
||||||
- nimble
|
|
||||||
- persistence
|
|
||||||
|
|
||||||
pkg.deps:
|
|
||||||
- "@apache-mynewt-core/encoding/base64"
|
|
||||||
- nimble/host
|
|
||||||
|
|
||||||
pkg.deps.BLE_STORE_CONFIG_PERSIST:
|
|
||||||
- "@apache-mynewt-core/sys/config"
|
|
||||||
|
|
||||||
pkg.init:
|
|
||||||
ble_store_config_init: 'MYNEWT_VAL(BLE_STORE_SYSINIT_STAGE)'
|
|
|
@ -1,231 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "syscfg/syscfg.h"
|
|
||||||
|
|
||||||
#if MYNEWT_VAL(BLE_STORE_CONFIG_PERSIST)
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "sysinit/sysinit.h"
|
|
||||||
#include "host/ble_hs.h"
|
|
||||||
#include "config/config.h"
|
|
||||||
#include "base64/base64.h"
|
|
||||||
#include "store/config/ble_store_config.h"
|
|
||||||
#include "ble_store_config_priv.h"
|
|
||||||
|
|
||||||
static int
|
|
||||||
ble_store_config_conf_set(int argc, char **argv, char *val);
|
|
||||||
static int
|
|
||||||
ble_store_config_conf_export(void (*func)(char *name, char *val),
|
|
||||||
enum conf_export_tgt tgt);
|
|
||||||
|
|
||||||
static struct conf_handler ble_store_config_conf_handler = {
|
|
||||||
.ch_name = "ble_hs",
|
|
||||||
.ch_get = NULL,
|
|
||||||
.ch_set = ble_store_config_conf_set,
|
|
||||||
.ch_commit = NULL,
|
|
||||||
.ch_export = ble_store_config_conf_export
|
|
||||||
};
|
|
||||||
|
|
||||||
#define BLE_STORE_CONFIG_SEC_ENCODE_SZ \
|
|
||||||
BASE64_ENCODE_SIZE(sizeof (struct ble_store_value_sec))
|
|
||||||
|
|
||||||
#define BLE_STORE_CONFIG_SEC_SET_ENCODE_SZ \
|
|
||||||
(MYNEWT_VAL(BLE_STORE_MAX_BONDS) * BLE_STORE_CONFIG_SEC_ENCODE_SZ + 1)
|
|
||||||
|
|
||||||
#define BLE_STORE_CONFIG_CCCD_ENCODE_SZ \
|
|
||||||
BASE64_ENCODE_SIZE(sizeof (struct ble_store_value_cccd))
|
|
||||||
|
|
||||||
#define BLE_STORE_CONFIG_CCCD_SET_ENCODE_SZ \
|
|
||||||
(MYNEWT_VAL(BLE_STORE_MAX_CCCDS) * BLE_STORE_CONFIG_CCCD_ENCODE_SZ + 1)
|
|
||||||
|
|
||||||
static void
|
|
||||||
ble_store_config_serialize_arr(const void *arr, int obj_sz, int num_objs,
|
|
||||||
char *out_buf, int buf_sz)
|
|
||||||
{
|
|
||||||
int arr_size;
|
|
||||||
|
|
||||||
arr_size = obj_sz * num_objs;
|
|
||||||
assert(arr_size <= buf_sz);
|
|
||||||
|
|
||||||
base64_encode(arr, arr_size, out_buf, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
ble_store_config_deserialize_arr(const char *enc,
|
|
||||||
void *out_arr,
|
|
||||||
int obj_sz,
|
|
||||||
int *out_num_objs)
|
|
||||||
{
|
|
||||||
int len;
|
|
||||||
|
|
||||||
len = base64_decode(enc, out_arr);
|
|
||||||
if (len < 0) {
|
|
||||||
return OS_EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_num_objs = len / obj_sz;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
ble_store_config_conf_set(int argc, char **argv, char *val)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (argc == 1) {
|
|
||||||
if (strcmp(argv[0], "our_sec") == 0) {
|
|
||||||
rc = ble_store_config_deserialize_arr(
|
|
||||||
val,
|
|
||||||
ble_store_config_our_secs,
|
|
||||||
sizeof *ble_store_config_our_secs,
|
|
||||||
&ble_store_config_num_our_secs);
|
|
||||||
return rc;
|
|
||||||
} else if (strcmp(argv[0], "peer_sec") == 0) {
|
|
||||||
rc = ble_store_config_deserialize_arr(
|
|
||||||
val,
|
|
||||||
ble_store_config_peer_secs,
|
|
||||||
sizeof *ble_store_config_peer_secs,
|
|
||||||
&ble_store_config_num_peer_secs);
|
|
||||||
return rc;
|
|
||||||
} else if (strcmp(argv[0], "cccd") == 0) {
|
|
||||||
rc = ble_store_config_deserialize_arr(
|
|
||||||
val,
|
|
||||||
ble_store_config_cccds,
|
|
||||||
sizeof *ble_store_config_cccds,
|
|
||||||
&ble_store_config_num_cccds);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return OS_ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
ble_store_config_conf_export(void (*func)(char *name, char *val),
|
|
||||||
enum conf_export_tgt tgt)
|
|
||||||
{
|
|
||||||
union {
|
|
||||||
char sec[BLE_STORE_CONFIG_SEC_SET_ENCODE_SZ];
|
|
||||||
char cccd[BLE_STORE_CONFIG_CCCD_SET_ENCODE_SZ];
|
|
||||||
} buf;
|
|
||||||
|
|
||||||
ble_store_config_serialize_arr(ble_store_config_our_secs,
|
|
||||||
sizeof *ble_store_config_our_secs,
|
|
||||||
ble_store_config_num_our_secs,
|
|
||||||
buf.sec,
|
|
||||||
sizeof buf.sec);
|
|
||||||
func("ble_hs/our_sec", buf.sec);
|
|
||||||
|
|
||||||
ble_store_config_serialize_arr(ble_store_config_peer_secs,
|
|
||||||
sizeof *ble_store_config_peer_secs,
|
|
||||||
ble_store_config_num_peer_secs,
|
|
||||||
buf.sec,
|
|
||||||
sizeof buf.sec);
|
|
||||||
func("ble_hs/peer_sec", buf.sec);
|
|
||||||
|
|
||||||
ble_store_config_serialize_arr(ble_store_config_cccds,
|
|
||||||
sizeof *ble_store_config_cccds,
|
|
||||||
ble_store_config_num_cccds,
|
|
||||||
buf.cccd,
|
|
||||||
sizeof buf.cccd);
|
|
||||||
func("ble_hs/cccd", buf.cccd);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
ble_store_config_persist_sec_set(const char *setting_name,
|
|
||||||
const struct ble_store_value_sec *secs,
|
|
||||||
int num_secs)
|
|
||||||
{
|
|
||||||
char buf[BLE_STORE_CONFIG_SEC_SET_ENCODE_SZ];
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
ble_store_config_serialize_arr(secs, sizeof *secs, num_secs,
|
|
||||||
buf, sizeof buf);
|
|
||||||
rc = conf_save_one(setting_name, buf);
|
|
||||||
if (rc != 0) {
|
|
||||||
return BLE_HS_ESTORE_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ble_store_config_persist_our_secs(void)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
rc = ble_store_config_persist_sec_set("ble_hs/our_sec",
|
|
||||||
ble_store_config_our_secs,
|
|
||||||
ble_store_config_num_our_secs);
|
|
||||||
if (rc != 0) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ble_store_config_persist_peer_secs(void)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
rc = ble_store_config_persist_sec_set("ble_hs/peer_sec",
|
|
||||||
ble_store_config_peer_secs,
|
|
||||||
ble_store_config_num_peer_secs);
|
|
||||||
if (rc != 0) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ble_store_config_persist_cccds(void)
|
|
||||||
{
|
|
||||||
char buf[BLE_STORE_CONFIG_CCCD_SET_ENCODE_SZ];
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
ble_store_config_serialize_arr(ble_store_config_cccds,
|
|
||||||
sizeof *ble_store_config_cccds,
|
|
||||||
ble_store_config_num_cccds,
|
|
||||||
buf,
|
|
||||||
sizeof buf);
|
|
||||||
rc = conf_save_one("ble_hs/cccd", buf);
|
|
||||||
if (rc != 0) {
|
|
||||||
return BLE_HS_ESTORE_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ble_store_config_conf_init(void)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
rc = conf_register(&ble_store_config_conf_handler);
|
|
||||||
SYSINIT_PANIC_ASSERT_MSG(rc == 0,
|
|
||||||
"Failed to register ble_store_config conf");
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* MYNEWT_VAL(BLE_STORE_CONFIG_PERSIST) */
|
|
|
@ -1,27 +0,0 @@
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
syscfg.defs:
|
|
||||||
BLE_STORE_CONFIG_PERSIST:
|
|
||||||
description: >
|
|
||||||
Whether to save data to sys/config, or just keep it in RAM.
|
|
||||||
value: 1
|
|
||||||
BLE_STORE_SYSINIT_STAGE:
|
|
||||||
description: >
|
|
||||||
Sysinit stage for BLE host store.
|
|
||||||
value: 500
|
|
|
@ -1,37 +0,0 @@
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
pkg.name: nimble/host/store/ram
|
|
||||||
pkg.description: >
|
|
||||||
DEPRECATED; for a RAM-only BLE store, use store/config and set
|
|
||||||
BLE_STORE_CONFIG_PERSIST to 0. RAM-based persistence layer for the NimBLE
|
|
||||||
host.
|
|
||||||
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
|
||||||
pkg.homepage: "http://mynewt.apache.org/"
|
|
||||||
pkg.keywords:
|
|
||||||
- ble
|
|
||||||
- bluetooth
|
|
||||||
- nimble
|
|
||||||
- persistence
|
|
||||||
|
|
||||||
pkg.deps:
|
|
||||||
- nimble/host
|
|
||||||
|
|
||||||
pkg.init:
|
|
||||||
ble_store_ram_init: 'MYNEWT_VAL(BLE_STORE_RAM_SYSINIT_STAGE)'
|
|
|
@ -1,23 +0,0 @@
|
||||||
# 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.
|
|
||||||
|
|
||||||
syscfg.defs:
|
|
||||||
BLE_STORE_RAM_SYSINIT_STAGE:
|
|
||||||
description: >
|
|
||||||
Sysinit stage for the RAM BLE store.
|
|
||||||
value: 500
|
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
pkg.name: nimble/host/util
|
|
||||||
pkg.description: Supplementary utilities for the NimBLE host
|
|
||||||
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
|
||||||
pkg.homepage: "http://mynewt.apache.org/"
|
|
||||||
pkg.keywords:
|
|
||||||
- ble
|
|
||||||
- bluetooth
|
|
||||||
|
|
||||||
pkg.deps:
|
|
||||||
- nimble/host
|
|
|
@ -1,19 +0,0 @@
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
syscfg.defs:
|
|
|
@ -9,27 +9,27 @@
|
||||||
/* Detect if using ESP-IDF or Arduino (Arduino won't have these defines in sdkconfig)*/
|
/* 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_BT_NIMBLE_TASK_STACK_SIZE) || defined(CONFIG_NIMBLE_TASK_STACK_SIZE)
|
||||||
|
|
||||||
#if defined(CONFIG_NIMBLE_ENABLED)
|
#if defined(CONFIG_NIMBLE_ENABLED) && !defined(CONFIG_BT_NIMBLE_ENABLED)
|
||||||
#define CONFIG_BT_NIMBLE_ENABLED
|
#define CONFIG_BT_NIMBLE_ENABLED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_NIMBLE_ROLE_OBSERVER)
|
#if defined(CONFIG_NIMBLE_ROLE_OBSERVER) && !defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||||
#define CONFIG_BT_NIMBLE_ROLE_OBSERVER
|
#define CONFIG_BT_NIMBLE_ROLE_OBSERVER
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_NIMBLE_ROLE_BROADCASTER)
|
#if defined(CONFIG_NIMBLE_ROLE_BROADCASTER) && !defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||||
#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER
|
#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_NIMBLE_ROLE_CENTRAL)
|
#if defined(CONFIG_NIMBLE_ROLE_CENTRAL) && !defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||||
#define CONFIG_BT_NIMBLE_ROLE_CENTRAL
|
#define CONFIG_BT_NIMBLE_ROLE_CENTRAL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_NIMBLE_ROLE_PERIPHERAL)
|
#if defined(CONFIG_NIMBLE_ROLE_PERIPHERAL) && !defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
#define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
|
#define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_NIMBLE_DEBUG)
|
#if defined(CONFIG_NIMBLE_DEBUG) && !defined(CONFIG_BT_NIMBLE_DEBUG)
|
||||||
#define CONFIG_BT_NIMBLE_DEBUG
|
#define CONFIG_BT_NIMBLE_DEBUG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -52,12 +52,12 @@
|
||||||
/** Comment out if not using NimBLE Server functions
|
/** Comment out if not using NimBLE Server functions
|
||||||
* Reduces flash size by approx. 16kB.
|
* Reduces flash size by approx. 16kB.
|
||||||
*/
|
*/
|
||||||
// #define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL // Tasmota
|
// #define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
|
||||||
|
|
||||||
/** Comment out if not using NimBLE Advertising functions
|
/** Comment out if not using NimBLE Advertising functions
|
||||||
* Reduces flash size by approx. 5kB.
|
* Reduces flash size by approx. 5kB.
|
||||||
*/
|
*/
|
||||||
// #define CONFIG_BT_NIMBLE_ROLE_BROADCASTER // Tasmota
|
// #define CONFIG_BT_NIMBLE_ROLE_BROADCASTER
|
||||||
|
|
||||||
/** Uncomment to see debug log messages from the NimBLE host
|
/** Uncomment to see debug log messages from the NimBLE host
|
||||||
* Uses approx. 32kB of flash memory.
|
* Uses approx. 32kB of flash memory.
|
||||||
|
@ -89,12 +89,12 @@
|
||||||
#define CONFIG_BT_NIMBLE_MAX_CONNECTIONS 3
|
#define CONFIG_BT_NIMBLE_MAX_CONNECTIONS 3
|
||||||
|
|
||||||
/** Sets the number of devices allowed to store/bond with */
|
/** Sets the number of devices allowed to store/bond with */
|
||||||
#define CONFIG_BT_NIMBLE_MAX_BONDS 3 // Tasmota
|
#define CONFIG_BT_NIMBLE_MAX_BONDS 3
|
||||||
|
|
||||||
/** Sets the number of CCCD's to store per bonded device */
|
/** Sets the number of CCCD's to store per bonded device */
|
||||||
#define CONFIG_BT_NIMBLE_MAX_CCCDS 3 // Tasmota
|
#define CONFIG_BT_NIMBLE_MAX_CCCDS 8
|
||||||
|
|
||||||
#define CONFIG_BT_NIMBLE_NVS_PERSIST 0 // Tasmota
|
#define CONFIG_BT_NIMBLE_NVS_PERSIST 0
|
||||||
#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"
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
NIMBLE_CFLAGS += \
|
|
||||||
-DNIMBLE_CFG_CONTROLLER=1 \
|
|
||||||
|
|
||||||
NIMBLE_INCLUDE += \
|
|
||||||
$(NIMBLE_ROOT)/nimble/transport/ram/include \
|
|
||||||
$(NIMBLE_ROOT)/nimble/controller/include \
|
|
||||||
$(NIMBLE_ROOT)/nimble/drivers/nrf52/include \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
NIMBLE_SRC += \
|
|
||||||
$(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/nimble/transport/ram/src/*.c)) \
|
|
||||||
$(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/nimble/controller/src/*.c)) \
|
|
||||||
$(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/nimble/drivers/nrf52/src/*.c)) \
|
|
||||||
$(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/porting/nimble/controller/src/*.c)) \
|
|
||||||
$(NULL)
|
|
|
@ -1,68 +0,0 @@
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
ifeq (,$(NIMBLE_ROOT))
|
|
||||||
$(error NIMBLE_ROOT shall be defined)
|
|
||||||
endif
|
|
||||||
|
|
||||||
NIMBLE_CFLAGS :=
|
|
||||||
|
|
||||||
NIMBLE_INCLUDE := \
|
|
||||||
$(NIMBLE_ROOT)/nimble/include \
|
|
||||||
$(NIMBLE_ROOT)/nimble/host/include \
|
|
||||||
$(NIMBLE_ROOT)/nimble/host/services/ans/include \
|
|
||||||
$(NIMBLE_ROOT)/nimble/host/services/bas/include \
|
|
||||||
$(NIMBLE_ROOT)/nimble/host/services/bleuart/include \
|
|
||||||
$(NIMBLE_ROOT)/nimble/host/services/gap/include \
|
|
||||||
$(NIMBLE_ROOT)/nimble/host/services/gatt/include \
|
|
||||||
$(NIMBLE_ROOT)/nimble/host/services/ias/include \
|
|
||||||
$(NIMBLE_ROOT)/nimble/host/services/lls/include \
|
|
||||||
$(NIMBLE_ROOT)/nimble/host/services/tps/include \
|
|
||||||
$(NIMBLE_ROOT)/nimble/host/store/ram/include \
|
|
||||||
$(NIMBLE_ROOT)/nimble/host/util/include \
|
|
||||||
$(NIMBLE_ROOT)/porting/nimble/include \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
NIMBLE_SRC := \
|
|
||||||
$(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/porting/nimble/src/*.c)) \
|
|
||||||
$(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/nimble/src/*.c)) \
|
|
||||||
$(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/nimble/host/src/*.c)) \
|
|
||||||
$(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/nimble/host/util/src/*.c)) \
|
|
||||||
$(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/nimble/host/services/ans/src/*.c)) \
|
|
||||||
$(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/nimble/host/services/bas/src/*.c)) \
|
|
||||||
$(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/nimble/host/services/gap/src/*.c)) \
|
|
||||||
$(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/nimble/host/services/gatt/src/*.c)) \
|
|
||||||
$(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/nimble/host/services/ias/src/*.c)) \
|
|
||||||
$(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/nimble/host/services/lls/src/*.c)) \
|
|
||||||
$(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/nimble/host/services/tps/src/*.c)) \
|
|
||||||
$(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/nimble/host/store/ram/src/*.c)) \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
ifneq (,$(NIMBLE_CFG_CONTROLLER))
|
|
||||||
include $(NIMBLE_ROOT)/porting/nimble/Makefile.controller
|
|
||||||
endif
|
|
||||||
|
|
||||||
# TinyCrypt (for SM)
|
|
||||||
ifneq (,$(NIMBLE_CFG_TINYCRYPT))
|
|
||||||
include $(NIMBLE_ROOT)/porting/nimble/Makefile.tinycrypt
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifneq (,$(NIMBLE_CFG_MESH))
|
|
||||||
include $(NIMBLE_ROOT)/porting/nimble/Makefile.mesh
|
|
||||||
endif
|
|
||||||
|
|
||||||
NIMBLE_OBJ := $(NIMBLE_SRC:.c=.o)
|
|
|
@ -1,24 +0,0 @@
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
NIMBLE_INCLUDE += \
|
|
||||||
$(NIMBLE_ROOT)/nimble/host/mesh/include \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
NIMBLE_SRC += \
|
|
||||||
$(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/nimble/host/mesh/src/*.c)) \
|
|
||||||
$(NULL)
|
|
|
@ -1,26 +0,0 @@
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
TINYCRYPT_CFLAGS := -std=c99
|
|
||||||
|
|
||||||
TINYCRYPT_INCLUDE := \
|
|
||||||
$(NIMBLE_ROOT)/ext/tinycrypt/include \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
TINYCRYPT_SRC := \
|
|
||||||
$(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/ext/tinycrypt/src/*.c)) \
|
|
||||||
$(NULL)
|
|
|
@ -1,43 +0,0 @@
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
pkg.name: porting/nimble
|
|
||||||
pkg.type: app
|
|
||||||
pkg.description: Stub for NimBLE porting
|
|
||||||
pkg.author: "Apache Mynewt <dev@mynewt.incubator.apache.org>"
|
|
||||||
pkg.homepage: "http://mynewt.apache.org/"
|
|
||||||
pkg.keywords:
|
|
||||||
|
|
||||||
pkg.deps:
|
|
||||||
- nimble/host
|
|
||||||
- nimble/host/services/ans
|
|
||||||
- nimble/host/services/bas
|
|
||||||
- nimble/host/services/gap
|
|
||||||
- nimble/host/services/gatt
|
|
||||||
- nimble/host/services/ias
|
|
||||||
- nimble/host/services/lls
|
|
||||||
- nimble/host/services/tps
|
|
||||||
- nimble/transport
|
|
||||||
- "@apache-mynewt-core/sys/console/stub"
|
|
||||||
- "@apache-mynewt-core/sys/log/stub"
|
|
||||||
- "@apache-mynewt-core/sys/stats/stub"
|
|
||||||
|
|
||||||
# No need to build files from this package
|
|
||||||
pkg.ign_files:
|
|
||||||
- ".*\\.c"
|
|
|
@ -385,7 +385,10 @@ os_mbuf_append(struct os_mbuf *om, const void *data, uint16_t len)
|
||||||
memcpy(OS_MBUF_DATA(last, uint8_t *) + last->om_len , data, space);
|
memcpy(OS_MBUF_DATA(last, uint8_t *) + last->om_len , data, space);
|
||||||
|
|
||||||
last->om_len += space;
|
last->om_len += space;
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wpointer-arith"
|
||||||
data += space;
|
data += space;
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
remainder -= space;
|
remainder -= space;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,7 +403,10 @@ os_mbuf_append(struct os_mbuf *om, const void *data, uint16_t len)
|
||||||
|
|
||||||
new->om_len = min(omp->omp_databuf_len, remainder);
|
new->om_len = min(omp->omp_databuf_len, remainder);
|
||||||
memcpy(OS_MBUF_DATA(new, void *), data, new->om_len);
|
memcpy(OS_MBUF_DATA(new, void *), data, new->om_len);
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wpointer-arith"
|
||||||
data += new->om_len;
|
data += new->om_len;
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
remainder -= new->om_len;
|
remainder -= new->om_len;
|
||||||
SLIST_NEXT(last, om_next) = new;
|
SLIST_NEXT(last, om_next) = new;
|
||||||
last = new;
|
last = new;
|
||||||
|
@ -651,7 +657,10 @@ os_mbuf_cmpf(const struct os_mbuf *om, int off, const void *data, int len)
|
||||||
|
|
||||||
chunk_sz = min(om->om_len - om_off, len - data_off);
|
chunk_sz = min(om->om_len - om_off, len - data_off);
|
||||||
if (chunk_sz > 0) {
|
if (chunk_sz > 0) {
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wpointer-arith"
|
||||||
rc = memcmp(om->om_data + om_off, data + data_off, chunk_sz);
|
rc = memcmp(om->om_data + om_off, data + data_off, chunk_sz);
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_BLE_SVC_IPSS_
|
||||||
|
#define H_BLE_SVC_IPSS_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BLE_SVC_IPSS_UUID16 0x1820
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the IPSS service
|
||||||
|
*/
|
||||||
|
void ble_svc_ipss_init(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
--------------------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------------------
|
||||||
Version yyyymmdd Action Description
|
Version yyyymmdd Action Description
|
||||||
--------------------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------------------
|
||||||
|
0.9.0.1 20200706 changed - adapt to new NimBLE-API, tweak scan process
|
||||||
0.9.0.0 20200413 started - initial development by Christian Baars
|
0.9.0.0 20200413 started - initial development by Christian Baars
|
||||||
forked - from arendst/tasmota - https://github.com/arendst/Tasmota
|
forked - from arendst/tasmota - https://github.com/arendst/Tasmota
|
||||||
|
|
||||||
|
@ -232,7 +233,6 @@ class MI32AdvCallbacks: public NimBLEAdvertisedDeviceCallbacks {
|
||||||
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Advertised Device: %s Buffer: %u"),advertisedDevice->getAddress().toString().c_str(),advertisedDevice->getServiceData().length());
|
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Advertised Device: %s Buffer: %u"),advertisedDevice->getAddress().toString().c_str(),advertisedDevice->getServiceData().length());
|
||||||
if (advertisedDevice->getServiceData().length() == 0) {
|
if (advertisedDevice->getServiceData().length() == 0) {
|
||||||
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("No Xiaomi Device: %s Buffer: %u"),advertisedDevice->getAddress().toString().c_str(),advertisedDevice->getServiceData().length());
|
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("No Xiaomi Device: %s Buffer: %u"),advertisedDevice->getAddress().toString().c_str(),advertisedDevice->getServiceData().length());
|
||||||
MI32Scan->erase(advertisedDevice->getAddress());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint16_t uuid = advertisedDevice->getServiceDataUUID().getNative()->u16.value;
|
uint16_t uuid = advertisedDevice->getServiceDataUUID().getNative()->u16.value;
|
||||||
|
@ -242,13 +242,14 @@ class MI32AdvCallbacks: public NimBLEAdvertisedDeviceCallbacks {
|
||||||
MI32_ReverseMAC(addr);
|
MI32_ReverseMAC(addr);
|
||||||
if(uuid==0xfe95) {
|
if(uuid==0xfe95) {
|
||||||
MI32ParseResponse((char*)advertisedDevice->getServiceData().data(),advertisedDevice->getServiceData().length(), addr);
|
MI32ParseResponse((char*)advertisedDevice->getServiceData().data(),advertisedDevice->getServiceData().length(), addr);
|
||||||
|
MI32Scan->erase(advertisedDevice->getAddress());
|
||||||
}
|
}
|
||||||
else if(uuid==0xfdcd) {
|
else if(uuid==0xfdcd) {
|
||||||
MI32parseCGD1Packet((char*)advertisedDevice->getServiceData().data(),advertisedDevice->getServiceData().length(), addr);
|
MI32parseCGD1Packet((char*)advertisedDevice->getServiceData().data(),advertisedDevice->getServiceData().length(), addr);
|
||||||
|
MI32Scan->erase(advertisedDevice->getAddress());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("No Xiaomi Device: %s Buffer: %u"),advertisedDevice->getAddress().toString().c_str(),advertisedDevice->getServiceData().length());
|
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("No Xiaomi Device: %s Buffer: %u"),advertisedDevice->getAddress().toString().c_str(),advertisedDevice->getServiceData().length());
|
||||||
MI32Scan->erase(advertisedDevice->getAddress());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -551,7 +552,7 @@ bool MI32connectLYWSD03forNotification(){
|
||||||
}
|
}
|
||||||
if (pChr){
|
if (pChr){
|
||||||
if(pChr->canNotify()) {
|
if(pChr->canNotify()) {
|
||||||
if(pChr->registerForNotify(MI32notifyCB)) {
|
if(pChr->subscribe(true,false,MI32notifyCB)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue