mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-28 05:06:32 +00:00
NimBLE release 1.1.0
This commit is contained in:
parent
5284d5f4f7
commit
688c0b1a9f
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
## [Unreleased]
|
## [1.1.0] - 2021-01-20
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- `NimBLEDevice::setOwnAddrType` added to enable the use of random and random-resolvable addresses, by asukiaaa
|
- `NimBLEDevice::setOwnAddrType` added to enable the use of random and random-resolvable addresses, by asukiaaa
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
[Latest release 
|
[Latest release 
|
||||||
](https://github.com/h2zero/NimBLE-Arduino/releases/latest/)
|
](https://github.com/h2zero/NimBLE-Arduino/releases/latest/)
|
||||||
|
|
||||||
|
Need help? Have questions or suggestions? Join the [](https://gitter.im/NimBLE-Arduino/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
# NimBLE-Arduino
|
# NimBLE-Arduino
|
||||||
@ -57,6 +59,8 @@ Also see [Improvements_and_updates](docs/Improvements_and_updates.md) for inform
|
|||||||
|
|
||||||
[Full API documentation and class list can be found here.](https://h2zero.github.io/esp-nimble-cpp/)
|
[Full API documentation and class list can be found here.](https://h2zero.github.io/esp-nimble-cpp/)
|
||||||
|
|
||||||
|
For added performance and optimizations see [Usage tips](docs/Usage_tips.md).
|
||||||
|
|
||||||
Check the Refactored_original_examples in the examples folder for highlights of the differences with the original library.
|
Check the Refactored_original_examples in the examples folder for highlights of the differences with the original library.
|
||||||
|
|
||||||
More advanced examples highlighting many available features are in examples/ NimBLE_Server, NimBLE_Client.
|
More advanced examples highlighting many available features are in examples/ NimBLE_Server, NimBLE_Client.
|
||||||
|
@ -79,27 +79,24 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *payLoad = advertisedDevice->getPayload();
|
BLEUUID eddyUUID = (uint16_t)0xfeaa;
|
||||||
|
|
||||||
BLEUUID checkUrlUUID = (uint16_t)0xfeaa;
|
if (advertisedDevice->getServiceUUID().equals(eddyUUID))
|
||||||
|
|
||||||
if (advertisedDevice->getServiceUUID().equals(checkUrlUUID))
|
|
||||||
{
|
{
|
||||||
if (payLoad[11] == 0x10)
|
std::string serviceData = advertisedDevice->getServiceData(eddyUUID);
|
||||||
|
if (serviceData[0] == 0x10)
|
||||||
{
|
{
|
||||||
Serial.println("Found an EddystoneURL beacon!");
|
Serial.println("Found an EddystoneURL beacon!");
|
||||||
BLEEddystoneURL foundEddyURL = BLEEddystoneURL();
|
BLEEddystoneURL foundEddyURL = BLEEddystoneURL();
|
||||||
std::string eddyContent((char *)&payLoad[11]); // incomplete EddystoneURL struct!
|
|
||||||
|
|
||||||
foundEddyURL.setData(eddyContent);
|
foundEddyURL.setData(serviceData);
|
||||||
std::string bareURL = foundEddyURL.getURL();
|
std::string bareURL = foundEddyURL.getURL();
|
||||||
if (bareURL[0] == 0x00)
|
if (bareURL[0] == 0x00)
|
||||||
{
|
{
|
||||||
size_t payLoadLen = advertisedDevice->getPayloadLength();
|
|
||||||
Serial.println("DATA-->");
|
Serial.println("DATA-->");
|
||||||
for (int idx = 0; idx < payLoadLen; idx++)
|
for (int idx = 0; idx < serviceData.length(); idx++)
|
||||||
{
|
{
|
||||||
Serial.printf("0x%08X ", payLoad[idx]);
|
Serial.printf("0x%08X ", serviceData[idx]);
|
||||||
}
|
}
|
||||||
Serial.println("\nInvalid Data");
|
Serial.println("\nInvalid Data");
|
||||||
return;
|
return;
|
||||||
@ -110,23 +107,15 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
|
|||||||
Serial.printf("TX power %d\n", foundEddyURL.getPower());
|
Serial.printf("TX power %d\n", foundEddyURL.getPower());
|
||||||
Serial.println("\n");
|
Serial.println("\n");
|
||||||
}
|
}
|
||||||
else if (payLoad[11] == 0x20)
|
else if (serviceData[0] == 0x20)
|
||||||
{
|
{
|
||||||
Serial.println("Found an EddystoneTLM beacon!");
|
Serial.println("Found an EddystoneTLM beacon!");
|
||||||
BLEEddystoneTLM foundEddyURL = BLEEddystoneTLM();
|
BLEEddystoneTLM foundEddyURL = BLEEddystoneTLM();
|
||||||
std::string eddyContent((char *)&payLoad[11]); // incomplete EddystoneURL struct!
|
foundEddyURL.setData(serviceData);
|
||||||
|
|
||||||
eddyContent = "01234567890123";
|
|
||||||
|
|
||||||
for (int idx = 0; idx < 14; idx++)
|
|
||||||
{
|
|
||||||
eddyContent[idx] = payLoad[idx + 11];
|
|
||||||
}
|
|
||||||
|
|
||||||
foundEddyURL.setData(eddyContent);
|
|
||||||
Serial.printf("Reported battery voltage: %dmV\n", foundEddyURL.getVolt());
|
Serial.printf("Reported battery voltage: %dmV\n", foundEddyURL.getVolt());
|
||||||
Serial.printf("Reported temperature from TLM class: %.2fC\n", (double)foundEddyURL.getTemp());
|
Serial.printf("Reported temperature from TLM class: %.2fC\n", (double)foundEddyURL.getTemp());
|
||||||
int temp = (int)payLoad[16] + (int)(payLoad[15] << 8);
|
int temp = (int)serviceData[5] + (int)(serviceData[4] << 8);
|
||||||
float calcTemp = temp / 256.0f;
|
float calcTemp = temp / 256.0f;
|
||||||
Serial.printf("Reported temperature from data: %.2fC\n", calcTemp);
|
Serial.printf("Reported temperature from data: %.2fC\n", calcTemp);
|
||||||
Serial.printf("Reported advertise count: %d\n", foundEddyURL.getCount());
|
Serial.printf("Reported advertise count: %d\n", foundEddyURL.getCount());
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
/** NimBLE_Server Demo:
|
/** NimBLE_Server Demo:
|
||||||
*
|
*
|
||||||
* Demonstrates many of the available features of the NimBLE client library.
|
* Demonstrates many of the available features of the NimBLE client library.
|
||||||
*
|
*
|
||||||
* Created: on March 24 2020
|
* Created: on March 24 2020
|
||||||
* Author: H2zero
|
* Author: H2zero
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <NimBLEDevice.h>
|
#include <NimBLEDevice.h>
|
||||||
@ -19,15 +19,15 @@ static uint32_t scanTime = 0; /** 0 = scan forever */
|
|||||||
|
|
||||||
|
|
||||||
/** None of these are required as they will be handled by the library with defaults. **
|
/** None of these are required as they will be handled by the library with defaults. **
|
||||||
** Remove as you see fit for your needs */
|
** Remove as you see fit for your needs */
|
||||||
class ClientCallbacks : public NimBLEClientCallbacks {
|
class ClientCallbacks : public NimBLEClientCallbacks {
|
||||||
void onConnect(NimBLEClient* pClient) {
|
void onConnect(NimBLEClient* pClient) {
|
||||||
Serial.println("Connected");
|
Serial.println("Connected");
|
||||||
/** After connection we should change the parameters if we don't need fast response times.
|
/** After connection we should change the parameters if we don't need fast response times.
|
||||||
* These settings are 150ms interval, 0 latency, 450ms timout.
|
* These settings are 150ms interval, 0 latency, 450ms timout.
|
||||||
* Timeout should be a multiple of the interval, minimum is 100ms.
|
* Timeout should be a multiple of the interval, minimum is 100ms.
|
||||||
* I find a multiple of 3-5 * the interval works best for quick response/reconnect.
|
* I find a multiple of 3-5 * the interval works best for quick response/reconnect.
|
||||||
* Min interval: 120 * 1.25ms = 150, Max interval: 120 * 1.25ms = 150, 0 latency, 60 * 10ms = 600ms timeout
|
* Min interval: 120 * 1.25ms = 150, Max interval: 120 * 1.25ms = 150, 0 latency, 60 * 10ms = 600ms timeout
|
||||||
*/
|
*/
|
||||||
pClient->updateConnParams(120,120,0,60);
|
pClient->updateConnParams(120,120,0,60);
|
||||||
};
|
};
|
||||||
@ -37,9 +37,9 @@ class ClientCallbacks : public NimBLEClientCallbacks {
|
|||||||
Serial.println(" Disconnected - Starting scan");
|
Serial.println(" Disconnected - Starting scan");
|
||||||
NimBLEDevice::getScan()->start(scanTime, scanEndedCB);
|
NimBLEDevice::getScan()->start(scanTime, scanEndedCB);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Called when the peripheral requests a change to the connection parameters.
|
/** Called when the peripheral requests a change to the connection parameters.
|
||||||
* Return true to accept and apply them or false to reject and keep
|
* Return true to accept and apply them or false to reject and keep
|
||||||
* the currently used parameters. Default will return true.
|
* the currently used parameters. Default will return true.
|
||||||
*/
|
*/
|
||||||
bool onConnParamsUpdateRequest(NimBLEClient* pClient, const ble_gap_upd_params* params) {
|
bool onConnParamsUpdateRequest(NimBLEClient* pClient, const ble_gap_upd_params* params) {
|
||||||
@ -55,7 +55,7 @@ class ClientCallbacks : public NimBLEClientCallbacks {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
/********************* Security handled here **********************
|
/********************* Security handled here **********************
|
||||||
****** Note: these are the same return values as defaults ********/
|
****** Note: these are the same return values as defaults ********/
|
||||||
uint32_t onPassKeyRequest(){
|
uint32_t onPassKeyRequest(){
|
||||||
@ -85,7 +85,7 @@ class ClientCallbacks : public NimBLEClientCallbacks {
|
|||||||
|
|
||||||
/** Define a class to handle the callbacks when advertisments are received */
|
/** Define a class to handle the callbacks when advertisments are received */
|
||||||
class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks {
|
class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks {
|
||||||
|
|
||||||
void onResult(NimBLEAdvertisedDevice* advertisedDevice) {
|
void onResult(NimBLEAdvertisedDevice* advertisedDevice) {
|
||||||
Serial.print("Advertised Device found: ");
|
Serial.print("Advertised Device found: ");
|
||||||
Serial.println(advertisedDevice->toString().c_str());
|
Serial.println(advertisedDevice->toString().c_str());
|
||||||
@ -94,9 +94,9 @@ class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks {
|
|||||||
Serial.println("Found Our Service");
|
Serial.println("Found Our Service");
|
||||||
/** stop scan before connecting */
|
/** stop scan before connecting */
|
||||||
NimBLEDevice::getScan()->stop();
|
NimBLEDevice::getScan()->stop();
|
||||||
/** Save the device reference in a global for the client to use*/
|
/** Save the device reference in a global for the client to use*/
|
||||||
advDevice = advertisedDevice;
|
advDevice = advertisedDevice;
|
||||||
/** Ready to connect now */
|
/** Ready to connect now */
|
||||||
doConnect = true;
|
doConnect = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -105,7 +105,7 @@ class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks {
|
|||||||
|
|
||||||
/** Notification / Indication receiving handler callback */
|
/** Notification / Indication receiving handler callback */
|
||||||
void notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify){
|
void notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify){
|
||||||
std::string str = (isNotify == true) ? "Notification" : "Indication";
|
std::string str = (isNotify == true) ? "Notification" : "Indication";
|
||||||
str += " from ";
|
str += " from ";
|
||||||
/** NimBLEAddress and NimBLEUUID have std::string operators */
|
/** NimBLEAddress and NimBLEUUID have std::string operators */
|
||||||
str += std::string(pRemoteCharacteristic->getRemoteService()->getClient()->getPeerAddress());
|
str += std::string(pRemoteCharacteristic->getRemoteService()->getClient()->getPeerAddress());
|
||||||
@ -128,10 +128,10 @@ static ClientCallbacks clientCB;
|
|||||||
/** Handles the provisioning of clients and connects / interfaces with the server */
|
/** Handles the provisioning of clients and connects / interfaces with the server */
|
||||||
bool connectToServer() {
|
bool connectToServer() {
|
||||||
NimBLEClient* pClient = nullptr;
|
NimBLEClient* pClient = nullptr;
|
||||||
|
|
||||||
/** Check if we have a client we should reuse first **/
|
/** Check if we have a client we should reuse first **/
|
||||||
if(NimBLEDevice::getClientListSize()) {
|
if(NimBLEDevice::getClientListSize()) {
|
||||||
/** Special case when we already know this device, we send false as the
|
/** Special case when we already know this device, we send false as the
|
||||||
* second argument in connect() to prevent refreshing the service database.
|
* second argument in connect() to prevent refreshing the service database.
|
||||||
* This saves considerable time and power.
|
* This saves considerable time and power.
|
||||||
*/
|
*/
|
||||||
@ -142,7 +142,7 @@ bool connectToServer() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Serial.println("Reconnected client");
|
Serial.println("Reconnected client");
|
||||||
}
|
}
|
||||||
/** We don't already have a client that knows this device,
|
/** We don't already have a client that knows this device,
|
||||||
* we will check for a client that is disconnected that we can use.
|
* we will check for a client that is disconnected that we can use.
|
||||||
*/
|
*/
|
||||||
@ -150,28 +150,28 @@ bool connectToServer() {
|
|||||||
pClient = NimBLEDevice::getDisconnectedClient();
|
pClient = NimBLEDevice::getDisconnectedClient();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** No client to reuse? Create a new one. */
|
/** No client to reuse? Create a new one. */
|
||||||
if(!pClient) {
|
if(!pClient) {
|
||||||
if(NimBLEDevice::getClientListSize() >= NIMBLE_MAX_CONNECTIONS) {
|
if(NimBLEDevice::getClientListSize() >= NIMBLE_MAX_CONNECTIONS) {
|
||||||
Serial.println("Max clients reached - no more connections available");
|
Serial.println("Max clients reached - no more connections available");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pClient = NimBLEDevice::createClient();
|
pClient = NimBLEDevice::createClient();
|
||||||
|
|
||||||
Serial.println("New client created");
|
Serial.println("New client created");
|
||||||
|
|
||||||
pClient->setClientCallbacks(&clientCB, false);
|
pClient->setClientCallbacks(&clientCB, false);
|
||||||
/** Set initial connection parameters: These settings are 15ms interval, 0 latency, 120ms timout.
|
/** Set initial connection parameters: These settings are 15ms interval, 0 latency, 120ms timout.
|
||||||
* These settings are safe for 3 clients to connect reliably, can go faster if you have less
|
* These settings are safe for 3 clients to connect reliably, can go faster if you have less
|
||||||
* connections. Timeout should be a multiple of the interval, minimum is 100ms.
|
* connections. Timeout should be a multiple of the interval, minimum is 100ms.
|
||||||
* Min interval: 12 * 1.25ms = 15, Max interval: 12 * 1.25ms = 15, 0 latency, 51 * 10ms = 510ms timeout
|
* Min interval: 12 * 1.25ms = 15, Max interval: 12 * 1.25ms = 15, 0 latency, 51 * 10ms = 510ms timeout
|
||||||
*/
|
*/
|
||||||
pClient->setConnectionParams(12,12,0,51);
|
pClient->setConnectionParams(12,12,0,51);
|
||||||
/** Set how long we are willing to wait for the connection to complete (seconds), default is 30. */
|
/** Set how long we are willing to wait for the connection to complete (seconds), default is 30. */
|
||||||
pClient->setConnectTimeout(5);
|
pClient->setConnectTimeout(5);
|
||||||
|
|
||||||
|
|
||||||
if (!pClient->connect(advDevice)) {
|
if (!pClient->connect(advDevice)) {
|
||||||
/** Created a client but failed to connect, don't need to keep it as it has no data */
|
/** Created a client but failed to connect, don't need to keep it as it has no data */
|
||||||
@ -179,149 +179,147 @@ bool connectToServer() {
|
|||||||
Serial.println("Failed to connect, deleted client");
|
Serial.println("Failed to connect, deleted client");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!pClient->isConnected()) {
|
if(!pClient->isConnected()) {
|
||||||
if (!pClient->connect(advDevice)) {
|
if (!pClient->connect(advDevice)) {
|
||||||
Serial.println("Failed to connect");
|
Serial.println("Failed to connect");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.print("Connected to: ");
|
Serial.print("Connected to: ");
|
||||||
Serial.println(pClient->getPeerAddress().toString().c_str());
|
Serial.println(pClient->getPeerAddress().toString().c_str());
|
||||||
Serial.print("RSSI: ");
|
Serial.print("RSSI: ");
|
||||||
Serial.println(pClient->getRssi());
|
Serial.println(pClient->getRssi());
|
||||||
|
|
||||||
/** Now we can read/write/subscribe the charateristics of the services we are interested in */
|
/** Now we can read/write/subscribe the charateristics of the services we are interested in */
|
||||||
NimBLERemoteService* pSvc = nullptr;
|
NimBLERemoteService* pSvc = nullptr;
|
||||||
NimBLERemoteCharacteristic* pChr = nullptr;
|
NimBLERemoteCharacteristic* pChr = nullptr;
|
||||||
NimBLERemoteDescriptor* pDsc = nullptr;
|
NimBLERemoteDescriptor* pDsc = nullptr;
|
||||||
|
|
||||||
pSvc = pClient->getService("DEAD");
|
pSvc = pClient->getService("DEAD");
|
||||||
if(pSvc) { /** make sure it's not null */
|
if(pSvc) { /** make sure it's not null */
|
||||||
pChr = pSvc->getCharacteristic("BEEF");
|
pChr = pSvc->getCharacteristic("BEEF");
|
||||||
}
|
|
||||||
|
|
||||||
if(pChr) { /** make sure it's not null */
|
if(pChr) { /** make sure it's not null */
|
||||||
if(pChr->canRead()) {
|
|
||||||
Serial.print(pChr->getUUID().toString().c_str());
|
|
||||||
Serial.print(" Value: ");
|
|
||||||
Serial.println(pChr->readValue().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pChr->canWrite()) {
|
|
||||||
if(pChr->writeValue("Tasty")) {
|
|
||||||
Serial.print("Wrote new value to: ");
|
|
||||||
Serial.println(pChr->getUUID().toString().c_str());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/** Disconnect if write failed */
|
|
||||||
pClient->disconnect();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pChr->canRead()) {
|
if(pChr->canRead()) {
|
||||||
Serial.print("The value of: ");
|
|
||||||
Serial.print(pChr->getUUID().toString().c_str());
|
Serial.print(pChr->getUUID().toString().c_str());
|
||||||
Serial.print(" is now: ");
|
Serial.print(" Value: ");
|
||||||
Serial.println(pChr->readValue().c_str());
|
Serial.println(pChr->readValue().c_str());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if(pChr->canWrite()) {
|
||||||
/** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
|
if(pChr->writeValue("Tasty")) {
|
||||||
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
|
Serial.print("Wrote new value to: ");
|
||||||
* Unsubscribe parameter defaults are: response=false.
|
Serial.println(pChr->getUUID().toString().c_str());
|
||||||
*/
|
}
|
||||||
if(pChr->canNotify()) {
|
else {
|
||||||
//if(!pChr->registerForNotify(notifyCB)) {
|
/** Disconnect if write failed */
|
||||||
if(!pChr->subscribe(true, notifyCB)) {
|
pClient->disconnect();
|
||||||
/** Disconnect if subscribe failed */
|
return false;
|
||||||
pClient->disconnect();
|
}
|
||||||
return false;
|
|
||||||
|
if(pChr->canRead()) {
|
||||||
|
Serial.print("The value of: ");
|
||||||
|
Serial.print(pChr->getUUID().toString().c_str());
|
||||||
|
Serial.print(" is now: ");
|
||||||
|
Serial.println(pChr->readValue().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
|
||||||
|
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
|
||||||
|
* Unsubscribe parameter defaults are: response=false.
|
||||||
|
*/
|
||||||
|
if(pChr->canNotify()) {
|
||||||
|
//if(!pChr->registerForNotify(notifyCB)) {
|
||||||
|
if(!pChr->subscribe(true, notifyCB)) {
|
||||||
|
/** Disconnect if subscribe failed */
|
||||||
|
pClient->disconnect();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(pChr->canIndicate()) {
|
||||||
|
/** Send false as first argument to subscribe to indications instead of notifications */
|
||||||
|
//if(!pChr->registerForNotify(notifyCB, false)) {
|
||||||
|
if(!pChr->subscribe(false, notifyCB)) {
|
||||||
|
/** Disconnect if subscribe failed */
|
||||||
|
pClient->disconnect();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(pChr->canIndicate()) {
|
|
||||||
/** Send false as first argument to subscribe to indications instead of notifications */
|
} else {
|
||||||
//if(!pChr->registerForNotify(notifyCB, false)) {
|
|
||||||
if(!pChr->subscribe(false, notifyCB)) {
|
|
||||||
/** Disconnect if subscribe failed */
|
|
||||||
pClient->disconnect();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else{
|
|
||||||
Serial.println("DEAD service not found.");
|
Serial.println("DEAD service not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
pSvc = pClient->getService("BAAD");
|
pSvc = pClient->getService("BAAD");
|
||||||
if(pSvc) { /** make sure it's not null */
|
if(pSvc) { /** make sure it's not null */
|
||||||
pChr = pSvc->getCharacteristic("F00D");
|
pChr = pSvc->getCharacteristic("F00D");
|
||||||
}
|
|
||||||
|
|
||||||
if(pChr) { /** make sure it's not null */
|
if(pChr) { /** make sure it's not null */
|
||||||
if(pChr->canRead()) {
|
|
||||||
Serial.print(pChr->getUUID().toString().c_str());
|
|
||||||
Serial.print(" Value: ");
|
|
||||||
Serial.println(pChr->readValue().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
pDsc = pChr->getDescriptor(NimBLEUUID("C01D"));
|
|
||||||
if(pDsc) { /** make sure it's not null */
|
|
||||||
Serial.print("Descriptor: ");
|
|
||||||
Serial.print(pDsc->getUUID().toString().c_str());
|
|
||||||
Serial.print(" Value: ");
|
|
||||||
Serial.println(pDsc->readValue().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pChr->canWrite()) {
|
|
||||||
if(pChr->writeValue("No tip!")) {
|
|
||||||
Serial.print("Wrote new value to: ");
|
|
||||||
Serial.println(pChr->getUUID().toString().c_str());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/** Disconnect if write failed */
|
|
||||||
pClient->disconnect();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pChr->canRead()) {
|
if(pChr->canRead()) {
|
||||||
Serial.print("The value of: ");
|
|
||||||
Serial.print(pChr->getUUID().toString().c_str());
|
Serial.print(pChr->getUUID().toString().c_str());
|
||||||
Serial.print(" is now: ");
|
Serial.print(" Value: ");
|
||||||
Serial.println(pChr->readValue().c_str());
|
Serial.println(pChr->readValue().c_str());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
|
|
||||||
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
|
|
||||||
* Unsubscribe parameter defaults are: response=false.
|
|
||||||
*/
|
|
||||||
if(pChr->canNotify()) {
|
|
||||||
//if(!pChr->registerForNotify(notifyCB)) {
|
|
||||||
if(!pChr->subscribe(true, notifyCB)) {
|
|
||||||
/** Disconnect if subscribe failed */
|
|
||||||
pClient->disconnect();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(pChr->canIndicate()) {
|
|
||||||
/** Send false as first argument to subscribe to indications instead of notifications */
|
|
||||||
//if(!pChr->registerForNotify(notifyCB, false)) {
|
|
||||||
if(!pChr->subscribe(false, notifyCB)) {
|
|
||||||
/** Disconnect if subscribe failed */
|
|
||||||
pClient->disconnect();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else{
|
pDsc = pChr->getDescriptor(NimBLEUUID("C01D"));
|
||||||
|
if(pDsc) { /** make sure it's not null */
|
||||||
|
Serial.print("Descriptor: ");
|
||||||
|
Serial.print(pDsc->getUUID().toString().c_str());
|
||||||
|
Serial.print(" Value: ");
|
||||||
|
Serial.println(pDsc->readValue().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pChr->canWrite()) {
|
||||||
|
if(pChr->writeValue("No tip!")) {
|
||||||
|
Serial.print("Wrote new value to: ");
|
||||||
|
Serial.println(pChr->getUUID().toString().c_str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/** Disconnect if write failed */
|
||||||
|
pClient->disconnect();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pChr->canRead()) {
|
||||||
|
Serial.print("The value of: ");
|
||||||
|
Serial.print(pChr->getUUID().toString().c_str());
|
||||||
|
Serial.print(" is now: ");
|
||||||
|
Serial.println(pChr->readValue().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
|
||||||
|
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
|
||||||
|
* Unsubscribe parameter defaults are: response=false.
|
||||||
|
*/
|
||||||
|
if(pChr->canNotify()) {
|
||||||
|
//if(!pChr->registerForNotify(notifyCB)) {
|
||||||
|
if(!pChr->subscribe(true, notifyCB)) {
|
||||||
|
/** Disconnect if subscribe failed */
|
||||||
|
pClient->disconnect();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(pChr->canIndicate()) {
|
||||||
|
/** Send false as first argument to subscribe to indications instead of notifications */
|
||||||
|
//if(!pChr->registerForNotify(notifyCB, false)) {
|
||||||
|
if(!pChr->subscribe(false, notifyCB)) {
|
||||||
|
/** Disconnect if subscribe failed */
|
||||||
|
pClient->disconnect();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
Serial.println("BAAD service not found.");
|
Serial.println("BAAD service not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.println("Done with this device!");
|
Serial.println("Done with this device!");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -331,7 +329,7 @@ void setup (){
|
|||||||
Serial.println("Starting NimBLE Client");
|
Serial.println("Starting NimBLE Client");
|
||||||
/** Initialize NimBLE, no device name spcified as we are not advertising */
|
/** Initialize NimBLE, no device name spcified as we are not advertising */
|
||||||
NimBLEDevice::init("");
|
NimBLEDevice::init("");
|
||||||
|
|
||||||
/** Set the IO capabilities of the device, each option will trigger a different pairing method.
|
/** Set the IO capabilities of the device, each option will trigger a different pairing method.
|
||||||
* BLE_HS_IO_KEYBOARD_ONLY - Passkey pairing
|
* BLE_HS_IO_KEYBOARD_ONLY - Passkey pairing
|
||||||
* BLE_HS_IO_DISPLAY_YESNO - Numeric comparison pairing
|
* BLE_HS_IO_DISPLAY_YESNO - Numeric comparison pairing
|
||||||
@ -339,37 +337,37 @@ void setup (){
|
|||||||
*/
|
*/
|
||||||
//NimBLEDevice::setSecurityIOCap(BLE_HS_IO_KEYBOARD_ONLY); // use passkey
|
//NimBLEDevice::setSecurityIOCap(BLE_HS_IO_KEYBOARD_ONLY); // use passkey
|
||||||
//NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO); //use numeric comparison
|
//NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO); //use numeric comparison
|
||||||
|
|
||||||
/** 2 different ways to set security - both calls achieve the same result.
|
/** 2 different ways to set security - both calls achieve the same result.
|
||||||
* no bonding, no man in the middle protection, secure connections.
|
* no bonding, no man in the middle protection, secure connections.
|
||||||
*
|
*
|
||||||
* These are the default values, only shown here for demonstration.
|
* These are the default values, only shown here for demonstration.
|
||||||
*/
|
*/
|
||||||
//NimBLEDevice::setSecurityAuth(false, false, true);
|
//NimBLEDevice::setSecurityAuth(false, false, true);
|
||||||
NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC);
|
NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC);
|
||||||
|
|
||||||
/** Optional: set the transmit power, default is 3db */
|
/** Optional: set the transmit power, default is 3db */
|
||||||
NimBLEDevice::setPower(ESP_PWR_LVL_P9); /** +9db */
|
NimBLEDevice::setPower(ESP_PWR_LVL_P9); /** +9db */
|
||||||
|
|
||||||
/** Optional: set any devices you don't want to get advertisments from */
|
/** Optional: set any devices you don't want to get advertisments from */
|
||||||
// NimBLEDevice::addIgnored(NimBLEAddress ("aa:bb:cc:dd:ee:ff"));
|
// NimBLEDevice::addIgnored(NimBLEAddress ("aa:bb:cc:dd:ee:ff"));
|
||||||
|
|
||||||
/** create new scan */
|
/** create new scan */
|
||||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||||
|
|
||||||
/** create a callback that gets called when advertisers are found */
|
/** create a callback that gets called when advertisers are found */
|
||||||
pScan->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallbacks());
|
pScan->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallbacks());
|
||||||
|
|
||||||
/** Set scan interval (how often) and window (how long) in milliseconds */
|
/** Set scan interval (how often) and window (how long) in milliseconds */
|
||||||
pScan->setInterval(45);
|
pScan->setInterval(45);
|
||||||
pScan->setWindow(15);
|
pScan->setWindow(15);
|
||||||
|
|
||||||
/** Active scan will gather scan response data from advertisers
|
/** Active scan will gather scan response data from advertisers
|
||||||
* but will use more energy from both devices
|
* but will use more energy from both devices
|
||||||
*/
|
*/
|
||||||
pScan->setActiveScan(true);
|
pScan->setActiveScan(true);
|
||||||
/** Start scanning for advertisers for the scan time specified (in seconds) 0 = forever
|
/** Start scanning for advertisers for the scan time specified (in seconds) 0 = forever
|
||||||
* Optional callback for when scanning stops.
|
* Optional callback for when scanning stops.
|
||||||
*/
|
*/
|
||||||
pScan->start(scanTime, scanEndedCB);
|
pScan->start(scanTime, scanEndedCB);
|
||||||
}
|
}
|
||||||
@ -380,15 +378,15 @@ void loop (){
|
|||||||
while(!doConnect){
|
while(!doConnect){
|
||||||
delay(1);
|
delay(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
doConnect = false;
|
doConnect = false;
|
||||||
|
|
||||||
/** Found a device we want to connect to, do it now */
|
/** Found a device we want to connect to, do it now */
|
||||||
if(connectToServer()) {
|
if(connectToServer()) {
|
||||||
Serial.println("Success! we should now be getting notifications, scanning for more!");
|
Serial.println("Success! we should now be getting notifications, scanning for more!");
|
||||||
} else {
|
} else {
|
||||||
Serial.println("Failed to connect, starting scan");
|
Serial.println("Failed to connect, starting scan");
|
||||||
}
|
}
|
||||||
|
|
||||||
NimBLEDevice::getScan()->start(scanTime,scanEndedCB);
|
NimBLEDevice::getScan()->start(scanTime,scanEndedCB);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
name=NimBLE-Arduino
|
name=NimBLE-Arduino
|
||||||
version=1.0.2
|
version=1.1.0
|
||||||
author=h2zero
|
author=h2zero
|
||||||
maintainer=h2zero <powellperalta@gmail.com>
|
maintainer=h2zero <powellperalta@gmail.com>
|
||||||
sentence=Bluetooth low energy (BLE) library for arduino-esp32 based on NimBLE.
|
sentence=Bluetooth low energy (BLE) library for arduino-esp32 based on NimBLE.
|
||||||
|
@ -100,9 +100,10 @@ NimBLEClient::~NimBLEClient() {
|
|||||||
* be called to reset the host in the case of a stalled controller.
|
* be called to reset the host in the case of a stalled controller.
|
||||||
*/
|
*/
|
||||||
void NimBLEClient::dcTimerCb(ble_npl_event *event) {
|
void NimBLEClient::dcTimerCb(ble_npl_event *event) {
|
||||||
NimBLEClient *pClient = (NimBLEClient*)event->arg;
|
/* NimBLEClient *pClient = (NimBLEClient*)event->arg;
|
||||||
NIMBLE_LOGC(LOG_TAG, "Timed out disconnecting from %s - resetting host",
|
NIMBLE_LOGC(LOG_TAG, "Timed out disconnecting from %s - resetting host",
|
||||||
std::string(pClient->getPeerAddress()).c_str());
|
std::string(pClient->getPeerAddress()).c_str());
|
||||||
|
*/
|
||||||
ble_hs_sched_reset(BLE_HS_ECONTROLLER);
|
ble_hs_sched_reset(BLE_HS_ECONTROLLER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,25 +183,30 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isConnected() || m_pTaskData != nullptr) {
|
if(isConnected() || m_connEstablished || m_pTaskData != nullptr) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Client busy, connected to %s, id=%d",
|
NIMBLE_LOGE(LOG_TAG, "Client busy, connected to %s, id=%d",
|
||||||
std::string(m_peerAddress).c_str(), getConnId());
|
std::string(m_peerAddress).c_str(), getConnId());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ble_addr_t peerAddr_t;
|
||||||
|
memcpy(&peerAddr_t.val, address.getNative(),6);
|
||||||
|
peerAddr_t.type = address.getType();
|
||||||
|
if(ble_gap_conn_find_by_addr(&peerAddr_t, NULL) == 0) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "A connection to %s already exists",
|
||||||
|
address.toString().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(address == NimBLEAddress("")) {
|
if(address == NimBLEAddress("")) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Invalid peer address;(NULL)");
|
NIMBLE_LOGE(LOG_TAG, "Invalid peer address;(NULL)");
|
||||||
return false;
|
return false;
|
||||||
} else if(m_peerAddress != address) {
|
} else {
|
||||||
m_peerAddress = address;
|
m_peerAddress = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
ble_addr_t peerAddr_t;
|
|
||||||
memcpy(&peerAddr_t.val, m_peerAddress.getNative(),6);
|
|
||||||
peerAddr_t.type = m_peerAddress.getType();
|
|
||||||
|
|
||||||
|
|
||||||
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
|
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
|
||||||
|
m_pTaskData = &taskData;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
/* Try to connect the the advertiser. Allow 30 seconds (30000 ms) for
|
/* Try to connect the the advertiser. Allow 30 seconds (30000 ms) for
|
||||||
@ -213,13 +219,12 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
|||||||
NimBLEClient::handleGapEvent, this);
|
NimBLEClient::handleGapEvent, this);
|
||||||
switch (rc) {
|
switch (rc) {
|
||||||
case 0:
|
case 0:
|
||||||
m_pTaskData = &taskData;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BLE_HS_EBUSY:
|
case BLE_HS_EBUSY:
|
||||||
// Scan was still running, stop it and try again
|
// Scan was still running, stop it and try again
|
||||||
if (!NimBLEDevice::getScan()->stop()) {
|
if (!NimBLEDevice::getScan()->stop()) {
|
||||||
return false;
|
rc = BLE_HS_EUNKNOWN;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -227,7 +232,7 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
|||||||
// A connection to this device already exists, do not connect twice.
|
// A connection to this device already exists, do not connect twice.
|
||||||
NIMBLE_LOGE(LOG_TAG, "Already connected to device; addr=%s",
|
NIMBLE_LOGE(LOG_TAG, "Already connected to device; addr=%s",
|
||||||
std::string(m_peerAddress).c_str());
|
std::string(m_peerAddress).c_str());
|
||||||
return false;
|
break;
|
||||||
|
|
||||||
case BLE_HS_EALREADY:
|
case BLE_HS_EALREADY:
|
||||||
// Already attemting to connect to this device, cancel the previous
|
// Already attemting to connect to this device, cancel the previous
|
||||||
@ -235,17 +240,22 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
|||||||
NIMBLE_LOGE(LOG_TAG, "Already attempting to connect to %s - cancelling",
|
NIMBLE_LOGE(LOG_TAG, "Already attempting to connect to %s - cancelling",
|
||||||
std::string(m_peerAddress).c_str());
|
std::string(m_peerAddress).c_str());
|
||||||
ble_gap_conn_cancel();
|
ble_gap_conn_cancel();
|
||||||
return false;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
NIMBLE_LOGE(LOG_TAG, "Failed to connect to %s, rc=%d; %s",
|
NIMBLE_LOGE(LOG_TAG, "Failed to connect to %s, rc=%d; %s",
|
||||||
std::string(m_peerAddress).c_str(),
|
std::string(m_peerAddress).c_str(),
|
||||||
rc, NimBLEUtils::returnCodeToString(rc));
|
rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
return false;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (rc == BLE_HS_EBUSY);
|
} while (rc == BLE_HS_EBUSY);
|
||||||
|
|
||||||
|
if(rc != 0) {
|
||||||
|
m_pTaskData = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Wait for the connect timeout time +1 second for the connection to complete
|
// Wait for the connect timeout time +1 second for the connection to complete
|
||||||
if(ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(m_connectTimeout + 1000)) == pdFALSE) {
|
if(ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(m_connectTimeout + 1000)) == pdFALSE) {
|
||||||
m_pTaskData = nullptr;
|
m_pTaskData = nullptr;
|
||||||
@ -255,7 +265,7 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
|||||||
disconnect();
|
disconnect();
|
||||||
} else {
|
} else {
|
||||||
// workaround; if the controller doesn't cancel the connection
|
// workaround; if the controller doesn't cancel the connection
|
||||||
// at the timeout cancel it here.
|
// at the timeout, cancel it here.
|
||||||
NIMBLE_LOGE(LOG_TAG, "Connect timeout - cancelling");
|
NIMBLE_LOGE(LOG_TAG, "Connect timeout - cancelling");
|
||||||
ble_gap_conn_cancel();
|
ble_gap_conn_cancel();
|
||||||
}
|
}
|
||||||
@ -269,7 +279,7 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
|||||||
// If the failure was not a result of a disconnection
|
// If the failure was not a result of a disconnection
|
||||||
// make sure we disconnect now to avoid dangling connections
|
// make sure we disconnect now to avoid dangling connections
|
||||||
if(isConnected()) {
|
if(isConnected()) {
|
||||||
ble_gap_terminate(m_conn_id, BLE_ERR_REM_USER_CONN_TERM);
|
disconnect();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
@ -325,26 +335,35 @@ bool NimBLEClient::secureConnection() {
|
|||||||
*/
|
*/
|
||||||
int NimBLEClient::disconnect(uint8_t reason) {
|
int NimBLEClient::disconnect(uint8_t reason) {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> disconnect()");
|
NIMBLE_LOGD(LOG_TAG, ">> disconnect()");
|
||||||
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
if(isConnected()){
|
if(isConnected()) {
|
||||||
rc = ble_gap_terminate(m_conn_id, reason);
|
// If the timer was already started, ignore this call.
|
||||||
if (rc == 0) {
|
if(ble_npl_callout_is_active(&m_dcTimer)) {
|
||||||
ble_addr_t peerAddr_t;
|
NIMBLE_LOGI(LOG_TAG, "Already disconnecting, timer started");
|
||||||
memcpy(&peerAddr_t.val, m_peerAddress.getNative(),6);
|
return BLE_HS_EALREADY;
|
||||||
peerAddr_t.type = m_peerAddress.getType();
|
}
|
||||||
|
|
||||||
// Set the disconnect timeout to the supervison timeout time + 1 second
|
ble_gap_conn_desc desc;
|
||||||
// In case the event triggers shortly after the supervision timeout.
|
if(ble_gap_conn_find(m_conn_id, &desc) != 0){
|
||||||
// We don't want to prematurely reset the host.
|
NIMBLE_LOGI(LOG_TAG, "Connection ID not found");
|
||||||
ble_gap_conn_desc desc;
|
return BLE_HS_EALREADY;
|
||||||
if(ble_gap_conn_find_by_addr(&peerAddr_t, &desc) == 0){
|
}
|
||||||
ble_npl_time_t ticks;
|
|
||||||
ble_npl_time_ms_to_ticks((desc.supervision_timeout + 100) * 10, &ticks);
|
// We use a timer to detect a controller error in the event that it does
|
||||||
ble_npl_callout_reset(&m_dcTimer, ticks);
|
// not inform the stack when disconnection is complete.
|
||||||
NIMBLE_LOGD(LOG_TAG, "DC TIMEOUT = %dms", (desc.supervision_timeout + 100) * 10);
|
// This is a common error in certain esp-idf versions.
|
||||||
|
// The disconnect timeout time is the supervison timeout time + 1 second.
|
||||||
|
// In the case that the event happenss shortly after the supervision timeout
|
||||||
|
// we don't want to prematurely reset the host.
|
||||||
|
ble_npl_time_t ticks;
|
||||||
|
ble_npl_time_ms_to_ticks((desc.supervision_timeout + 100) * 10, &ticks);
|
||||||
|
ble_npl_callout_reset(&m_dcTimer, ticks);
|
||||||
|
|
||||||
|
rc = ble_gap_terminate(m_conn_id, reason);
|
||||||
|
if (rc != 0) {
|
||||||
|
if(rc != BLE_HS_EALREADY) {
|
||||||
|
ble_npl_callout_stop(&m_dcTimer);
|
||||||
}
|
}
|
||||||
} else if (rc != BLE_HS_EALREADY) {
|
|
||||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_terminate failed: rc=%d %s",
|
NIMBLE_LOGE(LOG_TAG, "ble_gap_terminate failed: rc=%d %s",
|
||||||
rc, NimBLEUtils::returnCodeToString(rc));
|
rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
}
|
}
|
||||||
@ -359,12 +378,12 @@ int NimBLEClient::disconnect(uint8_t reason) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the connection paramaters to use when connecting to a server.
|
* @brief Set the connection paramaters to use when connecting to a server.
|
||||||
* @param [in] minInterval minimum connection interval in 0.625ms units.
|
* @param [in] minInterval The minimum connection interval in 1.25ms units.
|
||||||
* @param [in] maxInterval maximum connection interval in 0.625ms units.
|
* @param [in] maxInterval The maximum connection interval in 1.25ms units.
|
||||||
* @param [in] latency number of packets allowed to skip (extends max interval)
|
* @param [in] latency The number of packets allowed to skip (extends max interval).
|
||||||
* @param [in] timeout the timeout time in 10ms units before disconnecting
|
* @param [in] timeout The timeout time in 10ms units before disconnecting.
|
||||||
* @param [in] scanInterval the scan interval to use when attempting to connect in 0.625ms units.
|
* @param [in] scanInterval The scan interval to use when attempting to connect in 0.625ms units.
|
||||||
* @param [in] scanWindow the scan window to use when attempting to connect in 0.625ms units.
|
* @param [in] scanWindow The scan window to use when attempting to connect in 0.625ms units.
|
||||||
*/
|
*/
|
||||||
void NimBLEClient::setConnectionParams(uint16_t minInterval, uint16_t maxInterval,
|
void NimBLEClient::setConnectionParams(uint16_t minInterval, uint16_t maxInterval,
|
||||||
uint16_t latency, uint16_t timeout,
|
uint16_t latency, uint16_t timeout,
|
||||||
@ -391,10 +410,10 @@ void NimBLEClient::setConnectionParams(uint16_t minInterval, uint16_t maxInterva
|
|||||||
/**
|
/**
|
||||||
* @brief Update the connection parameters:
|
* @brief Update the connection parameters:
|
||||||
* * Can only be used after a connection has been established.
|
* * Can only be used after a connection has been established.
|
||||||
* @param [in] minInterval minimum connection interval in 0.625ms units.
|
* @param [in] minInterval The minimum connection interval in 1.25ms units.
|
||||||
* @param [in] maxInterval maximum connection interval in 0.625ms units.
|
* @param [in] maxInterval The maximum connection interval in 1.25ms units.
|
||||||
* @param [in] latency number of packets allowed to skip (extends max interval)
|
* @param [in] latency The number of packets allowed to skip (extends max interval).
|
||||||
* @param [in] timeout the timeout time in 10ms units before disconnecting
|
* @param [in] timeout The timeout time in 10ms units before disconnecting.
|
||||||
*/
|
*/
|
||||||
void NimBLEClient::updateConnParams(uint16_t minInterval, uint16_t maxInterval,
|
void NimBLEClient::updateConnParams(uint16_t minInterval, uint16_t maxInterval,
|
||||||
uint16_t latency, uint16_t timeout)
|
uint16_t latency, uint16_t timeout)
|
||||||
@ -797,14 +816,15 @@ uint16_t NimBLEClient::getMTU() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
client->m_conn_id = BLE_HS_CONN_HANDLE_NONE;
|
|
||||||
|
|
||||||
// Stop the disconnect timer since we are now disconnected.
|
// Stop the disconnect timer since we are now disconnected.
|
||||||
ble_npl_callout_stop(&client->m_dcTimer);
|
ble_npl_callout_stop(&client->m_dcTimer);
|
||||||
|
|
||||||
// Remove the device from ignore list so we will scan it again
|
// Remove the device from ignore list so we will scan it again
|
||||||
NimBLEDevice::removeIgnored(client->m_peerAddress);
|
NimBLEDevice::removeIgnored(client->m_peerAddress);
|
||||||
|
|
||||||
|
// No longer connected, clear the connection ID.
|
||||||
|
client->m_conn_id = BLE_HS_CONN_HANDLE_NONE;
|
||||||
|
|
||||||
// If we received a connected event but did not get established (no PDU)
|
// If we received a connected event but did not get established (no PDU)
|
||||||
// then a disconnect event will be sent but we should not send it to the
|
// then a disconnect event will be sent but we should not send it to the
|
||||||
// app for processing. Instead we will ensure the task is released
|
// app for processing. Instead we will ensure the task is released
|
||||||
|
@ -20,6 +20,10 @@
|
|||||||
#include "NimBLEHIDDevice.h"
|
#include "NimBLEHIDDevice.h"
|
||||||
#include "NimBLE2904.h"
|
#include "NimBLE2904.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a default NimBLEHIDDevice object.
|
||||||
|
* @param [in] server A pointer to the server instance this HID Device will use.
|
||||||
|
*/
|
||||||
NimBLEHIDDevice::NimBLEHIDDevice(NimBLEServer* server) {
|
NimBLEHIDDevice::NimBLEHIDDevice(NimBLEServer* server) {
|
||||||
/*
|
/*
|
||||||
* Here we create mandatory services described in bluetooth specification
|
* Here we create mandatory services described in bluetooth specification
|
||||||
@ -61,15 +65,18 @@ NimBLEHIDDevice::NimBLEHIDDevice(NimBLEServer* server) {
|
|||||||
NimBLEHIDDevice::~NimBLEHIDDevice() {
|
NimBLEHIDDevice::~NimBLEHIDDevice() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @brief
|
* @brief Set the report map data formatting information.
|
||||||
|
* @param [in] map A pointer to an array with the values to set.
|
||||||
|
* @param [in] size The number of values in the array.
|
||||||
*/
|
*/
|
||||||
void NimBLEHIDDevice::reportMap(uint8_t* map, uint16_t size) {
|
void NimBLEHIDDevice::reportMap(uint8_t* map, uint16_t size) {
|
||||||
m_reportMapCharacteristic->setValue(map, size);
|
m_reportMapCharacteristic->setValue(map, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @brief This function suppose to be called at the end, when we have created all characteristics we need to build HID service
|
* @brief Start the HID device services.\n
|
||||||
|
* This function called when all the services have been created.
|
||||||
*/
|
*/
|
||||||
void NimBLEHIDDevice::startServices() {
|
void NimBLEHIDDevice::startServices() {
|
||||||
m_deviceInfoService->start();
|
m_deviceInfoService->start();
|
||||||
@ -77,41 +84,47 @@ void NimBLEHIDDevice::startServices() {
|
|||||||
m_batteryService->start();
|
m_batteryService->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @brief Create manufacturer characteristic (this characteristic is optional)
|
* @brief Create a manufacturer characteristic (this characteristic is optional).
|
||||||
*/
|
*/
|
||||||
NimBLECharacteristic* NimBLEHIDDevice::manufacturer() {
|
NimBLECharacteristic* NimBLEHIDDevice::manufacturer() {
|
||||||
m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a29, NIMBLE_PROPERTY::READ);
|
m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a29, NIMBLE_PROPERTY::READ);
|
||||||
return m_manufacturerCharacteristic;
|
return m_manufacturerCharacteristic;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @brief Set manufacturer name
|
* @brief Set manufacturer name
|
||||||
* @param [in] name manufacturer name
|
* @param [in] name The manufacturer name of this HID device.
|
||||||
*/
|
*/
|
||||||
void NimBLEHIDDevice::manufacturer(std::string name) {
|
void NimBLEHIDDevice::manufacturer(std::string name) {
|
||||||
m_manufacturerCharacteristic->setValue(name);
|
m_manufacturerCharacteristic->setValue(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @brief
|
* @brief Sets the Plug n Play characterisc value.
|
||||||
|
* @param [in] sig The vendor ID source number.
|
||||||
|
* @param [in[ vid The vendor ID number.
|
||||||
|
* @param [in] pid The product ID number.
|
||||||
|
* @param [in] version The produce version number.
|
||||||
*/
|
*/
|
||||||
void NimBLEHIDDevice::pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version) {
|
void NimBLEHIDDevice::pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version) {
|
||||||
uint8_t pnp[] = { sig, (uint8_t) (vid >> 8), (uint8_t) vid, (uint8_t) (pid >> 8), (uint8_t) pid, (uint8_t) (version >> 8), (uint8_t) version };
|
uint8_t pnp[] = { sig, (uint8_t) (vid >> 8), (uint8_t) vid, (uint8_t) (pid >> 8), (uint8_t) pid, (uint8_t) (version >> 8), (uint8_t) version };
|
||||||
m_pnpCharacteristic->setValue(pnp, sizeof(pnp));
|
m_pnpCharacteristic->setValue(pnp, sizeof(pnp));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @brief
|
* @brief Sets the HID Information characteristic value.
|
||||||
|
* @param [in] country The country code for the device.
|
||||||
|
* @param [in] flags The HID Class Specification release number to use.
|
||||||
*/
|
*/
|
||||||
void NimBLEHIDDevice::hidInfo(uint8_t country, uint8_t flags) {
|
void NimBLEHIDDevice::hidInfo(uint8_t country, uint8_t flags) {
|
||||||
uint8_t info[] = { 0x11, 0x1, country, flags };
|
uint8_t info[] = { 0x11, 0x1, country, flags };
|
||||||
m_hidInfoCharacteristic->setValue(info, sizeof(info));
|
m_hidInfoCharacteristic->setValue(info, sizeof(info));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @brief Create input report characteristic that need to be saved as new characteristic object so can be further used
|
* @brief Create input report characteristic
|
||||||
* @param [in] reportID input report ID, the same as in report map for input object related to created characteristic
|
* @param [in] reportID input report ID, the same as in report map for input object related to the characteristic
|
||||||
* @return pointer to new input report characteristic
|
* @return pointer to new input report characteristic
|
||||||
*/
|
*/
|
||||||
NimBLECharacteristic* NimBLEHIDDevice::inputReport(uint8_t reportID) {
|
NimBLECharacteristic* NimBLEHIDDevice::inputReport(uint8_t reportID) {
|
||||||
@ -124,9 +137,9 @@ NimBLECharacteristic* NimBLEHIDDevice::inputReport(uint8_t reportID) {
|
|||||||
return inputReportCharacteristic;
|
return inputReportCharacteristic;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @brief Create output report characteristic that need to be saved as new characteristic object so can be further used
|
* @brief Create output report characteristic
|
||||||
* @param [in] reportID Output report ID, the same as in report map for output object related to created characteristic
|
* @param [in] reportID Output report ID, the same as in report map for output object related to the characteristic
|
||||||
* @return Pointer to new output report characteristic
|
* @return Pointer to new output report characteristic
|
||||||
*/
|
*/
|
||||||
NimBLECharacteristic* NimBLEHIDDevice::outputReport(uint8_t reportID) {
|
NimBLECharacteristic* NimBLEHIDDevice::outputReport(uint8_t reportID) {
|
||||||
@ -139,9 +152,9 @@ NimBLECharacteristic* NimBLEHIDDevice::outputReport(uint8_t reportID) {
|
|||||||
return outputReportCharacteristic;
|
return outputReportCharacteristic;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @brief Create feature report characteristic that need to be saved as new characteristic object so can be further used
|
* @brief Create feature report characteristic.
|
||||||
* @param [in] reportID Feature report ID, the same as in report map for feature object related to created characteristic
|
* @param [in] reportID Feature report ID, the same as in report map for feature object related to the characteristic
|
||||||
* @return Pointer to new feature report characteristic
|
* @return Pointer to new feature report characteristic
|
||||||
*/
|
*/
|
||||||
NimBLECharacteristic* NimBLEHIDDevice::featureReport(uint8_t reportID) {
|
NimBLECharacteristic* NimBLEHIDDevice::featureReport(uint8_t reportID) {
|
||||||
@ -154,34 +167,38 @@ NimBLECharacteristic* NimBLEHIDDevice::featureReport(uint8_t reportID) {
|
|||||||
return featureReportCharacteristic;
|
return featureReportCharacteristic;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @brief
|
* @brief Creates a keyboard boot input report characteristic
|
||||||
*/
|
*/
|
||||||
NimBLECharacteristic* NimBLEHIDDevice::bootInput() {
|
NimBLECharacteristic* NimBLEHIDDevice::bootInput() {
|
||||||
return m_hidService->createCharacteristic((uint16_t) 0x2a22, NIMBLE_PROPERTY::NOTIFY);
|
return m_hidService->createCharacteristic((uint16_t) 0x2a22, NIMBLE_PROPERTY::NOTIFY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @brief
|
* @brief Create a keyboard boot output report characteristic
|
||||||
*/
|
*/
|
||||||
NimBLECharacteristic* NimBLEHIDDevice::bootOutput() {
|
NimBLECharacteristic* NimBLEHIDDevice::bootOutput() {
|
||||||
return m_hidService->createCharacteristic((uint16_t) 0x2a32, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR);
|
return m_hidService->createCharacteristic((uint16_t) 0x2a32, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @brief
|
* @brief Returns a pointer to the HID control point characteristic.
|
||||||
*/
|
*/
|
||||||
NimBLECharacteristic* NimBLEHIDDevice::hidControl() {
|
NimBLECharacteristic* NimBLEHIDDevice::hidControl() {
|
||||||
return m_hidControlCharacteristic;
|
return m_hidControlCharacteristic;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @brief
|
* @brief Returns a pointer to the protocol mode characteristic.
|
||||||
*/
|
*/
|
||||||
NimBLECharacteristic* NimBLEHIDDevice::protocolMode() {
|
NimBLECharacteristic* NimBLEHIDDevice::protocolMode() {
|
||||||
return m_protocolModeCharacteristic;
|
return m_protocolModeCharacteristic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the battery level characteristic value.
|
||||||
|
* @param [in] level The battery level value.
|
||||||
|
*/
|
||||||
void NimBLEHIDDevice::setBatteryLevel(uint8_t level) {
|
void NimBLEHIDDevice::setBatteryLevel(uint8_t level) {
|
||||||
m_batteryLevelCharacteristic->setValue(&level, 1);
|
m_batteryLevelCharacteristic->setValue(&level, 1);
|
||||||
}
|
}
|
||||||
@ -208,22 +225,23 @@ BLECharacteristic* BLEHIDDevice::hidInfo() {
|
|||||||
return m_hidInfoCharacteristic;
|
return m_hidInfoCharacteristic;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
/*
|
|
||||||
* @brief
|
/**
|
||||||
|
* @brief Returns a pointer to the device information service.
|
||||||
*/
|
*/
|
||||||
NimBLEService* NimBLEHIDDevice::deviceInfo() {
|
NimBLEService* NimBLEHIDDevice::deviceInfo() {
|
||||||
return m_deviceInfoService;
|
return m_deviceInfoService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @brief
|
* @brief Returns a pointer to the HID service.
|
||||||
*/
|
*/
|
||||||
NimBLEService* NimBLEHIDDevice::hidService() {
|
NimBLEService* NimBLEHIDDevice::hidService() {
|
||||||
return m_hidService;
|
return m_hidService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @brief
|
* @brief @brief Returns a pointer to the battery service.
|
||||||
*/
|
*/
|
||||||
NimBLEService* NimBLEHIDDevice::batteryService() {
|
NimBLEService* NimBLEHIDDevice::batteryService() {
|
||||||
return m_batteryService;
|
return m_batteryService;
|
||||||
|
@ -36,6 +36,10 @@
|
|||||||
#define HID_DIGITAL_PEN 0x03C7
|
#define HID_DIGITAL_PEN 0x03C7
|
||||||
#define HID_BARCODE 0x03C8
|
#define HID_BARCODE 0x03C8
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A model of a %BLE Human Interface Device.
|
||||||
|
*/
|
||||||
class NimBLEHIDDevice {
|
class NimBLEHIDDevice {
|
||||||
public:
|
public:
|
||||||
NimBLEHIDDevice(NimBLEServer*);
|
NimBLEHIDDevice(NimBLEServer*);
|
||||||
|
@ -621,7 +621,13 @@ uint16_t NimBLEServer::getPeerMTU(uint16_t conn_id) {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update connection parameters can be called only after connection has been established
|
* @brief Request an Update the connection parameters:
|
||||||
|
* * Can only be used after a connection has been established.
|
||||||
|
* @param [in] conn_handle The connection handle of the peer to send the request to.
|
||||||
|
* @param [in] minInterval The minimum connection interval in 1.25ms units.
|
||||||
|
* @param [in] maxInterval The maximum connection interval in 1.25ms units.
|
||||||
|
* @param [in] latency The number of packets allowed to skip (extends max interval).
|
||||||
|
* @param [in] timeout The timeout time in 10ms units before disconnecting.
|
||||||
*/
|
*/
|
||||||
void NimBLEServer::updateConnParams(uint16_t conn_handle,
|
void NimBLEServer::updateConnParams(uint16_t conn_handle,
|
||||||
uint16_t minInterval, uint16_t maxInterval,
|
uint16_t minInterval, uint16_t maxInterval,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user