mirror of
https://github.com/h2zero/esp-nimble-cpp.git
synced 2024-12-18 09:10:47 +01:00
Update examples
This commit is contained in:
parent
e4d2e991f1
commit
49769f4aeb
66 changed files with 629 additions and 1705 deletions
8
.github/workflows/build.yml
vendored
8
.github/workflows/build.yml
vendored
|
@ -1,7 +1,7 @@
|
|||
name: Build
|
||||
|
||||
on:
|
||||
workflow_dispatch: # Start a workflow
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
|
@ -20,8 +20,8 @@ jobs:
|
|||
idf_ver: ["release-v4.4", "release-v5.1", "release-v5.3"]
|
||||
idf_target: ["esp32", "esp32s3", "esp32c2", "esp32c3", "esp32c6", "esp32h2", "esp32p4"]
|
||||
example:
|
||||
- Advanced/NimBLE_Client
|
||||
- Advanced/NimBLE_Server
|
||||
- NimBLE_Client
|
||||
- NimBLE_Server
|
||||
- Bluetooth_5/NimBLE_extended_client
|
||||
- Bluetooth_5/NimBLE_extended_server
|
||||
exclude:
|
||||
|
@ -29,8 +29,6 @@ jobs:
|
|||
example: Bluetooth_5/NimBLE_extended_client
|
||||
- idf_target: "esp32"
|
||||
example: Bluetooth_5/NimBLE_extended_server
|
||||
- idf_target: "esp32"
|
||||
example: Bluetooth_5/NimBLE_multi_advertiser
|
||||
- idf_ver: release-v4.4
|
||||
idf_target: "esp32c2"
|
||||
- idf_ver: release-v4.4
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
PROJECT_NAME := NimBLE_Client
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
|
@ -1,4 +0,0 @@
|
|||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
|
@ -1,369 +0,0 @@
|
|||
|
||||
/** NimBLE_Client Demo:
|
||||
*
|
||||
* Demonstrates many of the available features of the NimBLE client library.
|
||||
*
|
||||
* Created: on March 24 2020
|
||||
* Author: H2zero
|
||||
*
|
||||
*/
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
extern "C" {void app_main(void);}
|
||||
|
||||
static const NimBLEAdvertisedDevice* advDevice;
|
||||
|
||||
static bool doConnect = false;
|
||||
static uint32_t scanTime = 0; /** scan time in milliseconds, 0 = scan forever */
|
||||
|
||||
|
||||
/** None of these are required as they will be handled by the library with defaults. **
|
||||
** Remove as you see fit for your needs */
|
||||
class ClientCallbacks : public NimBLEClientCallbacks {
|
||||
void onConnect(NimBLEClient* pClient) {
|
||||
printf("Connected\n");
|
||||
/** After connection we should change the parameters if we don't need fast response times.
|
||||
* These settings are 150ms interval, 0 latency, 450ms timout.
|
||||
* 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.
|
||||
* Min interval: 120 * 1.25ms = 150, Max interval: 120 * 1.25ms = 150, 0 latency, 45 * 10ms = 450ms timeout
|
||||
*/
|
||||
pClient->updateConnParams(120,120,0,45);
|
||||
}
|
||||
|
||||
void onDisconnect(NimBLEClient* pClient, int reason) {
|
||||
printf("%s Disconnected, reason = %d - Starting scan\n",
|
||||
pClient->getPeerAddress().toString().c_str(), reason);
|
||||
NimBLEDevice::getScan()->start(scanTime);
|
||||
}
|
||||
|
||||
/********************* Security handled here **********************
|
||||
****** Note: these are the same return values as defaults ********/
|
||||
void onPassKeyEntry(NimBLEConnInfo& connInfo){
|
||||
printf("Server Passkey Entry\n");
|
||||
/** This should prompt the user to enter the passkey displayed
|
||||
* on the peer device.
|
||||
*/
|
||||
NimBLEDevice::injectPassKey(connInfo, 123456);
|
||||
};
|
||||
|
||||
void onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t pass_key){
|
||||
printf("The passkey YES/NO number: %" PRIu32 "\n", pass_key);
|
||||
/** Inject false if passkeys don't match. */
|
||||
NimBLEDevice::injectConfirmPasskey(connInfo, true);
|
||||
};
|
||||
|
||||
/** Pairing process complete, we can check the results in connInfo */
|
||||
void onAuthenticationComplete(NimBLEConnInfo& connInfo){
|
||||
if(!connInfo.isEncrypted()) {
|
||||
printf("Encrypt connection failed - disconnecting\n");
|
||||
/** Find the client with the connection handle provided in desc */
|
||||
NimBLEDevice::getClientByHandle(connInfo.getConnHandle())->disconnect();
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Define a class to handle the callbacks when advertisments are received */
|
||||
class scanCallbacks: public NimBLEScanCallbacks {
|
||||
void onResult(const NimBLEAdvertisedDevice* advertisedDevice) {
|
||||
printf("Advertised Device found: %s\n", advertisedDevice->toString().c_str());
|
||||
if(advertisedDevice->isAdvertisingService(NimBLEUUID("DEAD")))
|
||||
{
|
||||
printf("Found Our Service\n");
|
||||
/** stop scan before connecting */
|
||||
NimBLEDevice::getScan()->stop();
|
||||
/** Save the device reference in a global for the client to use*/
|
||||
advDevice = advertisedDevice;
|
||||
/** Ready to connect now */
|
||||
doConnect = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Callback to process the results of the completed scan or restart it */
|
||||
void onScanEnd(const NimBLEScanResults& results, int reason) {
|
||||
printf("Scan Ended, reason: %d, device count: %d\n", reason, results.getCount());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Notification / Indication receiving handler callback */
|
||||
void notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify){
|
||||
std::string str = (isNotify == true) ? "Notification" : "Indication";
|
||||
str += " from ";
|
||||
str += pRemoteCharacteristic->getClient()->getPeerAddress().toString();
|
||||
str += ": Service = " + pRemoteCharacteristic->getRemoteService()->getUUID().toString();
|
||||
str += ", Characteristic = " + pRemoteCharacteristic->getUUID().toString();
|
||||
str += ", Value = " + std::string((char*)pData, length);
|
||||
printf("%s\n", str.c_str());
|
||||
}
|
||||
|
||||
|
||||
/** Create a single global instance of the callback class to be used by all clients */
|
||||
static ClientCallbacks clientCB;
|
||||
|
||||
|
||||
/** Handles the provisioning of clients and connects / interfaces with the server */
|
||||
bool connectToServer() {
|
||||
NimBLEClient* pClient = nullptr;
|
||||
|
||||
/** Check if we have a client we should reuse first **/
|
||||
if(NimBLEDevice::getCreatedClientCount()) {
|
||||
/** Special case when we already know this device, we send false as the
|
||||
* second argument in connect() to prevent refreshing the service database.
|
||||
* This saves considerable time and power.
|
||||
*/
|
||||
pClient = NimBLEDevice::getClientByPeerAddress(advDevice->getAddress());
|
||||
if(pClient){
|
||||
if(!pClient->connect(advDevice, false)) {
|
||||
printf("Reconnect failed\n");
|
||||
return false;
|
||||
}
|
||||
printf("Reconnected client\n");
|
||||
}
|
||||
/** We don't already have a client that knows this device,
|
||||
* we will check for a client that is disconnected that we can use.
|
||||
*/
|
||||
else {
|
||||
pClient = NimBLEDevice::getDisconnectedClient();
|
||||
}
|
||||
}
|
||||
|
||||
/** No client to reuse? Create a new one. */
|
||||
if(!pClient) {
|
||||
if(NimBLEDevice::getCreatedClientCount() >= NIMBLE_MAX_CONNECTIONS) {
|
||||
printf("Max clients reached - no more connections available\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
pClient = NimBLEDevice::createClient();
|
||||
|
||||
printf("New client created\n");
|
||||
|
||||
pClient->setClientCallbacks(&clientCB, false);
|
||||
/** 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
|
||||
* 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, 12 * 10ms = 120ms timeout
|
||||
*/
|
||||
pClient->setConnectionParams(6,6,0,15);
|
||||
/** Set how long we are willing to wait for the connection to complete (milliseconds), default is 30000. */
|
||||
pClient->setConnectTimeout(5 * 1000);
|
||||
|
||||
|
||||
if (!pClient->connect(advDevice)) {
|
||||
/** Created a client but failed to connect, don't need to keep it as it has no data */
|
||||
NimBLEDevice::deleteClient(pClient);
|
||||
printf("Failed to connect, deleted client\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!pClient->isConnected()) {
|
||||
if (!pClient->connect(advDevice)) {
|
||||
printf("Failed to connect\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Connected to: %s RSSI: %d\n",
|
||||
pClient->getPeerAddress().toString().c_str(),
|
||||
pClient->getRssi());
|
||||
|
||||
/** Now we can read/write/subscribe the charateristics of the services we are interested in */
|
||||
NimBLERemoteService* pSvc = nullptr;
|
||||
NimBLERemoteCharacteristic* pChr = nullptr;
|
||||
NimBLERemoteDescriptor* pDsc = nullptr;
|
||||
|
||||
pSvc = pClient->getService("DEAD");
|
||||
if(pSvc) { /** make sure it's not null */
|
||||
pChr = pSvc->getCharacteristic("BEEF");
|
||||
}
|
||||
|
||||
if(pChr) { /** make sure it's not null */
|
||||
if(pChr->canRead()) {
|
||||
printf("%s Value: %s\n",
|
||||
pChr->getUUID().toString().c_str(),
|
||||
pChr->readValue().c_str());
|
||||
}
|
||||
|
||||
if(pChr->canWrite()) {
|
||||
if(pChr->writeValue("Tasty")) {
|
||||
printf("Wrote new value to: %s\n", pChr->getUUID().toString().c_str());
|
||||
}
|
||||
else {
|
||||
/** Disconnect if write failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pChr->canRead()) {
|
||||
printf("The value of: %s is now: %s\n",
|
||||
pChr->getUUID().toString().c_str(),
|
||||
pChr->readValue().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/** registerForNotify() has been removed and replaced with subscribe() / unsubscribe().
|
||||
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=true.
|
||||
* Unsubscribe parameter defaults are: response=true.
|
||||
*/
|
||||
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{
|
||||
printf("DEAD service not found.\n");
|
||||
}
|
||||
|
||||
pSvc = pClient->getService("BAAD");
|
||||
if(pSvc) { /** make sure it's not null */
|
||||
pChr = pSvc->getCharacteristic("F00D");
|
||||
}
|
||||
|
||||
if(pChr) { /** make sure it's not null */
|
||||
if(pChr->canRead()) {
|
||||
printf("%s Value: %s\n",
|
||||
pChr->getUUID().toString().c_str(),
|
||||
pChr->readValue().c_str());
|
||||
}
|
||||
|
||||
pDsc = pChr->getDescriptor(NimBLEUUID("C01D"));
|
||||
if(pDsc) { /** make sure it's not null */
|
||||
printf("Descriptor: %s Value: %s\n",
|
||||
pDsc->getUUID().toString().c_str(),
|
||||
pDsc->readValue().c_str());
|
||||
}
|
||||
|
||||
if(pChr->canWrite()) {
|
||||
if(pChr->writeValue("No tip!")) {
|
||||
printf("Wrote new value to: %s\n", pChr->getUUID().toString().c_str());
|
||||
}
|
||||
else {
|
||||
/** Disconnect if write failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pChr->canRead()) {
|
||||
printf("The value of: %s is now: %s\n",
|
||||
pChr->getUUID().toString().c_str(),
|
||||
pChr->readValue().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
|
||||
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=true.
|
||||
* Unsubscribe parameter defaults are: response=true.
|
||||
*/
|
||||
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{
|
||||
printf("BAAD service not found.\n");
|
||||
}
|
||||
|
||||
printf("Done with this device!\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
void connectTask (void * parameter){
|
||||
/** Loop here until we find a device we want to connect to */
|
||||
for(;;) {
|
||||
if(doConnect) {
|
||||
doConnect = false;
|
||||
/** Found a device we want to connect to, do it now */
|
||||
if(connectToServer()) {
|
||||
printf("Success! we should now be getting notifications, scanning for more!\n");
|
||||
} else {
|
||||
printf("Failed to connect, starting scan\n");
|
||||
}
|
||||
|
||||
NimBLEDevice::getScan()->start(scanTime);
|
||||
}
|
||||
vTaskDelay(10/portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void app_main (void){
|
||||
printf("Starting NimBLE Client\n");
|
||||
/** Initialize NimBLE, no device name spcified as we are not advertising */
|
||||
NimBLEDevice::init("");
|
||||
|
||||
/** 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_DISPLAY_YESNO - Numeric comparison pairing
|
||||
* BLE_HS_IO_NO_INPUT_OUTPUT - DEFAULT setting - just works pairing
|
||||
*/
|
||||
//NimBLEDevice::setSecurityIOCap(BLE_HS_IO_KEYBOARD_ONLY); // use passkey
|
||||
//NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO); //use numeric comparison
|
||||
|
||||
/** 2 different ways to set security - both calls achieve the same result.
|
||||
* no bonding, no man in the middle protection, secure connections.
|
||||
*
|
||||
* These are the default values, only shown here for demonstration.
|
||||
*/
|
||||
//NimBLEDevice::setSecurityAuth(false, false, true);
|
||||
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 */
|
||||
NimBLEDevice::setPower(9); // 9dbm
|
||||
|
||||
/** create new scan */
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
|
||||
/** create a callback that gets called when advertisers are found */
|
||||
pScan->setScanCallbacks (new scanCallbacks());
|
||||
|
||||
/** Set scan interval (how often) and window (how long) in milliseconds */
|
||||
pScan->setInterval(400);
|
||||
pScan->setWindow(100);
|
||||
|
||||
/** Active scan will gather scan response data from advertisers
|
||||
* but will use more energy from both devices
|
||||
*/
|
||||
pScan->setActiveScan(true);
|
||||
/** Start scanning for advertisers for the scan time specified (in milliseconds) 0 = forever
|
||||
* Optional callback for when scanning stops.
|
||||
*/
|
||||
pScan->start(scanTime);
|
||||
|
||||
printf("Scanning for peripherals\n");
|
||||
|
||||
xTaskCreate(connectTask, "connectTask", 5000, NULL, 1, NULL);
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
PROJECT_NAME := NimBLE_Server
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
|
@ -1,4 +0,0 @@
|
|||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
|
@ -3,5 +3,4 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(SUPPORTED_TARGETS esp32c3 esp32s3)
|
||||
project(NimBLE_extended_client)
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
PROJECT_NAME := NimBLE_extended_client
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
|
@ -1,4 +0,0 @@
|
|||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
|
@ -1,15 +1,14 @@
|
|||
|
||||
/** NimBLE Extended Client Demo:
|
||||
/**
|
||||
* NimBLE Extended Client Demo:
|
||||
*
|
||||
* Demonstrates the Bluetooth 5.x client capabilities.
|
||||
*
|
||||
* Created: on April 2 2022
|
||||
* Author: H2zero
|
||||
*
|
||||
*/
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
extern "C" void app_main(void);
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
#define SERVICE_UUID "ABCD"
|
||||
#define CHARACTERISTIC_UUID "1234"
|
||||
|
@ -18,54 +17,46 @@ static const NimBLEAdvertisedDevice* advDevice;
|
|||
static bool doConnect = false;
|
||||
static uint32_t scanTime = 10 * 1000; // In milliseconds, 0 = scan forever
|
||||
|
||||
/* Define the PHY's to use when connecting to peer devices, can be 1, 2, or all 3 (default).*/
|
||||
/** Define the PHY's to use when connecting to peer devices, can be 1, 2, or all 3 (default).*/
|
||||
static uint8_t connectPhys = BLE_GAP_LE_PHY_CODED_MASK | BLE_GAP_LE_PHY_1M_MASK /*| BLE_GAP_LE_PHY_2M_MASK */;
|
||||
|
||||
/* Define a class to handle the callbacks for client connection events */
|
||||
/** Define a class to handle the callbacks for client connection events */
|
||||
class ClientCallbacks : public NimBLEClientCallbacks {
|
||||
void onConnect(NimBLEClient* pClient) {
|
||||
printf("Connected\n");
|
||||
};
|
||||
void onConnect(NimBLEClient* pClient) override { printf("Connected\n"); };
|
||||
|
||||
void onDisconnect(NimBLEClient* pClient, int reason) {
|
||||
printf("%s Disconnected, reason = %d - Starting scan\n",
|
||||
pClient->getPeerAddress().toString().c_str(), reason);
|
||||
void onDisconnect(NimBLEClient* pClient, int reason) override {
|
||||
printf("%s Disconnected, reason = %d - Starting scan\n", pClient->getPeerAddress().toString().c_str(), reason);
|
||||
NimBLEDevice::getScan()->start(scanTime);
|
||||
};
|
||||
};
|
||||
}
|
||||
} clientCallbacks;
|
||||
|
||||
|
||||
/* Define a class to handle the callbacks when advertisements are received */
|
||||
/** Define a class to handle the callbacks when advertisements are received */
|
||||
class scanCallbacks : public NimBLEScanCallbacks {
|
||||
void onResult(const NimBLEAdvertisedDevice* advertisedDevice) {
|
||||
void onResult(const NimBLEAdvertisedDevice* advertisedDevice) override {
|
||||
printf("Advertised Device found: %s\n", advertisedDevice->toString().c_str());
|
||||
if(advertisedDevice->isAdvertisingService(NimBLEUUID("ABCD")))
|
||||
{
|
||||
if (advertisedDevice->isAdvertisingService(NimBLEUUID("ABCD"))) {
|
||||
printf("Found Our Service\n");
|
||||
/* Ready to connect now */
|
||||
doConnect = true;
|
||||
/* 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;
|
||||
/* stop scan before connecting */
|
||||
/** stop scan before connecting */
|
||||
NimBLEDevice::getScan()->stop();
|
||||
}
|
||||
}
|
||||
|
||||
/** Callback to process the results of the completed scan or restart it */
|
||||
void onScanEnd(const NimBLEScanResults& results, int rc) {
|
||||
printf("Scan Ended\n");
|
||||
}
|
||||
};
|
||||
void onScanEnd(const NimBLEScanResults& results, int rc) override { printf("Scan Ended\n"); }
|
||||
} scanCallbacks;
|
||||
|
||||
|
||||
/* Handles the provisioning of clients and connects / interfaces with the server */
|
||||
/** Handles the provisioning of clients and connects / interfaces with the server */
|
||||
bool connectToServer() {
|
||||
NimBLEClient* pClient = nullptr;
|
||||
|
||||
pClient = NimBLEDevice::createClient();
|
||||
pClient->setClientCallbacks(new ClientCallbacks, false);
|
||||
pClient->setClientCallbacks(&clientCallbacks, false);
|
||||
|
||||
/* Set the PHY's to use for this connection. This is a bitmask that represents the PHY's:
|
||||
/**
|
||||
* Set the PHY's to use for this connection. This is a bitmask that represents the PHY's:
|
||||
* * 0x01 BLE_GAP_LE_PHY_1M_MASK
|
||||
* * 0x02 BLE_GAP_LE_PHY_2M_MASK
|
||||
* * 0x04 BLE_GAP_LE_PHY_CODED_MASK
|
||||
|
@ -77,27 +68,22 @@ bool connectToServer() {
|
|||
pClient->setConnectTimeout(10 * 1000);
|
||||
|
||||
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 */
|
||||
NimBLEDevice::deleteClient(pClient);
|
||||
printf("Failed to connect, deleted client\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("Connected to: %s RSSI: %d\n",
|
||||
pClient->getPeerAddress().toString().c_str(),
|
||||
pClient->getRssi());
|
||||
printf("Connected to: %s RSSI: %d\n", pClient->getPeerAddress().toString().c_str(), pClient->getRssi());
|
||||
|
||||
/* Now we can read/write/subscribe the charateristics of the services we are interested in */
|
||||
/** Now we can read/write/subscribe the characteristics of the services we are interested in */
|
||||
NimBLERemoteService* pSvc = nullptr;
|
||||
NimBLERemoteCharacteristic* pChr = nullptr;
|
||||
|
||||
pSvc = pClient->getService(SERVICE_UUID);
|
||||
|
||||
if (pSvc) {
|
||||
pChr = pSvc->getCharacteristic(CHARACTERISTIC_UUID);
|
||||
|
||||
if (pChr) {
|
||||
// Read the value of the characteristic.
|
||||
if (pChr->canRead()) {
|
||||
std::string value = pChr->readValue();
|
||||
printf("Characteristic value: %s\n", value.c_str());
|
||||
|
@ -113,11 +99,37 @@ bool connectToServer() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void connectTask (void * parameter){
|
||||
/* Loop here until we find a device we want to connect to */
|
||||
extern "C" void app_main(void) {
|
||||
printf("Starting NimBLE Client\n");
|
||||
|
||||
/** Initialize NimBLE and set the device name */
|
||||
NimBLEDevice::init("NimBLE Extended Client");
|
||||
|
||||
/** Create aNimBLE Scan instance and set the callbacks for scan events */
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
pScan->setScanCallbacks(&scanCallbacks);
|
||||
|
||||
/** Set scan interval (how often) and window (how long) in milliseconds */
|
||||
pScan->setInterval(97);
|
||||
pScan->setWindow(67);
|
||||
|
||||
/**
|
||||
* Active scan will gather scan response data from advertisers
|
||||
* but will use more energy from both devices
|
||||
*/
|
||||
pScan->setActiveScan(true);
|
||||
|
||||
/**
|
||||
* Start scanning for advertisers for the scan time specified (in milliseconds) 0 = forever
|
||||
* Optional callback for when scanning stops.
|
||||
*/
|
||||
pScan->start(scanTime);
|
||||
|
||||
printf("Scanning for peripherals\n");
|
||||
|
||||
/** Loop here until we find a device we want to connect to */
|
||||
for (;;) {
|
||||
if (doConnect) {
|
||||
/* Found a device we want to connect to, do it now */
|
||||
if (connectToServer()) {
|
||||
printf("Success!, scanning for more!\n");
|
||||
} else {
|
||||
|
@ -129,35 +141,4 @@ void connectTask (void * parameter){
|
|||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void app_main (void) {
|
||||
printf("Starting NimBLE Client\n");
|
||||
/* Create a task to handle connecting to peers */
|
||||
xTaskCreate(connectTask, "connectTask", 5000, NULL, 1, NULL);
|
||||
|
||||
/* Initialize NimBLE, no device name specified as we are not advertising */
|
||||
NimBLEDevice::init("");
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
|
||||
/* create a callback that gets called when advertisers are found */
|
||||
pScan->setScanCallbacks(new scanCallbacks());
|
||||
|
||||
/* Set scan interval (how often) and window (how long) in milliseconds */
|
||||
pScan->setInterval(97);
|
||||
pScan->setWindow(67);
|
||||
|
||||
/* Active scan will gather scan response data from advertisers
|
||||
* but will use more energy from both devices
|
||||
*/
|
||||
pScan->setActiveScan(true);
|
||||
|
||||
/* Start scanning for advertisers for the scan time specified (in milliseconds) 0 = forever
|
||||
* Optional callback for when scanning stops.
|
||||
*/
|
||||
pScan->start(scanTime);
|
||||
|
||||
printf("Scanning for peripherals\n");
|
||||
}
|
||||
|
|
|
@ -3,5 +3,4 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(SUPPORTED_TARGETS esp32c3 esp32s3 esp32c6 esp32h2 esp32c2)
|
||||
project(NimBLE_extended_scan)
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
*
|
||||
* Created: on November 28, 2024
|
||||
* Author: H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
@ -13,18 +12,20 @@
|
|||
static uint32_t scanTime = 10 * 1000; // In milliseconds, 0 = scan forever
|
||||
static NimBLEScan::Phy scanPhy = NimBLEScan::Phy::SCAN_ALL;
|
||||
|
||||
// Define a class to handle the callbacks when advertisements are received
|
||||
class scanCallbacks: public NimBLEScanCallbacks {
|
||||
/** Define a class to handle the callbacks when advertisements are received */
|
||||
class ScanCallbacks : public NimBLEScanCallbacks {
|
||||
void onResult(const NimBLEAdvertisedDevice* advertisedDevice) {
|
||||
printf("Advertised Device found: %s\n PHY1: %d\n PHY2: %d\n", advertisedDevice->toString().c_str(),
|
||||
advertisedDevice->getPrimaryPhy(), advertisedDevice->getSecondaryPhy());
|
||||
printf("Advertised Device found: %s\n PHY1: %d\n PHY2: %d\n",
|
||||
advertisedDevice->toString().c_str(),
|
||||
advertisedDevice->getPrimaryPhy(),
|
||||
advertisedDevice->getSecondaryPhy());
|
||||
}
|
||||
|
||||
// Callback to process the results of the completed scan or restart it
|
||||
/** Callback to process the results of the completed scan or restart it */
|
||||
void onScanEnd(const NimBLEScanResults& scanResults, int reason) {
|
||||
printf("Scan Ended, reason: %d; found %d devices\n", reason, scanResults.getCount());
|
||||
|
||||
// Try Different PHY's
|
||||
/** Try Different PHY's */
|
||||
switch (scanPhy) {
|
||||
case NimBLEScan::Phy::SCAN_ALL:
|
||||
printf("Scanning only 1M PHY\n");
|
||||
|
@ -44,25 +45,25 @@ class scanCallbacks: public NimBLEScanCallbacks {
|
|||
pScan->setPhy(scanPhy);
|
||||
pScan->start(scanTime);
|
||||
}
|
||||
} scanCb;
|
||||
} scanCallbacks;
|
||||
|
||||
extern "C" void app_main(void) {
|
||||
printf("Starting Extended Scanner\n");
|
||||
|
||||
// Initialize NimBLE, no device name specified as we are not advertising
|
||||
NimBLEDevice::init("");
|
||||
/** Initialize NimBLE and set the device name */
|
||||
NimBLEDevice::init("NimBLE Extended Scanner");
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
|
||||
// Set the callbacks that the scanner will call on events.
|
||||
pScan->setScanCallbacks(&scanCb);
|
||||
/** Set the callbacks that the scanner will call on events. */
|
||||
pScan->setScanCallbacks(&scanCallbacks);
|
||||
|
||||
// Use active scanning to obtain scan response data from advertisers
|
||||
/** Use active scanning to obtain scan response data from advertisers */
|
||||
pScan->setActiveScan(true);
|
||||
|
||||
// Set the initial PHY's to scan on, default is SCAN_ALL
|
||||
/** Set the initial PHY's to scan on, default is SCAN_ALL */
|
||||
pScan->setPhy(scanPhy);
|
||||
|
||||
// Start scanning for scanTime, 0 = forever
|
||||
/** Start scanning for scanTime */
|
||||
pScan->start(scanTime);
|
||||
printf("Scanning for peripherals\n");
|
||||
}
|
||||
|
|
|
@ -3,5 +3,4 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(SUPPORTED_TARGETS esp32c3 esp32s3)
|
||||
project(NimBLE_extended_server)
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
PROJECT_NAME := NimBLE_extended_server
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
|
@ -1,4 +0,0 @@
|
|||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
|
@ -1,4 +1,5 @@
|
|||
/** NimBLE Extended Server Demo:
|
||||
/**
|
||||
* NimBLE Extended Server Demo:
|
||||
*
|
||||
* Demonstrates the Bluetooth 5.x extended advertising capabilities.
|
||||
*
|
||||
|
@ -9,49 +10,46 @@
|
|||
*
|
||||
* Created: on April 2 2022
|
||||
* Author: H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#include "NimBLEDevice.h"
|
||||
#include "esp_sleep.h"
|
||||
|
||||
extern "C" void app_main(void);
|
||||
#include <NimBLEDevice.h>
|
||||
#include <esp_sleep.h>
|
||||
|
||||
#define SERVICE_UUID "ABCD"
|
||||
#define CHARACTERISTIC_UUID "1234"
|
||||
|
||||
/* Time in milliseconds to advertise */
|
||||
/** Time in milliseconds to advertise */
|
||||
static uint32_t advTime = 5000;
|
||||
|
||||
/* Time to sleep between advertisements */
|
||||
/** Time to sleep between advertisements */
|
||||
static uint32_t sleepSeconds = 20;
|
||||
|
||||
/* Primary PHY used for advertising, can be one of BLE_HCI_LE_PHY_1M or BLE_HCI_LE_PHY_CODED */
|
||||
/** Primary PHY used for advertising, can be one of BLE_HCI_LE_PHY_1M or BLE_HCI_LE_PHY_CODED */
|
||||
static uint8_t primaryPhy = BLE_HCI_LE_PHY_CODED;
|
||||
|
||||
/* Secondary PHY used for advertising and connecting,
|
||||
/**
|
||||
* Secondary PHY used for advertising and connecting,
|
||||
* can be one of BLE_HCI_LE_PHY_1M, BLE_HCI_LE_PHY_2M or BLE_HCI_LE_PHY_CODED
|
||||
*/
|
||||
static uint8_t secondaryPhy = BLE_HCI_LE_PHY_1M;
|
||||
|
||||
|
||||
/* Handler class for server events */
|
||||
/** Handler class for server events */
|
||||
class ServerCallbacks : public NimBLEServerCallbacks {
|
||||
void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) {
|
||||
void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) override {
|
||||
printf("Client connected:: %s\n", connInfo.getAddress().toString().c_str());
|
||||
};
|
||||
}
|
||||
|
||||
void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) {
|
||||
void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) override {
|
||||
printf("Client disconnected - sleeping for %" PRIu32 " seconds\n", sleepSeconds);
|
||||
esp_deep_sleep_start();
|
||||
};
|
||||
};
|
||||
}
|
||||
} serverCallbacks;
|
||||
|
||||
/* Callback class to handle advertising events */
|
||||
class advertisingCallbacks: public NimBLEExtAdvertisingCallbacks {
|
||||
void onStopped(NimBLEExtAdvertising* pAdv, int reason, uint8_t inst_id) {
|
||||
/** Callback class to handle advertising events */
|
||||
class AdvertisingCallbacks : public NimBLEExtAdvertisingCallbacks {
|
||||
void onStopped(NimBLEExtAdvertising* pAdv, int reason, uint8_t instId) override {
|
||||
/* Check the reason advertising stopped, don't sleep if client is connecting */
|
||||
printf("Advertising instance %u stopped\n", inst_id);
|
||||
printf("Advertising instance %u stopped\n", instId);
|
||||
switch (reason) {
|
||||
case 0:
|
||||
printf("Client connecting\n");
|
||||
|
@ -65,40 +63,42 @@ class advertisingCallbacks: public NimBLEExtAdvertisingCallbacks {
|
|||
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
};
|
||||
} advertisingCallbacks;
|
||||
|
||||
extern "C"
|
||||
void app_main(void) {
|
||||
/** Initialize NimBLE and set the device name */
|
||||
NimBLEDevice::init("Extended advertiser");
|
||||
|
||||
/* Create the server and add the services/characteristics/descriptors */
|
||||
/** Create the server and add the services/characteristics/descriptors */
|
||||
NimBLEServer* pServer = NimBLEDevice::createServer();
|
||||
pServer->setCallbacks(new ServerCallbacks);
|
||||
pServer->setCallbacks(&serverCallbacks);
|
||||
|
||||
NimBLEService* pService = pServer->createService(SERVICE_UUID);
|
||||
NimBLECharacteristic *pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID,
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE |
|
||||
NIMBLE_PROPERTY::NOTIFY);
|
||||
NimBLECharacteristic* pCharacteristic =
|
||||
pService->createCharacteristic(CHARACTERISTIC_UUID,
|
||||
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::NOTIFY);
|
||||
|
||||
pCharacteristic->setValue("Hello World");
|
||||
|
||||
/* Start the services */
|
||||
/** Start the service */
|
||||
pService->start();
|
||||
|
||||
/*
|
||||
/**
|
||||
* Create an extended advertisement with the instance ID 0 and set the PHY's.
|
||||
* Multiple instances can be added as long as the instance ID is incremented.
|
||||
*/
|
||||
NimBLEExtAdvertisement extAdv(primaryPhy, secondaryPhy);
|
||||
|
||||
/* Set the advertisement as connectable */
|
||||
/** Set the advertisement as connectable */
|
||||
extAdv.setConnectable(true);
|
||||
|
||||
/* As per Bluetooth specification, extended advertising cannot be both scannable and connectable */
|
||||
/** As per Bluetooth specification, extended advertising cannot be both scannable and connectable */
|
||||
extAdv.setScannable(false); // The default is false, set here for demonstration.
|
||||
|
||||
/* Extended advertising allows for 251 bytes (minus header bytes ~20) in a single advertisement or up to 1650 if chained */
|
||||
extAdv.setServiceData(NimBLEUUID(SERVICE_UUID), std::string("Extended Advertising Demo.\r\n"
|
||||
/** Extended advertising allows for 251 bytes (minus header bytes ~20) in a single advertisement or up to 1650 if chained */
|
||||
extAdv.setServiceData(NimBLEUUID(SERVICE_UUID),
|
||||
std::string("Extended Advertising Demo.\r\n"
|
||||
"Extended advertising allows for "
|
||||
"251 bytes of data in a single advertisement,\r\n"
|
||||
"or up to 1650 bytes with chaining.\r\n"
|
||||
|
@ -106,14 +106,15 @@ void app_main (void) {
|
|||
"and is using CODED_PHY for long range."));
|
||||
|
||||
extAdv.setCompleteServices16({NimBLEUUID(SERVICE_UUID)});
|
||||
extAdv.setName("Extended advertiser");
|
||||
|
||||
/* When extended advertising is enabled `NimBLEDevice::getAdvertising` returns a pointer to `NimBLEExtAdvertising */
|
||||
/** When extended advertising is enabled `NimBLEDevice::getAdvertising` returns a pointer to `NimBLEExtAdvertising */
|
||||
NimBLEExtAdvertising* pAdvertising = NimBLEDevice::getAdvertising();
|
||||
|
||||
/* Set the callbacks for advertising events */
|
||||
pAdvertising->setCallbacks(new advertisingCallbacks);
|
||||
/** Set the callbacks for advertising events */
|
||||
pAdvertising->setCallbacks(&advertisingCallbacks);
|
||||
|
||||
/*
|
||||
/**
|
||||
* NimBLEExtAdvertising::setInstanceData takes the instance ID and
|
||||
* a reference to a `NimBLEExtAdvertisement` object. This sets the data
|
||||
* that will be advertised for this instance ID, returns true if successful.
|
||||
|
@ -122,8 +123,8 @@ void app_main (void) {
|
|||
* is called before exiting the code block as the data will be copied.
|
||||
*/
|
||||
if (pAdvertising->setInstanceData(0, extAdv)) {
|
||||
/*
|
||||
* `NimBLEExtAdvertising::start` takes the advertisement instance ID to start
|
||||
/**
|
||||
* NimBLEExtAdvertising::start takes the advertisement instance ID to start
|
||||
* and a duration in milliseconds or a max number of advertisements to send (or both).
|
||||
*/
|
||||
if (pAdvertising->start(0, advTime)) {
|
||||
|
@ -132,7 +133,7 @@ void app_main (void) {
|
|||
printf("Failed to start advertising\n");
|
||||
}
|
||||
} else {
|
||||
printf("Failed to register advertisment data\n");
|
||||
printf("Failed to register advertisement data\n");
|
||||
}
|
||||
|
||||
esp_sleep_enable_timer_wakeup(sleepSeconds * 1000000);
|
||||
|
|
|
@ -3,5 +3,4 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(SUPPORTED_TARGETS esp32c3 esp32s3)
|
||||
project(NimBLE_multi_advertiser)
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
PROJECT_NAME := NimBLE_multi_advertiser
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
|
@ -1,4 +0,0 @@
|
|||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
|
@ -1,4 +1,5 @@
|
|||
/** NimBLE Multi Advertiser Demo:
|
||||
/**
|
||||
* NimBLE Multi Advertiser Demo:
|
||||
*
|
||||
* Demonstrates the Bluetooth 5.x extended advertising capabilities.
|
||||
*
|
||||
|
@ -9,53 +10,50 @@
|
|||
*
|
||||
* Created: on April 9 2022
|
||||
* Author: H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#include "NimBLEDevice.h"
|
||||
#include "esp_sleep.h"
|
||||
|
||||
extern "C" void app_main(void);
|
||||
#include <NimBLEDevice.h>
|
||||
#include <esp_sleep.h>
|
||||
|
||||
#define SERVICE_UUID "ABCD"
|
||||
#define CHARACTERISTIC_UUID "1234"
|
||||
|
||||
/* Time in milliseconds to advertise */
|
||||
/** Time in milliseconds to advertise */
|
||||
static uint32_t advTime = 5000;
|
||||
|
||||
/* Time to sleep between advertisements */
|
||||
/** Time to sleep between advertisements */
|
||||
static uint32_t sleepTime = 20;
|
||||
|
||||
/* Primary PHY used for advertising, can be one of BLE_HCI_LE_PHY_1M or BLE_HCI_LE_PHY_CODED */
|
||||
/** Primary PHY used for advertising, can be one of BLE_HCI_LE_PHY_1M or BLE_HCI_LE_PHY_CODED */
|
||||
static uint8_t primaryPhy = BLE_HCI_LE_PHY_CODED;
|
||||
|
||||
/* Secondary PHY used for advertising and connecting,
|
||||
/**
|
||||
* Secondary PHY used for advertising and connecting,
|
||||
* can be one of BLE_HCI_LE_PHY_1M, BLE_HCI_LE_PHY_2M or BLE_HCI_LE_PHY_CODED
|
||||
*/
|
||||
static uint8_t secondaryPhy = BLE_HCI_LE_PHY_1M;
|
||||
|
||||
|
||||
/* Handler class for server events */
|
||||
/** Handler class for server events */
|
||||
class ServerCallbacks : public NimBLEServerCallbacks {
|
||||
void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) {
|
||||
void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) override {
|
||||
printf("Client connected: %s\n", connInfo.getAddress().toString().c_str());
|
||||
};
|
||||
}
|
||||
|
||||
void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) {
|
||||
void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) override {
|
||||
printf("Client disconnected\n");
|
||||
// if still advertising we won't sleep yet.
|
||||
if (!pServer->getAdvertising()->isAdvertising()) {
|
||||
printf("Sleeping for %" PRIu32 " seconds\n", sleepTime);
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
} serverCallbacks;
|
||||
|
||||
/* Callback class to handle advertising events */
|
||||
class advCallbacks: public NimBLEExtAdvertisingCallbacks {
|
||||
void onStopped(NimBLEExtAdvertising* pAdv, int reason, uint8_t inst_id) {
|
||||
/** Callback class to handle advertising events */
|
||||
class AdvCallbacks : public NimBLEExtAdvertisingCallbacks {
|
||||
void onStopped(NimBLEExtAdvertising* pAdv, int reason, uint8_t instId) override {
|
||||
/* Check the reason advertising stopped, don't sleep if client is connecting */
|
||||
printf("Advertising instance %u stopped\n", inst_id);
|
||||
printf("Advertising instance %u stopped\n", instId);
|
||||
switch (reason) {
|
||||
case 0:
|
||||
printf(" client connecting\n");
|
||||
|
@ -72,89 +70,89 @@ class advCallbacks: public NimBLEExtAdvertisingCallbacks {
|
|||
|
||||
bool m_updatedSR = false;
|
||||
|
||||
void onScanRequest(NimBLEExtAdvertising* pAdv, uint8_t inst_id, NimBLEAddress addr) {
|
||||
printf("Scan request for instance %u\n", inst_id);
|
||||
void onScanRequest(NimBLEExtAdvertising* pAdv, uint8_t instId, NimBLEAddress addr) override {
|
||||
printf("Scan request for instance %u\n", instId);
|
||||
// if the data has already been updated we don't need to change it again.
|
||||
if (!m_updatedSR) {
|
||||
printf("Updating scan data\n");
|
||||
NimBLEExtAdvertisement sr;
|
||||
sr.setServiceData(NimBLEUUID(SERVICE_UUID), std::string("Hello from scan response!"));
|
||||
pAdv->setScanResponseData(inst_id, sr);
|
||||
pAdv->setScanResponseData(instId, sr);
|
||||
m_updatedSR = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
} advCallbacks;
|
||||
|
||||
void app_main (void) {
|
||||
extern "C" void app_main(void) {
|
||||
/** Initialize NimBLE and set the device name */
|
||||
NimBLEDevice::init("Multi advertiser");
|
||||
|
||||
/* Create a server for our legacy advertiser */
|
||||
/** Create a server for our legacy advertiser */
|
||||
NimBLEServer* pServer = NimBLEDevice::createServer();
|
||||
pServer->setCallbacks(new ServerCallbacks);
|
||||
pServer->setCallbacks(&serverCallbacks);
|
||||
|
||||
NimBLEService* pService = pServer->createService(SERVICE_UUID);
|
||||
NimBLECharacteristic *pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID,
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE |
|
||||
NIMBLE_PROPERTY::NOTIFY);
|
||||
NimBLECharacteristic* pCharacteristic =
|
||||
pService->createCharacteristic(CHARACTERISTIC_UUID,
|
||||
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::NOTIFY);
|
||||
|
||||
pCharacteristic->setValue("Hello World");
|
||||
|
||||
/* Start the service */
|
||||
/** Start the service */
|
||||
pService->start();
|
||||
|
||||
/* Create our multi advertising instances */
|
||||
/** Create our multi advertising instances */
|
||||
|
||||
// extended scannable instance advertising on coded and 1m PHY's.
|
||||
/** extended scannable instance advertising on coded and 1m PHY's. */
|
||||
NimBLEExtAdvertisement extScannable(primaryPhy, secondaryPhy);
|
||||
|
||||
// Legacy advertising as a connectable device.
|
||||
/** Legacy advertising as a connectable device. */
|
||||
NimBLEExtAdvertisement legacyConnectable;
|
||||
|
||||
// Optional scan response data.
|
||||
/** Optional scan response data. */
|
||||
NimBLEExtAdvertisement legacyScanResponse;
|
||||
|
||||
/* As per Bluetooth specification, extended advertising cannot be both scannable and connectable */
|
||||
/** As per Bluetooth specification, extended advertising cannot be both scannable and connectable */
|
||||
extScannable.setScannable(true);
|
||||
extScannable.setConnectable(false);
|
||||
|
||||
/* Set the initial data */
|
||||
/** Set the initial data */
|
||||
extScannable.setServiceData(NimBLEUUID(SERVICE_UUID), std::string("Scan me!"));
|
||||
|
||||
/* enable the scan response callback, we will use this to update the data. */
|
||||
/** Enable the scan response callback, we will use this to update the data. */
|
||||
extScannable.enableScanRequestCallback(true);
|
||||
|
||||
/* Optional custom address for this advertisment. */
|
||||
/** Optional custom address for this advertisment. */
|
||||
legacyConnectable.setAddress(NimBLEAddress("DE:AD:BE:EF:BA:AD"));
|
||||
|
||||
/* Set the advertising data. */
|
||||
/** Set the advertising data. */
|
||||
legacyConnectable.setName("Legacy");
|
||||
legacyConnectable.setCompleteServices16({NimBLEUUID(SERVICE_UUID)});
|
||||
|
||||
/* Set the legacy and connectable flags. */
|
||||
/** Set the legacy and connectable flags. */
|
||||
legacyConnectable.setLegacyAdvertising(true);
|
||||
legacyConnectable.setConnectable(true);
|
||||
|
||||
/* Put some data in the scan response if desired. */
|
||||
/** Put some data in the scan response if desired. */
|
||||
legacyScanResponse.setServiceData(NimBLEUUID(SERVICE_UUID), "Legacy SR");
|
||||
|
||||
/* Get the advertising ready */
|
||||
/** Get the advertising ready */
|
||||
NimBLEExtAdvertising* pAdvertising = NimBLEDevice::getAdvertising();
|
||||
|
||||
/* Set the callbacks to handle advertising events */
|
||||
pAdvertising->setCallbacks(new advCallbacks);
|
||||
/** Set the callbacks to handle advertising events */
|
||||
pAdvertising->setCallbacks(&advCallbacks);
|
||||
|
||||
/* Set instance data.
|
||||
/**
|
||||
* Set instance data.
|
||||
* Up to 5 instances can be used if configured in menuconfig, instance 0 is always available.
|
||||
*
|
||||
* We will set the extended scannable data on instance 0 and the legacy data on instance 1.
|
||||
* Note that the legacy scan response data needs to be set to the same instance (1).
|
||||
*/
|
||||
if (pAdvertising->setInstanceData( 0, extScannable ) &&
|
||||
pAdvertising->setInstanceData( 1, legacyConnectable ) &&
|
||||
if (pAdvertising->setInstanceData(0, extScannable) && pAdvertising->setInstanceData(1, legacyConnectable) &&
|
||||
pAdvertising->setScanResponseData(1, legacyScanResponse)) {
|
||||
/*
|
||||
* `NimBLEExtAdvertising::start` takes the advertisement instance ID to start
|
||||
/**
|
||||
* NimBLEExtAdvertising::start takes the advertisement instance ID to start
|
||||
* and a duration in milliseconds or a max number of advertisements to send (or both).
|
||||
*/
|
||||
if (pAdvertising->start(0, advTime) && pAdvertising->start(1, advTime)) {
|
||||
|
@ -163,7 +161,7 @@ void app_main (void) {
|
|||
printf("Failed to start advertising\n");
|
||||
}
|
||||
} else {
|
||||
printf("Failed to register advertisment data\n");
|
||||
printf("Failed to register advertisement data\n");
|
||||
}
|
||||
|
||||
esp_sleep_enable_timer_wakeup(sleepTime * 1000000);
|
||||
|
|
|
@ -9,21 +9,22 @@
|
|||
*
|
||||
* Created: on March 24 2020
|
||||
* Author: H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#include "NimBLEDevice.h"
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
static constexpr uint32_t scanTime = 30 * 1000; // 30 seconds scan time.
|
||||
|
||||
class scanCallbacks : public NimBLEScanCallbacks {
|
||||
// Initial discovery, advertisement data only.
|
||||
/** Initial discovery, advertisement data only. */
|
||||
void onDiscovered(const NimBLEAdvertisedDevice* advertisedDevice) override {
|
||||
printf("Discovered Device: %s\n", advertisedDevice->toString().c_str());
|
||||
}
|
||||
|
||||
// If active scanning the result here will have the scan response data.
|
||||
// If not active scanning then this will be the same as onDiscovered.
|
||||
/**
|
||||
* If active scanning the result here will have the scan response data.
|
||||
* If not active scanning then this will be the same as onDiscovered.
|
||||
*/
|
||||
void onResult(const NimBLEAdvertisedDevice* advertisedDevice) override {
|
||||
printf("Device result: %s\n", advertisedDevice->toString().c_str());
|
||||
}
|
||||
|
@ -32,7 +33,7 @@ class scanCallbacks : public NimBLEScanCallbacks {
|
|||
printf("Scan ended reason = %d; restarting scan\n", reason);
|
||||
NimBLEDevice::getScan()->start(scanTime, false, true);
|
||||
}
|
||||
} scanCallbacks; // create a callback class instance.
|
||||
} scanCallbacks;
|
||||
|
||||
extern "C" void app_main() {
|
||||
NimBLEDevice::init(""); // Initialize the device, you can specify a device name if you want.
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
PROJECT_NAME := NimBLE_Async_Client
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
|
@ -1,4 +0,0 @@
|
|||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
|
@ -6,7 +6,6 @@
|
|||
*
|
||||
* Created: on November 4, 2024
|
||||
* Author: H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
@ -14,22 +13,23 @@
|
|||
static constexpr uint32_t scanTimeMs = 5 * 1000;
|
||||
|
||||
class ClientCallbacks : public NimBLEClientCallbacks {
|
||||
void onConnect(NimBLEClient* pClient) {
|
||||
void onConnect(NimBLEClient* pClient) override {
|
||||
printf("Connected to: %s\n", pClient->getPeerAddress().toString().c_str());
|
||||
}
|
||||
|
||||
void onDisconnect(NimBLEClient* pClient, int reason) {
|
||||
void onDisconnect(NimBLEClient* pClient, int reason) override {
|
||||
printf("%s Disconnected, reason = %d - Starting scan\n", pClient->getPeerAddress().toString().c_str(), reason);
|
||||
NimBLEDevice::getScan()->start(scanTimeMs);
|
||||
}
|
||||
} clientCB;
|
||||
} clientCallbacks;
|
||||
|
||||
class scanCallbacks : public NimBLEScanCallbacks {
|
||||
void onResult(const NimBLEAdvertisedDevice* advertisedDevice) {
|
||||
class ScanCallbacks : public NimBLEScanCallbacks {
|
||||
void onResult(const NimBLEAdvertisedDevice* advertisedDevice) override {
|
||||
printf("Advertised Device found: %s\n", advertisedDevice->toString().c_str());
|
||||
if (advertisedDevice->haveName() && advertisedDevice->getName() == "NimBLE-Server") {
|
||||
printf("Found Our Device\n");
|
||||
|
||||
/** Async connections can be made directly in the scan callbacks */
|
||||
auto pClient = NimBLEDevice::getDisconnectedClient();
|
||||
if (!pClient) {
|
||||
pClient = NimBLEDevice::createClient(advertisedDevice->getAddress());
|
||||
|
@ -39,7 +39,7 @@ class scanCallbacks : public NimBLEScanCallbacks {
|
|||
}
|
||||
}
|
||||
|
||||
pClient->setClientCallbacks(&clientCB, false);
|
||||
pClient->setClientCallbacks(&clientCallbacks, false);
|
||||
if (!pClient->connect(true, true, false)) { // delete attributes, async connect, no MTU exchange
|
||||
NimBLEDevice::deleteClient(pClient);
|
||||
printf("Failed to connect\n");
|
||||
|
@ -48,19 +48,19 @@ class scanCallbacks : public NimBLEScanCallbacks {
|
|||
}
|
||||
}
|
||||
|
||||
void onScanEnd(const NimBLEScanResults&, int reason) {
|
||||
void onScanEnd(const NimBLEScanResults& results, int reason) override {
|
||||
printf("Scan Ended\n");
|
||||
NimBLEDevice::getScan()->start(scanTimeMs);
|
||||
}
|
||||
};
|
||||
} scanCallbacks;
|
||||
|
||||
extern "C" void app_main(void) {
|
||||
printf("Starting NimBLE Async Client\n");
|
||||
NimBLEDevice::init("");
|
||||
NimBLEDevice::init("Async-Client");
|
||||
NimBLEDevice::setPower(3); /** +3db */
|
||||
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
pScan->setScanCallbacks(new scanCallbacks());
|
||||
pScan->setScanCallbacks(&scanCallbacks);
|
||||
pScan->setInterval(45);
|
||||
pScan->setWindow(15);
|
||||
pScan->setActiveScan(true);
|
||||
|
|
|
@ -3,5 +3,4 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(SUPPORTED_TARGETS esp32)
|
||||
project(NimBLE_Client)
|
305
examples/NimBLE_Client/main/main.cpp
Normal file
305
examples/NimBLE_Client/main/main.cpp
Normal file
|
@ -0,0 +1,305 @@
|
|||
|
||||
/** NimBLE_Client Demo:
|
||||
*
|
||||
* Demonstrates many of the available features of the NimBLE client library.
|
||||
*
|
||||
* Created: on March 24 2020
|
||||
* Author: H2zero
|
||||
*/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
static const NimBLEAdvertisedDevice* advDevice;
|
||||
static bool doConnect = false;
|
||||
static uint32_t scanTime = 5000; /** scan time in milliseconds, 0 = scan forever */
|
||||
|
||||
/** None of these are required as they will be handled by the library with defaults. **
|
||||
** Remove as you see fit for your needs */
|
||||
class ClientCallbacks : public NimBLEClientCallbacks {
|
||||
void onConnect(NimBLEClient* pClient) override { printf("Connected\n"); }
|
||||
|
||||
void onDisconnect(NimBLEClient* pClient, int reason) override {
|
||||
printf("%s Disconnected, reason = %d - Starting scan\n", pClient->getPeerAddress().toString().c_str(), reason);
|
||||
NimBLEDevice::getScan()->start(scanTime, false, true);
|
||||
}
|
||||
|
||||
/********************* Security handled here *********************/
|
||||
void onPassKeyEntry(NimBLEConnInfo& connInfo) override {
|
||||
printf("Server Passkey Entry\n");
|
||||
/**
|
||||
* This should prompt the user to enter the passkey displayed
|
||||
* on the peer device.
|
||||
*/
|
||||
NimBLEDevice::injectPassKey(connInfo, 123456);
|
||||
}
|
||||
|
||||
void onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t pass_key) override {
|
||||
printf("The passkey YES/NO number: %" PRIu32 "\n", pass_key);
|
||||
/** Inject false if passkeys don't match. */
|
||||
NimBLEDevice::injectConfirmPasskey(connInfo, true);
|
||||
}
|
||||
|
||||
/** Pairing process complete, we can check the results in connInfo */
|
||||
void onAuthenticationComplete(NimBLEConnInfo& connInfo) override {
|
||||
if (!connInfo.isEncrypted()) {
|
||||
printf("Encrypt connection failed - disconnecting\n");
|
||||
/** Find the client with the connection handle provided in connInfo */
|
||||
NimBLEDevice::getClientByHandle(connInfo.getConnHandle())->disconnect();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} clientCB;
|
||||
|
||||
/** Define a class to handle the callbacks when scan events are received */
|
||||
class scanCallbacks : public NimBLEScanCallbacks {
|
||||
void onResult(const NimBLEAdvertisedDevice* advertisedDevice) override {
|
||||
printf("Advertised Device found: %s\n", advertisedDevice->toString().c_str());
|
||||
if (advertisedDevice->isAdvertisingService(NimBLEUUID("DEAD"))) {
|
||||
printf("Found Our Service\n");
|
||||
/** stop scan before connecting */
|
||||
NimBLEDevice::getScan()->stop();
|
||||
/** Save the device reference in a global for the client to use*/
|
||||
advDevice = advertisedDevice;
|
||||
/** Ready to connect now */
|
||||
doConnect = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Callback to process the results of the completed scan or restart it */
|
||||
void onScanEnd(const NimBLEScanResults& results, int reason) override {
|
||||
printf("Scan Ended, reason: %d, device count: %d; Restarting scan\n", reason, results.getCount());
|
||||
NimBLEDevice::getScan()->start(scanTime, false, true);
|
||||
}
|
||||
} scanCB;
|
||||
|
||||
/** Notification / Indication receiving handler callback */
|
||||
void notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) {
|
||||
std::string str = (isNotify == true) ? "Notification" : "Indication";
|
||||
str += " from ";
|
||||
str += pRemoteCharacteristic->getClient()->getPeerAddress().toString();
|
||||
str += ": Service = " + pRemoteCharacteristic->getRemoteService()->getUUID().toString();
|
||||
str += ", Characteristic = " + pRemoteCharacteristic->getUUID().toString();
|
||||
str += ", Value = " + std::string((char*)pData, length);
|
||||
printf("%s\n", str.c_str());
|
||||
}
|
||||
|
||||
/** Handles the provisioning of clients and connects / interfaces with the server */
|
||||
bool connectToServer() {
|
||||
NimBLEClient* pClient = nullptr;
|
||||
|
||||
/** Check if we have a client we should reuse first **/
|
||||
if (NimBLEDevice::getCreatedClientCount()) {
|
||||
/**
|
||||
* Special case when we already know this device, we send false as the
|
||||
* second argument in connect() to prevent refreshing the service database.
|
||||
* This saves considerable time and power.
|
||||
*/
|
||||
pClient = NimBLEDevice::getClientByPeerAddress(advDevice->getAddress());
|
||||
if (pClient) {
|
||||
if (!pClient->connect(advDevice, false)) {
|
||||
printf("Reconnect failed\n");
|
||||
return false;
|
||||
}
|
||||
printf("Reconnected client\n");
|
||||
} else {
|
||||
/**
|
||||
* We don't already have a client that knows this device,
|
||||
* check for a client that is disconnected that we can use.
|
||||
*/
|
||||
pClient = NimBLEDevice::getDisconnectedClient();
|
||||
}
|
||||
}
|
||||
|
||||
/** No client to reuse? Create a new one. */
|
||||
if (!pClient) {
|
||||
if (NimBLEDevice::getCreatedClientCount() >= NIMBLE_MAX_CONNECTIONS) {
|
||||
printf("Max clients reached - no more connections available\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
pClient = NimBLEDevice::createClient();
|
||||
|
||||
printf("New client created\n");
|
||||
|
||||
pClient->setClientCallbacks(&clientCB, false);
|
||||
/**
|
||||
* Set initial connection parameters:
|
||||
* 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.
|
||||
* Min interval: 12 * 1.25ms = 15, Max interval: 12 * 1.25ms = 15, 0 latency, 150 * 10ms = 1500ms timeout
|
||||
*/
|
||||
pClient->setConnectionParams(12, 12, 0, 150);
|
||||
|
||||
/** Set how long we are willing to wait for the connection to complete (milliseconds), default is 30000. */
|
||||
pClient->setConnectTimeout(5 * 1000);
|
||||
|
||||
if (!pClient->connect(advDevice)) {
|
||||
/** Created a client but failed to connect, don't need to keep it as it has no data */
|
||||
NimBLEDevice::deleteClient(pClient);
|
||||
printf("Failed to connect, deleted client\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pClient->isConnected()) {
|
||||
if (!pClient->connect(advDevice)) {
|
||||
printf("Failed to connect\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Connected to: %s RSSI: %d\n", pClient->getPeerAddress().toString().c_str(), pClient->getRssi());
|
||||
|
||||
/** Now we can read/write/subscribe the characteristics of the services we are interested in */
|
||||
NimBLERemoteService* pSvc = nullptr;
|
||||
NimBLERemoteCharacteristic* pChr = nullptr;
|
||||
NimBLERemoteDescriptor* pDsc = nullptr;
|
||||
|
||||
pSvc = pClient->getService("DEAD");
|
||||
if (pSvc) {
|
||||
pChr = pSvc->getCharacteristic("BEEF");
|
||||
}
|
||||
|
||||
if (pChr) {
|
||||
if (pChr->canRead()) {
|
||||
printf("%s Value: %s\n", pChr->getUUID().toString().c_str(), pChr->readValue().c_str());
|
||||
}
|
||||
|
||||
if (pChr->canWrite()) {
|
||||
if (pChr->writeValue("Tasty")) {
|
||||
printf("Wrote new value to: %s\n", pChr->getUUID().toString().c_str());
|
||||
} else {
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pChr->canRead()) {
|
||||
printf("The value of: %s is now: %s\n", pChr->getUUID().toString().c_str(), pChr->readValue().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (pChr->canNotify()) {
|
||||
if (!pChr->subscribe(true, notifyCB)) {
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
} else if (pChr->canIndicate()) {
|
||||
/** Send false as first argument to subscribe to indications instead of notifications */
|
||||
if (!pChr->subscribe(false, notifyCB)) {
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf("DEAD service not found.\n");
|
||||
}
|
||||
|
||||
pSvc = pClient->getService("BAAD");
|
||||
if (pSvc) {
|
||||
pChr = pSvc->getCharacteristic("F00D");
|
||||
if (pChr) {
|
||||
if (pChr->canRead()) {
|
||||
printf("%s Value: %s\n", pChr->getUUID().toString().c_str(), pChr->readValue().c_str());
|
||||
}
|
||||
|
||||
pDsc = pChr->getDescriptor(NimBLEUUID("C01D"));
|
||||
if (pDsc) {
|
||||
printf("Descriptor: %s Value: %s\n", pDsc->getUUID().toString().c_str(), pDsc->readValue().c_str());
|
||||
}
|
||||
|
||||
if (pChr->canWrite()) {
|
||||
if (pChr->writeValue("No tip!")) {
|
||||
printf("Wrote new value to: %s\n", pChr->getUUID().toString().c_str());
|
||||
} else {
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pChr->canRead()) {
|
||||
printf("The value of: %s is now: %s\n", pChr->getUUID().toString().c_str(), pChr->readValue().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (pChr->canNotify()) {
|
||||
if (!pChr->subscribe(true, notifyCB)) {
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
} else if (pChr->canIndicate()) {
|
||||
/** Send false as first argument to subscribe to indications instead of notifications */
|
||||
if (!pChr->subscribe(false, notifyCB)) {
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf("BAAD service not found.\n");
|
||||
}
|
||||
|
||||
printf("Done with this device!\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
void app_main(void) {
|
||||
printf("Starting NimBLE Client\n");
|
||||
/** Initialize NimBLE and set the device name */
|
||||
NimBLEDevice::init("NimBLE-Client");
|
||||
|
||||
/**
|
||||
* 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_DISPLAY_YESNO - Numeric comparison pairing
|
||||
* BLE_HS_IO_NO_INPUT_OUTPUT - DEFAULT setting - just works pairing
|
||||
*/
|
||||
// NimBLEDevice::setSecurityIOCap(BLE_HS_IO_KEYBOARD_ONLY); // use passkey
|
||||
// NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO); //use numeric comparison
|
||||
|
||||
/**
|
||||
* 2 different ways to set security - both calls achieve the same result.
|
||||
* no bonding, no man in the middle protection, BLE secure connections.
|
||||
* These are the default values, only shown here for demonstration.
|
||||
*/
|
||||
// NimBLEDevice::setSecurityAuth(false, false, true);
|
||||
|
||||
NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC);
|
||||
|
||||
/** Optional: set the transmit power */
|
||||
NimBLEDevice::setPower(3); // 9dbm
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
|
||||
/** Set the callbacks to call when scan events occur, no duplicates */
|
||||
pScan->setScanCallbacks(&scanCB, false);
|
||||
|
||||
/** Set scan interval (how often) and window (how long) in milliseconds */
|
||||
pScan->setInterval(100);
|
||||
pScan->setWindow(100);
|
||||
|
||||
/**
|
||||
* Active scan will gather scan response data from advertisers
|
||||
* but will use more energy from both devices
|
||||
*/
|
||||
pScan->setActiveScan(true);
|
||||
|
||||
/** Start scanning for advertisers */
|
||||
pScan->start(scanTime);
|
||||
printf("Scanning for peripherals\n");
|
||||
|
||||
/** Loop here until we find a device we want to connect to */
|
||||
for (;;) {
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
|
||||
if (doConnect) {
|
||||
doConnect = false;
|
||||
/** Found a device we want to connect to, do it now */
|
||||
if (connectToServer()) {
|
||||
printf("Success! we should now be getting notifications, scanning for more!\n");
|
||||
} else {
|
||||
printf("Failed to connect, starting scan\n");
|
||||
}
|
||||
|
||||
NimBLEDevice::getScan()->start(scanTime, false, true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,5 +3,4 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(SUPPORTED_TARGETS esp32)
|
||||
project(NimBLE_Server)
|
|
@ -1,104 +1,94 @@
|
|||
|
||||
/** NimBLE_Server Demo:
|
||||
/**
|
||||
* NimBLE_Server Demo:
|
||||
*
|
||||
* Demonstrates many of the available features of the NimBLE server library.
|
||||
*
|
||||
* Created: on March 22 2020
|
||||
* Author: H2zero
|
||||
*
|
||||
*/
|
||||
#include "NimBLEDevice.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
extern "C" {void app_main(void);}
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
static NimBLEServer* pServer;
|
||||
|
||||
/** None of these are required as they will be handled by the library with defaults. **
|
||||
** Remove as you see fit for your needs */
|
||||
class ServerCallbacks : public NimBLEServerCallbacks {
|
||||
void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) {
|
||||
void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) override {
|
||||
printf("Client address: %s\n", connInfo.getAddress().toString().c_str());
|
||||
|
||||
/** We can use the connection handle here to ask for different connection parameters.
|
||||
/**
|
||||
* We can use the connection handle here to ask for different connection parameters.
|
||||
* Args: connection handle, min connection interval, max connection interval
|
||||
* latency, supervision timeout.
|
||||
* Units; Min/Max Intervals: 1.25 millisecond increments.
|
||||
* Latency: number of intervals allowed to skip.
|
||||
* Timeout: 10 millisecond increments, try for 3x interval time for best results.
|
||||
* Timeout: 10 millisecond increments.
|
||||
*/
|
||||
pServer->updateConnParams(connInfo.getConnHandle(), 24, 48, 0, 18);
|
||||
};
|
||||
}
|
||||
|
||||
void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) {
|
||||
void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) override {
|
||||
printf("Client disconnected - start advertising\n");
|
||||
NimBLEDevice::startAdvertising();
|
||||
};
|
||||
}
|
||||
|
||||
void onMTUChange(uint16_t MTU, NimBLEConnInfo& connInfo) {
|
||||
void onMTUChange(uint16_t MTU, NimBLEConnInfo& connInfo) override {
|
||||
printf("MTU updated: %u for connection ID: %u\n", MTU, connInfo.getConnHandle());
|
||||
pServer->updateConnParams(connInfo.getConnHandle(), 24, 48, 0, 60);
|
||||
};
|
||||
}
|
||||
|
||||
/********************* Security handled here **********************
|
||||
****** Note: these are the same return values as defaults ********/
|
||||
uint32_t onPassKeyDisplay(){
|
||||
/********************* Security handled here *********************/
|
||||
uint32_t onPassKeyDisplay() override {
|
||||
printf("Server Passkey Display\n");
|
||||
/** This should return a random 6 digit number for security
|
||||
/**
|
||||
* This should return a random 6 digit number for security
|
||||
* or make your own static passkey as done here.
|
||||
*/
|
||||
return 123456;
|
||||
};
|
||||
}
|
||||
|
||||
void onConfirmasskeyN(NimBLEConnInfo& connInfo, uint32_t pass_key){
|
||||
void onConfirmPassKey(NimBLEConnInfo& connInfo, uint32_t pass_key) override {
|
||||
printf("The passkey YES/NO number: %" PRIu32 "\n", pass_key);
|
||||
/** Inject false if passkeys don't match. */
|
||||
NimBLEDevice::injectConfirmPasskey(connInfo, true);
|
||||
};
|
||||
}
|
||||
|
||||
void onAuthenticationComplete(NimBLEConnInfo& connInfo){
|
||||
void onAuthenticationComplete(NimBLEConnInfo& connInfo) override {
|
||||
/** Check that encryption was successful, if not we disconnect the client */
|
||||
if (!connInfo.isEncrypted()) {
|
||||
NimBLEDevice::getServer()->disconnect(connInfo.getConnHandle());
|
||||
printf("Encrypt connection failed - disconnecting client\n");
|
||||
return;
|
||||
}
|
||||
printf("Starting BLE work!");
|
||||
};
|
||||
};
|
||||
|
||||
printf("Secured connection to: %s\n", connInfo.getAddress().toString().c_str());
|
||||
}
|
||||
} serverCallbacks;
|
||||
|
||||
/** Handler class for characteristic actions */
|
||||
class CharacteristicCallbacks : public NimBLECharacteristicCallbacks {
|
||||
void onRead(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo) {
|
||||
void onRead(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo) override {
|
||||
printf("%s : onRead(), value: %s\n",
|
||||
pCharacteristic->getUUID().toString().c_str(),
|
||||
pCharacteristic->getValue().c_str());
|
||||
}
|
||||
|
||||
void onWrite(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo) {
|
||||
void onWrite(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo) override {
|
||||
printf("%s : onWrite(), value: %s\n",
|
||||
pCharacteristic->getUUID().toString().c_str(),
|
||||
pCharacteristic->getValue().c_str());
|
||||
}
|
||||
|
||||
/** Called before notification or indication is sent,
|
||||
* the value can be changed here before sending if desired.
|
||||
*/
|
||||
void onNotify(NimBLECharacteristic* pCharacteristic) {
|
||||
printf("Sending notification to clients\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* The value returned in code is the NimBLE host return code.
|
||||
*/
|
||||
void onStatus(NimBLECharacteristic* pCharacteristic, int code) {
|
||||
printf("Notification/Indication return code: %d, %s\n",
|
||||
code, NimBLEUtils::returnCodeToString(code));
|
||||
void onStatus(NimBLECharacteristic* pCharacteristic, int code) override {
|
||||
printf("Notification/Indication return code: %d, %s\n", code, NimBLEUtils::returnCodeToString(code));
|
||||
}
|
||||
|
||||
void onSubscribe(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo, uint16_t subValue) {
|
||||
/** Peer subscribed to notifications/indications */
|
||||
void onSubscribe(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo, uint16_t subValue) override {
|
||||
std::string str = "Client ID: ";
|
||||
str += connInfo.getConnHandle();
|
||||
str += " Address: ";
|
||||
|
@ -106,7 +96,7 @@ class CharacteristicCallbacks: public NimBLECharacteristicCallbacks {
|
|||
if (subValue == 0) {
|
||||
str += " Unsubscribed to ";
|
||||
} else if (subValue == 1) {
|
||||
str += " Subscribed to notfications for ";
|
||||
str += " Subscribed to notifications for ";
|
||||
} else if (subValue == 2) {
|
||||
str += " Subscribed to indications for ";
|
||||
} else if (subValue == 3) {
|
||||
|
@ -116,26 +106,103 @@ class CharacteristicCallbacks: public NimBLECharacteristicCallbacks {
|
|||
|
||||
printf("%s\n", str.c_str());
|
||||
}
|
||||
};
|
||||
} chrCallbacks;
|
||||
|
||||
/** Handler class for descriptor actions */
|
||||
class DescriptorCallbacks : public NimBLEDescriptorCallbacks {
|
||||
void onWrite(NimBLEDescriptor* pDescriptor, NimBLEConnInfo& connInfo) {
|
||||
void onWrite(NimBLEDescriptor* pDescriptor, NimBLEConnInfo& connInfo) override {
|
||||
std::string dscVal = pDescriptor->getValue();
|
||||
printf("Descriptor witten value: %s\n", dscVal.c_str());
|
||||
};
|
||||
printf("Descriptor written value: %s\n", dscVal.c_str());
|
||||
}
|
||||
|
||||
void onRead(NimBLEDescriptor* pDescriptor, NimBLEConnInfo& connInfo) {
|
||||
void onRead(NimBLEDescriptor* pDescriptor, NimBLEConnInfo& connInfo) override {
|
||||
printf("%s Descriptor read\n", pDescriptor->getUUID().toString().c_str());
|
||||
};;
|
||||
};
|
||||
}
|
||||
} dscCallbacks;
|
||||
|
||||
extern "C" void app_main(void) {
|
||||
printf("Starting NimBLE Server\n");
|
||||
|
||||
/** Define callback instances globally to use for multiple Charateristics \ Descriptors */
|
||||
static DescriptorCallbacks dscCallbacks;
|
||||
static CharacteristicCallbacks chrCallbacks;
|
||||
/** Initialize NimBLE and set the device name */
|
||||
NimBLEDevice::init("NimBLE");
|
||||
|
||||
void notifyTask(void * parameter){
|
||||
/**
|
||||
* Set the IO capabilities of the device, each option will trigger a different pairing method.
|
||||
* BLE_HS_IO_DISPLAY_ONLY - Passkey pairing
|
||||
* BLE_HS_IO_DISPLAY_YESNO - Numeric comparison pairing
|
||||
* BLE_HS_IO_NO_INPUT_OUTPUT - DEFAULT setting - just works pairing
|
||||
*/
|
||||
// NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY); // use passkey
|
||||
// NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO); //use numeric comparison
|
||||
|
||||
/**
|
||||
* 2 different ways to set security - both calls achieve the same result.
|
||||
* no bonding, no man in the middle protection, BLE secure connections.
|
||||
*
|
||||
* These are the default values, only shown here for demonstration.
|
||||
*/
|
||||
// NimBLEDevice::setSecurityAuth(false, false, true);
|
||||
|
||||
NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC);
|
||||
pServer = NimBLEDevice::createServer();
|
||||
pServer->setCallbacks(&serverCallbacks);
|
||||
|
||||
NimBLEService* pDeadService = pServer->createService("DEAD");
|
||||
NimBLECharacteristic* pBeefCharacteristic =
|
||||
pDeadService->createCharacteristic("BEEF",
|
||||
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE |
|
||||
/** Require a secure connection for read and write access */
|
||||
NIMBLE_PROPERTY::READ_ENC | // only allow reading if paired / encrypted
|
||||
NIMBLE_PROPERTY::WRITE_ENC // only allow writing if paired / encrypted
|
||||
);
|
||||
|
||||
pBeefCharacteristic->setValue("Burger");
|
||||
pBeefCharacteristic->setCallbacks(&chrCallbacks);
|
||||
|
||||
/**
|
||||
* 2902 and 2904 descriptors are a special case, when createDescriptor is called with
|
||||
* either of those uuid's it will create the associated class with the correct properties
|
||||
* and sizes. However we must cast the returned reference to the correct type as the method
|
||||
* only returns a pointer to the base NimBLEDescriptor class.
|
||||
*/
|
||||
NimBLE2904* pBeef2904 = pBeefCharacteristic->create2904();
|
||||
pBeef2904->setFormat(NimBLE2904::FORMAT_UTF8);
|
||||
pBeef2904->setCallbacks(&dscCallbacks);
|
||||
|
||||
NimBLEService* pBaadService = pServer->createService("BAAD");
|
||||
NimBLECharacteristic* pFoodCharacteristic =
|
||||
pBaadService->createCharacteristic("F00D", NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::NOTIFY);
|
||||
|
||||
pFoodCharacteristic->setValue("Fries");
|
||||
pFoodCharacteristic->setCallbacks(&chrCallbacks);
|
||||
|
||||
/** Custom descriptor: Arguments are UUID, Properties, max length of the value in bytes */
|
||||
NimBLEDescriptor* pC01Ddsc =
|
||||
pFoodCharacteristic->createDescriptor("C01D",
|
||||
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_ENC,
|
||||
20);
|
||||
pC01Ddsc->setValue("Send it back!");
|
||||
pC01Ddsc->setCallbacks(&dscCallbacks);
|
||||
|
||||
/** Start the services when finished creating all Characteristics and Descriptors */
|
||||
pDeadService->start();
|
||||
pBaadService->start();
|
||||
|
||||
/** Create an advertising instance and add the services to the advertised data */
|
||||
NimBLEAdvertising* pAdvertising = NimBLEDevice::getAdvertising();
|
||||
pAdvertising->setName("NimBLE-Server");
|
||||
pAdvertising->addServiceUUID(pDeadService->getUUID());
|
||||
pAdvertising->addServiceUUID(pBaadService->getUUID());
|
||||
/**
|
||||
* If your device is battery powered you may consider setting scan response
|
||||
* to false as it will extend battery life at the expense of less data sent.
|
||||
*/
|
||||
pAdvertising->enableScanResponse(true);
|
||||
pAdvertising->start();
|
||||
|
||||
printf("Advertising Started\n");
|
||||
|
||||
/** Loop here and send notifications to connected peers */
|
||||
for (;;) {
|
||||
if (pServer->getConnectedCount()) {
|
||||
NimBLEService* pSvc = pServer->getServiceByUUID("BAAD");
|
||||
|
@ -148,95 +215,4 @@ void notifyTask(void * parameter){
|
|||
}
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void app_main(void) {
|
||||
printf("Starting NimBLE Server\n");
|
||||
|
||||
/** sets device name */
|
||||
NimBLEDevice::init("NimBLE");
|
||||
|
||||
/** Set the IO capabilities of the device, each option will trigger a different pairing method.
|
||||
* BLE_HS_IO_DISPLAY_ONLY - Passkey pairing
|
||||
* BLE_HS_IO_DISPLAY_YESNO - Numeric comparison pairing
|
||||
* BLE_HS_IO_NO_INPUT_OUTPUT - DEFAULT setting - just works pairing
|
||||
*/
|
||||
//NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY); // use passkey
|
||||
//NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO); //use numeric comparison
|
||||
|
||||
/** 2 different ways to set security - both calls achieve the same result.
|
||||
* no bonding, no man in the middle protection, secure connections.
|
||||
*
|
||||
* These are the default values, only shown here for demonstration.
|
||||
*/
|
||||
//NimBLEDevice::setSecurityAuth(false, false, true);
|
||||
NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC);
|
||||
|
||||
pServer = NimBLEDevice::createServer();
|
||||
pServer->setCallbacks(new ServerCallbacks());
|
||||
|
||||
NimBLEService* pDeadService = pServer->createService("DEAD");
|
||||
NimBLECharacteristic* pBeefCharacteristic = pDeadService->createCharacteristic(
|
||||
"BEEF",
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE |
|
||||
/** Require a secure connection for read and write access */
|
||||
NIMBLE_PROPERTY::READ_ENC | // only allow reading if paired / encrypted
|
||||
NIMBLE_PROPERTY::WRITE_ENC // only allow writing if paired / encrypted
|
||||
);
|
||||
|
||||
pBeefCharacteristic->setValue("Burger");
|
||||
pBeefCharacteristic->setCallbacks(&chrCallbacks);
|
||||
|
||||
/** 2902 and 2904 descriptors are a special case, when createDescriptor is called with
|
||||
* either of those uuid's it will create the associated class with the correct properties
|
||||
* and sizes. However we must cast the returned reference to the correct type as the method
|
||||
* only returns a pointer to the base NimBLEDescriptor class.
|
||||
*/
|
||||
NimBLE2904* pBeef2904 = pBeefCharacteristic->create2904();
|
||||
pBeef2904->setFormat(NimBLE2904::FORMAT_UTF8);
|
||||
pBeef2904->setCallbacks(&dscCallbacks);
|
||||
|
||||
|
||||
NimBLEService* pBaadService = pServer->createService("BAAD");
|
||||
NimBLECharacteristic* pFoodCharacteristic = pBaadService->createCharacteristic(
|
||||
"F00D",
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE |
|
||||
NIMBLE_PROPERTY::NOTIFY
|
||||
);
|
||||
|
||||
pFoodCharacteristic->setValue("Fries");
|
||||
pFoodCharacteristic->setCallbacks(&chrCallbacks);
|
||||
|
||||
/** Custom descriptor: Arguments are UUID, Properties, max length in bytes of the value */
|
||||
NimBLEDescriptor* pC01Ddsc = pFoodCharacteristic->createDescriptor(
|
||||
"C01D",
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE|
|
||||
NIMBLE_PROPERTY::WRITE_ENC, // only allow writing if paired / encrypted
|
||||
20
|
||||
);
|
||||
pC01Ddsc->setValue("Send it back!");
|
||||
pC01Ddsc->setCallbacks(&dscCallbacks);
|
||||
|
||||
/** Start the services when finished creating all Characteristics and Descriptors */
|
||||
pDeadService->start();
|
||||
pBaadService->start();
|
||||
|
||||
NimBLEAdvertising* pAdvertising = NimBLEDevice::getAdvertising();
|
||||
/** Add the services to the advertisment data **/
|
||||
pAdvertising->addServiceUUID(pDeadService->getUUID());
|
||||
pAdvertising->addServiceUUID(pBaadService->getUUID());
|
||||
/** If your device is battery powered you may consider setting scan response
|
||||
* to false as it will extend battery life at the expense of less data sent.
|
||||
*/
|
||||
pAdvertising->enableScanResponse(true);
|
||||
pAdvertising->start();
|
||||
|
||||
printf("Advertising Started\n");
|
||||
|
||||
xTaskCreate(notifyTask, "notifyTask", 5000, NULL, 1, NULL);
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(SUPPORTED_TARGETS esp32)
|
||||
project(NimBLE_server_get_client_name)
|
|
@ -1,4 +0,0 @@
|
|||
set(COMPONENT_SRCS "main.cpp")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
|
@ -1,83 +0,0 @@
|
|||
/** NimBLE_server_get_client_name
|
||||
*
|
||||
* Demonstrates 2 ways for the server to read the device name from the connected client.
|
||||
*
|
||||
* Created: on June 24 2024
|
||||
* Author: H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
// See the following for generating UUIDs:
|
||||
// https://www.uuidgenerator.net/
|
||||
|
||||
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
|
||||
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
|
||||
#define ENC_CHARACTERISTIC_UUID "9551f35b-8d91-42e4-8f7e-1358dfe272dc"
|
||||
|
||||
NimBLEServer* pServer;
|
||||
|
||||
class ServerCallbacks : public NimBLEServerCallbacks {
|
||||
// Same as before but now includes the name parameter
|
||||
void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, std::string& name) override {
|
||||
printf("Client address: %s Name: %s\n", connInfo.getAddress().toString().c_str(), name.c_str());
|
||||
}
|
||||
|
||||
// Same as before but now includes the name parameter
|
||||
void onAuthenticationComplete(NimBLEConnInfo& connInfo, const std::string& name) override {
|
||||
if (!connInfo.isEncrypted()) {
|
||||
NimBLEDevice::getServer()->disconnect(connInfo.getConnHandle());
|
||||
printf("Encrypt connection failed - disconnecting client\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Encrypted Client address: %s Name: %s\n", connInfo.getAddress().toString().c_str(), name.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" void app_main(void) {
|
||||
printf("Starting BLE Server!\n");
|
||||
|
||||
NimBLEDevice::init("Connect to me!");
|
||||
NimBLEDevice::setSecurityAuth(true, false, true); // Enable bonding to see full name on phones.
|
||||
|
||||
pServer = NimBLEDevice::createServer();
|
||||
NimBLEService* pService = pServer->createService(SERVICE_UUID);
|
||||
NimBLECharacteristic* pCharacteristic =
|
||||
pService->createCharacteristic(CHARACTERISTIC_UUID, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE);
|
||||
pCharacteristic->setValue("Hello World says NimBLE!");
|
||||
|
||||
NimBLECharacteristic* pEncCharacteristic = pService->createCharacteristic(
|
||||
ENC_CHARACTERISTIC_UUID,
|
||||
(NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC));
|
||||
pEncCharacteristic->setValue("Hello World says NimBLE Encrypted");
|
||||
|
||||
pService->start();
|
||||
|
||||
pServer->setCallbacks(new ServerCallbacks());
|
||||
pServer->getPeerNameOnConnect(true); // Setting this will enable the onConnect callback that provides the name.
|
||||
|
||||
BLEAdvertising* pAdvertising = NimBLEDevice::getAdvertising();
|
||||
pAdvertising->addServiceUUID(SERVICE_UUID);
|
||||
pAdvertising->enableScanResponse(true);
|
||||
|
||||
pAdvertising->start();
|
||||
printf("Advertising started, connect with your phone.\n");
|
||||
|
||||
while (true) {
|
||||
auto clientCount = pServer->getConnectedCount();
|
||||
if (clientCount) {
|
||||
printf("Connected clients:\n");
|
||||
for (auto i = 0; i < clientCount; ++i) {
|
||||
NimBLEConnInfo peerInfo = pServer->getPeerInfo(i);
|
||||
printf("Client address: %s Name: %s\n", peerInfo.getAddress().toString().c_str(),
|
||||
// This function blocks until the name is retrieved, so cannot be used in callback functions.
|
||||
pServer->getPeerName(peerInfo).c_str());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(10000));
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
|
@ -1,7 +0,0 @@
|
|||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(SUPPORTED_TARGETS esp32)
|
||||
project(BLE_client)
|
|
@ -1,3 +0,0 @@
|
|||
PROJECT_NAME := BLE_client
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
|
@ -1,4 +0,0 @@
|
|||
set(COMPONENT_SRCS "main.cpp")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
|
@ -1,4 +0,0 @@
|
|||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
|
@ -1,214 +0,0 @@
|
|||
/**
|
||||
* A BLE client example that is rich in capabilities.
|
||||
* There is a lot new capabilities implemented.
|
||||
* author unknown
|
||||
* updated by chegewara
|
||||
* updated for NimBLE by H2zero
|
||||
*/
|
||||
|
||||
/** NimBLE differences highlighted in comment blocks **/
|
||||
|
||||
/*******original********
|
||||
#include "BLEDevice.h"
|
||||
***********************/
|
||||
#include "NimBLEDevice.h"
|
||||
|
||||
extern "C"{void app_main(void);}
|
||||
|
||||
// The remote service we wish to connect to.
|
||||
static BLEUUID serviceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
|
||||
// The characteristic of the remote service we are interested in.
|
||||
static BLEUUID charUUID("beb5483e-36e1-4688-b7f5-ea07361b26a8");
|
||||
|
||||
static bool doConnect = false;
|
||||
static bool connected = false;
|
||||
static bool doScan = false;
|
||||
static BLERemoteCharacteristic* pRemoteCharacteristic;
|
||||
static const BLEAdvertisedDevice* myDevice;
|
||||
|
||||
static void notifyCallback(
|
||||
BLERemoteCharacteristic* pBLERemoteCharacteristic,
|
||||
uint8_t* pData,
|
||||
size_t length,
|
||||
bool isNotify) {
|
||||
printf("Notify callback for characteristic %s of data length %d data: %s\n",
|
||||
pBLERemoteCharacteristic->getUUID().toString().c_str(),
|
||||
length,
|
||||
(char*)pData);
|
||||
}
|
||||
|
||||
/** None of these are required as they will be handled by the library with defaults. **
|
||||
** Remove as you see fit for your needs */
|
||||
class MyClientCallback : public BLEClientCallbacks {
|
||||
void onConnect(BLEClient* pclient) {
|
||||
}
|
||||
|
||||
/** onDisconnect now takes a reason parameter to indicate the reason for disconnection
|
||||
void onDisconnect(BLEClient* pclient) { */
|
||||
void onDisconnect(BLEClient* pclient, int reason) {
|
||||
connected = false;
|
||||
printf("onDisconnect");
|
||||
}
|
||||
/***************** New - Security handled here ********************
|
||||
****** Note: these are the same return values as defaults ********/
|
||||
void onPassKeyEntry(NimBLEConnInfo& connInfo){
|
||||
printf("Server Passkey Entry\n");
|
||||
/** This should prompt the user to enter the passkey displayed
|
||||
* on the peer device.
|
||||
*/
|
||||
NimBLEDevice::injectPassKey(connInfo, 123456);
|
||||
};
|
||||
|
||||
void onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t pass_key){
|
||||
printf("The passkey YES/NO number: %" PRIu32 "\n", pass_key);
|
||||
/** Inject false if passkeys don't match. */
|
||||
NimBLEDevice::injectConfirmPasskey(connInfo, true);
|
||||
};
|
||||
|
||||
/** Pairing process complete, we can check the results in connInfo */
|
||||
void onAuthenticationComplete(NimBLEConnInfo& connInfo){
|
||||
if(!connInfo.isEncrypted()) {
|
||||
printf("Encrypt connection failed - disconnecting\n");
|
||||
/** Find the client with the connection handle provided in desc */
|
||||
NimBLEDevice::getClientByHandle(connInfo.getConnHandle())->disconnect();
|
||||
return;
|
||||
}
|
||||
}
|
||||
/*******************************************************************/
|
||||
};
|
||||
|
||||
bool connectToServer() {
|
||||
printf("Forming a connection to %s\n", myDevice->getAddress().toString().c_str());
|
||||
|
||||
BLEClient* pClient = BLEDevice::createClient();
|
||||
printf(" - Created client\n");
|
||||
|
||||
pClient->setClientCallbacks(new MyClientCallback());
|
||||
|
||||
// Connect to the remove BLE Server.
|
||||
pClient->connect(myDevice); // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
|
||||
printf(" - Connected to server\n");
|
||||
|
||||
// Obtain a reference to the service we are after in the remote BLE server.
|
||||
BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
|
||||
if (pRemoteService == nullptr) {
|
||||
printf("Failed to find our service UUID: %s\n", serviceUUID.toString().c_str());
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
printf(" - Found our service\n");
|
||||
|
||||
|
||||
// Obtain a reference to the characteristic in the service of the remote BLE server.
|
||||
pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
|
||||
if (pRemoteCharacteristic == nullptr) {
|
||||
printf("Failed to find our characteristic UUID: %s\n", charUUID.toString().c_str());
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
printf(" - Found our characteristic\n");
|
||||
|
||||
// Read the value of the characteristic.
|
||||
if(pRemoteCharacteristic->canRead()) {
|
||||
std::string value = pRemoteCharacteristic->readValue();
|
||||
printf("The characteristic value was: %s\n", value.c_str());
|
||||
}
|
||||
|
||||
/** registerForNotify() has been removed and replaced with subscribe() / unsubscribe().
|
||||
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=true.
|
||||
* Unsubscribe parameter defaults are: response=true.
|
||||
*/
|
||||
if(pRemoteCharacteristic->canNotify()) {
|
||||
//pRemoteCharacteristic->registerForNotify(notifyCallback);
|
||||
pRemoteCharacteristic->subscribe(true, notifyCallback);
|
||||
}
|
||||
|
||||
connected = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan for BLE servers and find the first one that advertises the service we are looking for.
|
||||
*/
|
||||
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
|
||||
/**
|
||||
* Called for each advertising BLE server.
|
||||
*/
|
||||
|
||||
/*** Only a reference to the advertised device is passed now
|
||||
void onResult(BLEAdvertisedDevice advertisedDevice) { **/
|
||||
void onResult(const BLEAdvertisedDevice* advertisedDevice) {
|
||||
printf("BLE Advertised Device found: %s\n", advertisedDevice->toString().c_str());
|
||||
|
||||
// We have found a device, let us now see if it contains the service we are looking for.
|
||||
/********************************************************************************
|
||||
if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) {
|
||||
********************************************************************************/
|
||||
if (advertisedDevice->haveServiceUUID() && advertisedDevice->isAdvertisingService(serviceUUID)) {
|
||||
|
||||
BLEDevice::getScan()->stop();
|
||||
/*******************************************************************
|
||||
myDevice = new BLEAdvertisedDevice(advertisedDevice);
|
||||
*******************************************************************/
|
||||
myDevice = advertisedDevice; /** Just save the reference now, no need to copy the object */
|
||||
doConnect = true;
|
||||
doScan = true;
|
||||
|
||||
} // Found our server
|
||||
} // onResult
|
||||
}; // MyAdvertisedDeviceCallbacks
|
||||
|
||||
|
||||
// This is the Arduino main loop function.
|
||||
void connectTask (void * parameter){
|
||||
for(;;) {
|
||||
// If the flag "doConnect" is true then we have scanned for and found the desired
|
||||
// BLE Server with which we wish to connect. Now we connect to it. Once we are
|
||||
// connected we set the connected flag to be true.
|
||||
if (doConnect == true) {
|
||||
if (connectToServer()) {
|
||||
printf("We are now connected to the BLE Server.\n");
|
||||
} else {
|
||||
printf("We have failed to connect to the server; there is nothin more we will do.\n");
|
||||
}
|
||||
doConnect = false;
|
||||
}
|
||||
|
||||
// If we are connected to a peer BLE Server, update the characteristic each time we are reached
|
||||
// with the current time since boot.
|
||||
if (connected) {
|
||||
char buf[256];
|
||||
snprintf(buf, 256, "Time since boot: %lu", (unsigned long)(esp_timer_get_time() / 1000000ULL));
|
||||
printf("Setting new characteristic value to %s\n", buf);
|
||||
|
||||
// Set the characteristic's value to be the array of bytes that is actually a string.
|
||||
/*** Note: write value now returns true if successful, false otherwise - try again or disconnect ***/
|
||||
pRemoteCharacteristic->writeValue((uint8_t*)buf, strlen(buf), false);
|
||||
}else if(doScan){
|
||||
BLEDevice::getScan()->start(0); // this is just eample to start scan after disconnect, most likely there is better way to do it
|
||||
}
|
||||
|
||||
vTaskDelay(1000/portTICK_PERIOD_MS); // Delay a second between loops.
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
} // End of loop
|
||||
|
||||
|
||||
void app_main(void) {
|
||||
printf("Starting BLE Client application...\n");
|
||||
BLEDevice::init("");
|
||||
|
||||
// Retrieve a Scanner and set the callback we want to use to be informed when we
|
||||
// have detected a new device. Specify that we want active scanning and start the
|
||||
// scan to run for 5 seconds.
|
||||
BLEScan* pBLEScan = BLEDevice::getScan();
|
||||
pBLEScan->setScanCallbacks(new MyAdvertisedDeviceCallbacks());
|
||||
pBLEScan->setInterval(1349);
|
||||
pBLEScan->setWindow(449);
|
||||
pBLEScan->setActiveScan(true);
|
||||
|
||||
xTaskCreate(connectTask, "connectTask", 5000, NULL, 1, NULL);
|
||||
pBLEScan->start(5 * 1000, false);
|
||||
} // End of setup.
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
|
@ -1,7 +0,0 @@
|
|||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(SUPPORTED_TARGETS esp32)
|
||||
project(BLE_notify)
|
|
@ -1,3 +0,0 @@
|
|||
PROJECT_NAME := BLE_notify
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
|
@ -1,4 +0,0 @@
|
|||
set(COMPONENT_SRCS "main.cpp")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
|
@ -1,4 +0,0 @@
|
|||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
|
@ -1,164 +0,0 @@
|
|||
/*
|
||||
Video: https://www.youtube.com/watch?v=oCMOYS71NIU
|
||||
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
|
||||
Ported to Arduino ESP32 by Evandro Copercini
|
||||
updated by chegewara
|
||||
Refactored back to IDF by H2zero
|
||||
|
||||
Create a BLE server that, once we receive a connection, will send periodic notifications.
|
||||
The service advertises itself as: 4fafc201-1fb5-459e-8fcc-c5c9c331914b
|
||||
And has a characteristic of: beb5483e-36e1-4688-b7f5-ea07361b26a8
|
||||
|
||||
The design of creating the BLE server is:
|
||||
1. Create a BLE Server
|
||||
2. Create a BLE Service
|
||||
3. Create a BLE Characteristic on the Service
|
||||
4. Create a BLE Descriptor on the characteristic
|
||||
5. Start the service.
|
||||
6. Start advertising.
|
||||
|
||||
A connect hander associated with the server starts a background task that performs notification
|
||||
every couple of seconds.
|
||||
*/
|
||||
|
||||
/** NimBLE differences highlighted in comment blocks **/
|
||||
|
||||
/*******original********
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEServer.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <BLE2902.h>
|
||||
***********************/
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
extern "C" {void app_main(void);}
|
||||
|
||||
BLEServer* pServer = NULL;
|
||||
BLECharacteristic* pCharacteristic = NULL;
|
||||
bool deviceConnected = false;
|
||||
bool oldDeviceConnected = false;
|
||||
uint32_t value = 0;
|
||||
|
||||
// See the following for generating UUIDs:
|
||||
// https://www.uuidgenerator.net/
|
||||
|
||||
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
|
||||
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
|
||||
|
||||
/** None of these are required as they will be handled by the library with defaults. **
|
||||
** Remove as you see fit for your needs */
|
||||
class MyServerCallbacks: public BLEServerCallbacks {
|
||||
void onConnect(BLEServer* pServer, BLEConnInfo& connInfo) {
|
||||
deviceConnected = true;
|
||||
};
|
||||
|
||||
void onDisconnect(BLEServer* pServer, BLEConnInfo& connInfo, int reason) {
|
||||
deviceConnected = false;
|
||||
}
|
||||
/***************** New - Security handled here ********************
|
||||
****** Note: these are the same return values as defaults ********/
|
||||
uint32_t onPassKeyDisplay(){
|
||||
printf("Server Passkey Display\n");
|
||||
/** This should return a random 6 digit number for security
|
||||
* or make your own static passkey as done here.
|
||||
*/
|
||||
return 123456;
|
||||
};
|
||||
|
||||
void onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t pass_key){
|
||||
printf("The passkey YES/NO number: %" PRIu32 "\n", pass_key);
|
||||
/** Inject false if passkeys don't match. */
|
||||
NimBLEDevice::injectConfirmPasskey(connInfo, true);
|
||||
};
|
||||
|
||||
void onAuthenticationComplete(NimBLEConnInfo& connInfo){
|
||||
/** Check that encryption was successful, if not we disconnect the client */
|
||||
if(!connInfo.isEncrypted()) {
|
||||
NimBLEDevice::getServer()->disconnect(connInfo.getConnHandle());
|
||||
printf("Encrypt connection failed - disconnecting client\n");
|
||||
return;
|
||||
}
|
||||
printf("Starting BLE work!");
|
||||
};
|
||||
/*******************************************************************/
|
||||
};
|
||||
|
||||
void connectedTask (void * parameter){
|
||||
for(;;) {
|
||||
// notify changed value
|
||||
if (deviceConnected) {
|
||||
pCharacteristic->setValue((uint8_t*)&value, 4);
|
||||
pCharacteristic->notify();
|
||||
value++;
|
||||
vTaskDelay(100/portTICK_PERIOD_MS); // bluetooth stack will go into congestion, if too many packets are sent
|
||||
}
|
||||
// disconnecting
|
||||
if (!deviceConnected && oldDeviceConnected) {
|
||||
vTaskDelay(500/portTICK_PERIOD_MS); // give the bluetooth stack the chance to get things ready
|
||||
pServer->startAdvertising(); // restart advertising
|
||||
printf("start advertising\n");
|
||||
oldDeviceConnected = deviceConnected;
|
||||
}
|
||||
// connecting
|
||||
if (deviceConnected && !oldDeviceConnected) {
|
||||
// do stuff here on connecting
|
||||
oldDeviceConnected = deviceConnected;
|
||||
}
|
||||
|
||||
vTaskDelay(10/portTICK_PERIOD_MS); // Delay between loops to reset watchdog timer
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void app_main(void) {
|
||||
// Create the BLE Device
|
||||
BLEDevice::init("ESP32");
|
||||
|
||||
// Create the BLE Server
|
||||
pServer = BLEDevice::createServer();
|
||||
pServer->setCallbacks(new MyServerCallbacks());
|
||||
|
||||
// Create the BLE Service
|
||||
BLEService *pService = pServer->createService(SERVICE_UUID);
|
||||
|
||||
// Create a BLE Characteristic
|
||||
pCharacteristic = pService->createCharacteristic(
|
||||
CHARACTERISTIC_UUID,
|
||||
/******* Enum Type NIMBLE_PROPERTY now *******
|
||||
BLECharacteristic::PROPERTY_READ |
|
||||
BLECharacteristic::PROPERTY_WRITE |
|
||||
BLECharacteristic::PROPERTY_NOTIFY |
|
||||
BLECharacteristic::PROPERTY_INDICATE
|
||||
);
|
||||
**********************************************/
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE |
|
||||
NIMBLE_PROPERTY::NOTIFY |
|
||||
NIMBLE_PROPERTY::INDICATE
|
||||
);
|
||||
|
||||
// Create a BLE Descriptor
|
||||
/***************************************************
|
||||
NOTE: DO NOT create a 2902 descriptor.
|
||||
it will be created automatically if notifications
|
||||
or indications are enabled on a characteristic.
|
||||
|
||||
pCharacteristic->addDescriptor(new BLE2902());
|
||||
****************************************************/
|
||||
// Start the service
|
||||
pService->start();
|
||||
|
||||
// Start advertising
|
||||
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
|
||||
pAdvertising->addServiceUUID(SERVICE_UUID);
|
||||
pAdvertising->enableScanResponse(false);
|
||||
/** This method had been removed **
|
||||
pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter
|
||||
**/
|
||||
|
||||
xTaskCreate(connectedTask, "connectedTask", 5000, NULL, 1, NULL);
|
||||
|
||||
BLEDevice::startAdvertising();
|
||||
printf("Waiting a client connection to notify...\n");
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
|
@ -1,7 +0,0 @@
|
|||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(SUPPORTED_TARGETS esp32)
|
||||
project(BLE_scan)
|
|
@ -1,3 +0,0 @@
|
|||
PROJECT_NAME := BLE_scan
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
|
@ -1,4 +0,0 @@
|
|||
set(COMPONENT_SRCS "main.cpp")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
|
@ -1,4 +0,0 @@
|
|||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
|
||||
Ported to Arduino ESP32 by Evandro Copercini
|
||||
Refactored back to IDF by H2zero
|
||||
*/
|
||||
|
||||
/** NimBLE differences highlighted in comment blocks **/
|
||||
|
||||
/*******original********
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <BLEScan.h>
|
||||
#include <BLEAdvertisedDevice.h>
|
||||
***********************/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
extern "C"{void app_main(void);}
|
||||
|
||||
int scanTime = 5 * 1000; // In milliseconds, 0 = scan forever
|
||||
BLEScan* pBLEScan;
|
||||
|
||||
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
|
||||
void onResult(const BLEAdvertisedDevice* advertisedDevice) {
|
||||
printf("Advertised Device: %s \n", advertisedDevice->toString().c_str());
|
||||
}
|
||||
};
|
||||
|
||||
void scanTask (void * parameter){
|
||||
for(;;) {
|
||||
// put your main code here, to run repeatedly:
|
||||
BLEScanResults foundDevices = pBLEScan->getResults(scanTime, false);
|
||||
printf("Devices found: %d\n", foundDevices.getCount());
|
||||
printf("Scan done!\n");
|
||||
pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
|
||||
vTaskDelay(2000/portTICK_PERIOD_MS); // Delay a second between loops.
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void app_main(void) {
|
||||
printf("Scanning...\n");
|
||||
|
||||
BLEDevice::init("");
|
||||
pBLEScan = BLEDevice::getScan(); //create new scan
|
||||
pBLEScan->setScanCallbacks(new MyAdvertisedDeviceCallbacks());
|
||||
pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
|
||||
pBLEScan->setInterval(100);
|
||||
pBLEScan->setWindow(99); // less or equal setInterval value
|
||||
xTaskCreate(scanTask, "scanTask", 5000, NULL, 1, NULL);
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
|
@ -1,7 +0,0 @@
|
|||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(SUPPORTED_TARGETS esp32)
|
||||
project(BLE_server)
|
|
@ -1,3 +0,0 @@
|
|||
PROJECT_NAME := BLE_server
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
|
@ -1,4 +0,0 @@
|
|||
set(COMPONENT_SRCS "main.cpp")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
|
@ -1,4 +0,0 @@
|
|||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp
|
||||
Ported to Arduino ESP32 by Evandro Copercini
|
||||
updates by chegewara
|
||||
Refactored back to IDF by H2zero
|
||||
*/
|
||||
|
||||
/** NimBLE differences highlighted in comment blocks **/
|
||||
|
||||
/*******original********
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <BLEServer.h>
|
||||
***********************/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
extern "C"{void app_main(void);}
|
||||
|
||||
// See the following for generating UUIDs:
|
||||
// https://www.uuidgenerator.net/
|
||||
|
||||
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
|
||||
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
|
||||
|
||||
void app_main(void) {
|
||||
printf("Starting BLE work!\n");
|
||||
|
||||
BLEDevice::init("Long name works now");
|
||||
BLEServer *pServer = BLEDevice::createServer();
|
||||
BLEService *pService = pServer->createService(SERVICE_UUID);
|
||||
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
|
||||
CHARACTERISTIC_UUID,
|
||||
/***** Enum Type NIMBLE_PROPERTY now *****
|
||||
BLECharacteristic::PROPERTY_READ |
|
||||
BLECharacteristic::PROPERTY_WRITE
|
||||
);
|
||||
*****************************************/
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE
|
||||
);
|
||||
|
||||
pCharacteristic->setValue("Hello World says Neil");
|
||||
pService->start();
|
||||
// BLEAdvertising *pAdvertising = pServer->getAdvertising(); // this still is working for backward compatibility
|
||||
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
|
||||
pAdvertising->addServiceUUID(SERVICE_UUID);
|
||||
pAdvertising->enableScanResponse(true);
|
||||
|
||||
/** These methods have been removed **
|
||||
pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
|
||||
pAdvertising->setMinPreferred(0x12);
|
||||
*/
|
||||
|
||||
BLEDevice::startAdvertising();
|
||||
printf("Characteristic defined! Now you can read it in your phone!\n");
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
|
@ -1,7 +0,0 @@
|
|||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(SUPPORTED_TARGETS esp32)
|
||||
project(BLE_uart)
|
|
@ -1,3 +0,0 @@
|
|||
PROJECT_NAME := BLE_uart
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
|
@ -1,4 +0,0 @@
|
|||
set(COMPONENT_SRCS "main.cpp")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
|
@ -1,4 +0,0 @@
|
|||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
|
@ -1,177 +0,0 @@
|
|||
/*
|
||||
Video: https://www.youtube.com/watch?v=oCMOYS71NIU
|
||||
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
|
||||
Ported to Arduino ESP32 by Evandro Copercini
|
||||
Refactored back to IDF by H2zero
|
||||
|
||||
Create a BLE server that, once we receive a connection, will send periodic notifications.
|
||||
The service advertises itself as: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E
|
||||
Has a characteristic of: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E - used for receiving data with "WRITE"
|
||||
Has a characteristic of: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E - used to send data with "NOTIFY"
|
||||
|
||||
The design of creating the BLE server is:
|
||||
1. Create a BLE Server
|
||||
2. Create a BLE Service
|
||||
3. Create a BLE Characteristic on the Service
|
||||
4. Create a BLE Descriptor on the characteristic
|
||||
5. Start the service.
|
||||
6. Start advertising.
|
||||
|
||||
In this example rxValue is the data received (only accessible inside that function).
|
||||
And txValue is the data to be sent, in this example just a byte incremented every second.
|
||||
*/
|
||||
|
||||
/** NimBLE differences highlighted in comment blocks **/
|
||||
|
||||
/*******original********
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEServer.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <BLE2902.h>
|
||||
***********************/
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
extern "C"{void app_main(void);}
|
||||
|
||||
BLEServer *pServer = NULL;
|
||||
BLECharacteristic * pTxCharacteristic;
|
||||
bool deviceConnected = false;
|
||||
bool oldDeviceConnected = false;
|
||||
uint8_t txValue = 0;
|
||||
|
||||
// See the following for generating UUIDs:
|
||||
// https://www.uuidgenerator.net/
|
||||
|
||||
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
|
||||
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||
|
||||
|
||||
/** None of these are required as they will be handled by the library with defaults. **
|
||||
** Remove as you see fit for your needs */
|
||||
class MyServerCallbacks: public BLEServerCallbacks {
|
||||
void onConnect(BLEServer* pServer, BLEConnInfo& connInfo) {
|
||||
deviceConnected = true;
|
||||
};
|
||||
|
||||
void onDisconnect(BLEServer* pServer, BLEConnInfo& connInfo, int reason) {
|
||||
deviceConnected = false;
|
||||
}
|
||||
/***************** New - Security handled here ********************
|
||||
****** Note: these are the same return values as defaults ********/
|
||||
uint32_t onPassKeyDisplay(){
|
||||
printf("Server Passkey Display\n");
|
||||
/** This should return a random 6 digit number for security
|
||||
* or make your own static passkey as done here.
|
||||
*/
|
||||
return 123456;
|
||||
};
|
||||
|
||||
void onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t pass_key){
|
||||
printf("The passkey YES/NO number: %" PRIu32 "\n", pass_key);
|
||||
/** Inject false if passkeys don't match. */
|
||||
NimBLEDevice::injectConfirmPasskey(connInfo, true);
|
||||
};
|
||||
|
||||
void onAuthenticationComplete(NimBLEConnInfo& connInfo){
|
||||
/** Check that encryption was successful, if not we disconnect the client */
|
||||
if(!connInfo.isEncrypted()) {
|
||||
NimBLEDevice::getServer()->disconnect(connInfo.getConnHandle());
|
||||
printf("Encrypt connection failed - disconnecting client\n");
|
||||
return;
|
||||
}
|
||||
printf("Starting BLE work!");
|
||||
};
|
||||
/*******************************************************************/
|
||||
};
|
||||
|
||||
class MyCallbacks: public BLECharacteristicCallbacks {
|
||||
void onWrite(BLECharacteristic *pCharacteristic, BLEConnInfo& connInfo) {
|
||||
std::string rxValue = pCharacteristic->getValue();
|
||||
|
||||
if (rxValue.length() > 0) {
|
||||
printf("*********\n");
|
||||
printf("Received Value: ");
|
||||
for (int i = 0; i < rxValue.length(); i++)
|
||||
printf("%d", rxValue[i]);
|
||||
|
||||
printf("\n*********\n");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void connectedTask (void * parameter){
|
||||
for(;;) {
|
||||
if (deviceConnected) {
|
||||
pTxCharacteristic->setValue(&txValue, 1);
|
||||
pTxCharacteristic->notify();
|
||||
txValue++;
|
||||
}
|
||||
|
||||
// disconnecting
|
||||
if (!deviceConnected && oldDeviceConnected) {
|
||||
pServer->startAdvertising(); // restart advertising
|
||||
printf("start advertising\n");
|
||||
oldDeviceConnected = deviceConnected;
|
||||
}
|
||||
// connecting
|
||||
if (deviceConnected && !oldDeviceConnected) {
|
||||
// do stuff here on connecting
|
||||
oldDeviceConnected = deviceConnected;
|
||||
}
|
||||
|
||||
vTaskDelay(10/portTICK_PERIOD_MS); // Delay between loops to reset watchdog timer
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void app_main(void) {
|
||||
// Create the BLE Device
|
||||
BLEDevice::init("UART Service");
|
||||
|
||||
// Create the BLE Server
|
||||
pServer = BLEDevice::createServer();
|
||||
pServer->setCallbacks(new MyServerCallbacks());
|
||||
|
||||
// Create the BLE Service
|
||||
BLEService *pService = pServer->createService(SERVICE_UUID);
|
||||
|
||||
// Create a BLE Characteristic
|
||||
pTxCharacteristic = pService->createCharacteristic(
|
||||
CHARACTERISTIC_UUID_TX,
|
||||
/******* Enum Type NIMBLE_PROPERTY now *******
|
||||
BLECharacteristic::PROPERTY_NOTIFY
|
||||
);
|
||||
**********************************************/
|
||||
NIMBLE_PROPERTY::NOTIFY
|
||||
);
|
||||
|
||||
/***************************************************
|
||||
NOTE: DO NOT create a 2902 descriptor
|
||||
it will be created automatically if notifications
|
||||
or indications are enabled on a characteristic.
|
||||
|
||||
pCharacteristic->addDescriptor(new BLE2902());
|
||||
****************************************************/
|
||||
|
||||
BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
|
||||
CHARACTERISTIC_UUID_RX,
|
||||
/******* Enum Type NIMBLE_PROPERTY now *******
|
||||
BLECharacteristic::PROPERTY_WRITE
|
||||
);
|
||||
*********************************************/
|
||||
NIMBLE_PROPERTY::WRITE
|
||||
);
|
||||
|
||||
pRxCharacteristic->setCallbacks(new MyCallbacks());
|
||||
|
||||
// Start the service
|
||||
pService->start();
|
||||
|
||||
xTaskCreate(connectedTask, "connectedTask", 5000, NULL, 1, NULL);
|
||||
|
||||
// Start advertising
|
||||
pServer->getAdvertising()->start();
|
||||
printf("Waiting a client connection to notify...\n");
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
Loading…
Reference in a new issue