mirror of
https://github.com/h2zero/esp-nimble-cpp.git
synced 2024-11-22 05:00:55 +01:00
Add examples
This commit is contained in:
parent
f672d04a90
commit
34c6417b48
35 changed files with 1355 additions and 0 deletions
7
examples/Advanced/NimBLE_Client/CMakeLists.txt
Normal file
7
examples/Advanced/NimBLE_Client/CMakeLists.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# 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_Client)
|
3
examples/Advanced/NimBLE_Client/Makefile
Normal file
3
examples/Advanced/NimBLE_Client/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
PROJECT_NAME := NimBLE_Client
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
4
examples/Advanced/NimBLE_Client/main/CMakeLists.txt
Normal file
4
examples/Advanced/NimBLE_Client/main/CMakeLists.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
set(COMPONENT_SRCS "main.cpp")
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||||
|
|
||||||
|
register_component()
|
4
examples/Advanced/NimBLE_Client/main/component.mk
Normal file
4
examples/Advanced/NimBLE_Client/main/component.mk
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
372
examples/Advanced/NimBLE_Client/main/main.cpp
Normal file
372
examples/Advanced/NimBLE_Client/main/main.cpp
Normal file
|
@ -0,0 +1,372 @@
|
||||||
|
|
||||||
|
/** NimBLE_Server 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);}
|
||||||
|
|
||||||
|
void scanEndedCB(NimBLEScanResults results);
|
||||||
|
|
||||||
|
static NimBLEAdvertisedDevice* advDevice;
|
||||||
|
|
||||||
|
static bool doConnect = false;
|
||||||
|
static uint32_t scanTime = 0; /** 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) {
|
||||||
|
printf("%s Disconnected - Starting scan\n", pClient->getPeerAddress().toString().c_str());
|
||||||
|
NimBLEDevice::getScan()->start(scanTime, scanEndedCB);
|
||||||
|
};
|
||||||
|
|
||||||
|
/********************* Security handled here **********************
|
||||||
|
****** Note: these are the same return values as defaults ********/
|
||||||
|
uint32_t onPassKeyRequest(){
|
||||||
|
printf("Client Passkey Request\n");
|
||||||
|
/** return the passkey to send to the server */
|
||||||
|
return 123456;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool onConfirmPIN(uint32_t pass_key){
|
||||||
|
printf("The passkey YES/NO number: %d\n", pass_key);
|
||||||
|
/** Return false if passkeys don't match. */
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Pairing process complete, we can check the results in ble_gap_conn_desc */
|
||||||
|
void onAuthenticationComplete(ble_gap_conn_desc* desc){
|
||||||
|
if(!desc->sec_state.encrypted) {
|
||||||
|
printf("Encrypt connection failed - disconnecting\n");
|
||||||
|
/** Find the client with the connection handle provided in desc */
|
||||||
|
NimBLEDevice::getClientByID(desc->conn_handle)->disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** Define a class to handle the callbacks when advertisments are received */
|
||||||
|
class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks {
|
||||||
|
|
||||||
|
void onResult(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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** 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->getRemoteService()->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());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Callback to process the results of the last scan or restart it */
|
||||||
|
void scanEndedCB(NimBLEScanResults results){
|
||||||
|
printf("Scan Ended\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** 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::getClientListSize()) {
|
||||||
|
/** 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::getClientListSize() >= 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 (seconds), default is 30. */
|
||||||
|
pClient->setConnectTimeout(5);
|
||||||
|
|
||||||
|
|
||||||
|
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 deprecated and replaced with subscribe() / unsubscribe().
|
||||||
|
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
|
||||||
|
* Unsubscribe parameter defaults are: response=false.
|
||||||
|
*/
|
||||||
|
if(pChr->canNotify()) {
|
||||||
|
//if(!pChr->registerForNotify(notifyCB)) {
|
||||||
|
if(!pChr->subscribe(true, notifyCB)) {
|
||||||
|
/** Disconnect if subscribe failed */
|
||||||
|
pClient->disconnect();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(pChr->canIndicate()) {
|
||||||
|
/** Send false as first argument to subscribe to indications instead of notifications */
|
||||||
|
//if(!pChr->registerForNotify(notifyCB, false)) {
|
||||||
|
if(!pChr->subscribe(false, notifyCB)) {
|
||||||
|
/** Disconnect if subscribe failed */
|
||||||
|
pClient->disconnect();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else{
|
||||||
|
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=false.
|
||||||
|
* Unsubscribe parameter defaults are: response=false.
|
||||||
|
*/
|
||||||
|
if(pChr->canNotify()) {
|
||||||
|
//if(!pChr->registerForNotify(notifyCB)) {
|
||||||
|
if(!pChr->subscribe(true, notifyCB)) {
|
||||||
|
/** Disconnect if subscribe failed */
|
||||||
|
pClient->disconnect();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(pChr->canIndicate()) {
|
||||||
|
/** Send false as first argument to subscribe to indications instead of notifications */
|
||||||
|
//if(!pChr->registerForNotify(notifyCB, false)) {
|
||||||
|
if(!pChr->subscribe(false, notifyCB)) {
|
||||||
|
/** Disconnect if subscribe failed */
|
||||||
|
pClient->disconnect();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else{
|
||||||
|
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,scanEndedCB);
|
||||||
|
}
|
||||||
|
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(ESP_PWR_LVL_P9); /** 12db */
|
||||||
|
|
||||||
|
/** Optional: set any devices you don't want to get advertisments from */
|
||||||
|
// NimBLEDevice::addIgnored(NimBLEAddress ("aa:bb:cc:dd:ee:ff"));
|
||||||
|
|
||||||
|
/** create new scan */
|
||||||
|
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||||
|
|
||||||
|
/** create a callback that gets called when advertisers are found */
|
||||||
|
pScan->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallbacks());
|
||||||
|
|
||||||
|
/** 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 seconds) 0 = forever
|
||||||
|
* Optional callback for when scanning stops.
|
||||||
|
*/
|
||||||
|
pScan->start(scanTime, scanEndedCB);
|
||||||
|
|
||||||
|
printf("Scanning for peripherals\n");
|
||||||
|
|
||||||
|
xTaskCreate(connectTask, "connectTask", 5000, NULL, 1, NULL);
|
||||||
|
}
|
||||||
|
|
7
examples/Advanced/NimBLE_Server/CMakeLists.txt
Normal file
7
examples/Advanced/NimBLE_Server/CMakeLists.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# 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)
|
3
examples/Advanced/NimBLE_Server/Makefile
Normal file
3
examples/Advanced/NimBLE_Server/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
PROJECT_NAME := NimBLE_Server
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
4
examples/Advanced/NimBLE_Server/main/CMakeLists.txt
Normal file
4
examples/Advanced/NimBLE_Server/main/CMakeLists.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
set(COMPONENT_SRCS "main.cpp")
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||||
|
|
||||||
|
register_component()
|
4
examples/Advanced/NimBLE_Server/main/component.mk
Normal file
4
examples/Advanced/NimBLE_Server/main/component.mk
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
226
examples/Advanced/NimBLE_Server/main/main.cpp
Normal file
226
examples/Advanced/NimBLE_Server/main/main.cpp
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
|
||||||
|
/** 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);}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
printf("Client connected\n");
|
||||||
|
NimBLEDevice::startAdvertising();
|
||||||
|
};
|
||||||
|
/** Alternative onConnect() method to extract details of the connection.
|
||||||
|
* See: src/ble_gap.h for the details of the ble_gap_conn_desc struct.
|
||||||
|
*/
|
||||||
|
void onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) {
|
||||||
|
printf("Client address: %s\n", NimBLEAddress(desc->peer_ota_addr).toString().c_str());
|
||||||
|
/** 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.
|
||||||
|
*/
|
||||||
|
pServer->updateConnParams(desc->conn_handle, 24, 48, 0, 18);
|
||||||
|
};
|
||||||
|
void onDisconnect(NimBLEServer* pServer) {
|
||||||
|
printf("Client disconnected - start advertising\n");
|
||||||
|
NimBLEDevice::startAdvertising();
|
||||||
|
};
|
||||||
|
|
||||||
|
/********************* Security handled here **********************
|
||||||
|
****** Note: these are the same return values as defaults ********/
|
||||||
|
uint32_t onPassKeyRequest(){
|
||||||
|
printf("Server Passkey Request\n");
|
||||||
|
/** This should return a random 6 digit number for security
|
||||||
|
* or make your own static passkey as done here.
|
||||||
|
*/
|
||||||
|
return 123456;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool onConfirmPIN(uint32_t pass_key){
|
||||||
|
printf("The passkey YES/NO number: %d\n", pass_key);
|
||||||
|
/** Return false if passkeys don't match. */
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
void onAuthenticationComplete(ble_gap_conn_desc* desc){
|
||||||
|
/** Check that encryption was successful, if not we disconnect the client */
|
||||||
|
if(!desc->sec_state.encrypted) {
|
||||||
|
/** NOTE: createServer returns the current server reference unless one is not already created */
|
||||||
|
NimBLEDevice::createServer()->disconnect(desc->conn_handle);
|
||||||
|
printf("Encrypt connection failed - disconnecting client\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("Starting BLE work!");
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Handler class for characteristic actions */
|
||||||
|
class CharacteristicCallbacks: public NimBLECharacteristicCallbacks {
|
||||||
|
void onRead(NimBLECharacteristic* pCharacteristic){
|
||||||
|
printf("%s : onRead(), value: %s\n",
|
||||||
|
pCharacteristic->getUUID().toString().c_str(),
|
||||||
|
pCharacteristic->getValue().c_str());
|
||||||
|
};
|
||||||
|
|
||||||
|
void onWrite(NimBLECharacteristic* pCharacteristic) {
|
||||||
|
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 status returned in status is defined in NimBLECharacteristic.h.
|
||||||
|
* The value returned in code is the NimBLE host return code.
|
||||||
|
*/
|
||||||
|
void onStatus(NimBLECharacteristic* pCharacteristic, Status status, int code) {
|
||||||
|
printf("Notification/Indication status code: %d , return code: %d, %s\n",
|
||||||
|
status,
|
||||||
|
code,
|
||||||
|
NimBLEUtils::returnCodeToString(code));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Handler class for descriptor actions */
|
||||||
|
class DescriptorCallbacks : public NimBLEDescriptorCallbacks {
|
||||||
|
void onWrite(NimBLEDescriptor* pDescriptor) {
|
||||||
|
std::string dscVal((char*)pDescriptor->getValue(), pDescriptor->getLength());
|
||||||
|
printf("Descriptor witten value: %s\n", dscVal.c_str());
|
||||||
|
};
|
||||||
|
|
||||||
|
void onRead(NimBLEDescriptor* pDescriptor) {
|
||||||
|
printf("%s Descriptor read\n", pDescriptor->getUUID().toString().c_str());
|
||||||
|
};;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** Define callback instances globally to use for multiple Charateristics \ Descriptors */
|
||||||
|
static DescriptorCallbacks dscCallbacks;
|
||||||
|
static CharacteristicCallbacks chrCallbacks;
|
||||||
|
|
||||||
|
void notifyTask(void * parameter){
|
||||||
|
for(;;) {
|
||||||
|
if(pServer->getConnectedCount()) {
|
||||||
|
NimBLEService* pSvc = pServer->getServiceByUUID("BAAD");
|
||||||
|
if(pSvc) {
|
||||||
|
NimBLECharacteristic* pChr = pSvc->getCharacteristic("F00D");
|
||||||
|
if(pChr) {
|
||||||
|
pChr->notify(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 = (NimBLE2904*)pBeefCharacteristic->createDescriptor("2904");
|
||||||
|
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->setScanResponse(true);
|
||||||
|
pAdvertising->start();
|
||||||
|
|
||||||
|
printf("Advertising Started\n");
|
||||||
|
|
||||||
|
xTaskCreate(notifyTask, "notifyTask", 5000, NULL, 1, NULL);
|
||||||
|
}
|
7
examples/basic/BLE_client/CMakeLists.txt
Normal file
7
examples/basic/BLE_client/CMakeLists.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# 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)
|
3
examples/basic/BLE_client/Makefile
Normal file
3
examples/basic/BLE_client/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
PROJECT_NAME := BLE_client
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
4
examples/basic/BLE_client/main/CMakeLists.txt
Normal file
4
examples/basic/BLE_client/main/CMakeLists.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
set(COMPONENT_SRCS "main.cpp")
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||||
|
|
||||||
|
register_component()
|
4
examples/basic/BLE_client/main/component.mk
Normal file
4
examples/basic/BLE_client/main/component.mk
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
200
examples/basic/BLE_client/main/main.cpp
Normal file
200
examples/basic/BLE_client/main/main.cpp
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
/**
|
||||||
|
* 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 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) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDisconnect(BLEClient* pclient) {
|
||||||
|
connected = false;
|
||||||
|
printf("onDisconnect");
|
||||||
|
}
|
||||||
|
/***************** New - Security handled here ********************
|
||||||
|
****** Note: these are the same return values as defaults ********/
|
||||||
|
uint32_t onPassKeyRequest(){
|
||||||
|
printf("Client PassKeyRequest\n");
|
||||||
|
return 123456;
|
||||||
|
}
|
||||||
|
bool onConfirmPIN(uint32_t pass_key){
|
||||||
|
printf("The passkey YES/NO number: %d\n", pass_key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onAuthenticationComplete(ble_gap_conn_desc desc){
|
||||||
|
printf("Starting BLE work!\n");
|
||||||
|
}
|
||||||
|
/*******************************************************************/
|
||||||
|
};
|
||||||
|
|
||||||
|
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 deprecated and replaced with subscribe() / unsubscribe().
|
||||||
|
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
|
||||||
|
* Unsubscribe parameter defaults are: response=false.
|
||||||
|
*/
|
||||||
|
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(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 in arduino
|
||||||
|
}
|
||||||
|
|
||||||
|
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->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
|
||||||
|
pBLEScan->setInterval(1349);
|
||||||
|
pBLEScan->setWindow(449);
|
||||||
|
pBLEScan->setActiveScan(true);
|
||||||
|
|
||||||
|
xTaskCreate(connectTask, "connectTask", 5000, NULL, 1, NULL);
|
||||||
|
pBLEScan->start(5, false);
|
||||||
|
} // End of setup.
|
||||||
|
|
7
examples/basic/BLE_notify/CMakeLists.txt
Normal file
7
examples/basic/BLE_notify/CMakeLists.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# 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)
|
3
examples/basic/BLE_notify/Makefile
Normal file
3
examples/basic/BLE_notify/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
PROJECT_NAME := BLE_notify
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
4
examples/basic/BLE_notify/main/CMakeLists.txt
Normal file
4
examples/basic/BLE_notify/main/CMakeLists.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
set(COMPONENT_SRCS "main.cpp")
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||||
|
|
||||||
|
register_component()
|
4
examples/basic/BLE_notify/main/component.mk
Normal file
4
examples/basic/BLE_notify/main/component.mk
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
155
examples/basic/BLE_notify/main/main.cpp
Normal file
155
examples/basic/BLE_notify/main/main.cpp
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
/*
|
||||||
|
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) {
|
||||||
|
deviceConnected = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
void onDisconnect(BLEServer* pServer) {
|
||||||
|
deviceConnected = false;
|
||||||
|
}
|
||||||
|
/***************** New - Security handled here ********************
|
||||||
|
****** Note: these are the same return values as defaults ********/
|
||||||
|
uint32_t onPassKeyRequest(){
|
||||||
|
printf("Server PassKeyRequest\n");
|
||||||
|
return 123456;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool onConfirmPIN(uint32_t pass_key){
|
||||||
|
printf("The passkey YES/NO number: %d\n", pass_key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onAuthenticationComplete(ble_gap_conn_desc desc){
|
||||||
|
printf("Starting BLE work!\n");
|
||||||
|
}
|
||||||
|
/*******************************************************************/
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
// https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
|
||||||
|
// 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->setScanResponse(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");
|
||||||
|
}
|
7
examples/basic/BLE_scan/CMakeLists.txt
Normal file
7
examples/basic/BLE_scan/CMakeLists.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# 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)
|
3
examples/basic/BLE_scan/Makefile
Normal file
3
examples/basic/BLE_scan/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
PROJECT_NAME := BLE_scan
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
4
examples/basic/BLE_scan/main/CMakeLists.txt
Normal file
4
examples/basic/BLE_scan/main/CMakeLists.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
set(COMPONENT_SRCS "main.cpp")
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||||
|
|
||||||
|
register_component()
|
4
examples/basic/BLE_scan/main/component.mk
Normal file
4
examples/basic/BLE_scan/main/component.mk
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
52
examples/basic/BLE_scan/main/main.cpp
Normal file
52
examples/basic/BLE_scan/main/main.cpp
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
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; //In seconds
|
||||||
|
BLEScan* pBLEScan;
|
||||||
|
|
||||||
|
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
|
||||||
|
void onResult(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->start(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->setAdvertisedDeviceCallbacks(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);
|
||||||
|
}
|
7
examples/basic/BLE_server/CMakeLists.txt
Normal file
7
examples/basic/BLE_server/CMakeLists.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# 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)
|
3
examples/basic/BLE_server/Makefile
Normal file
3
examples/basic/BLE_server/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
PROJECT_NAME := BLE_server
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
4
examples/basic/BLE_server/main/CMakeLists.txt
Normal file
4
examples/basic/BLE_server/main/CMakeLists.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
set(COMPONENT_SRCS "main.cpp")
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||||
|
|
||||||
|
register_component()
|
4
examples/basic/BLE_server/main/component.mk
Normal file
4
examples/basic/BLE_server/main/component.mk
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
57
examples/basic/BLE_server/main/main.cpp
Normal file
57
examples/basic/BLE_server/main/main.cpp
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
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->setScanResponse(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");
|
||||||
|
}
|
7
examples/basic/BLE_uart/CMakeLists.txt
Normal file
7
examples/basic/BLE_uart/CMakeLists.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# 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)
|
3
examples/basic/BLE_uart/Makefile
Normal file
3
examples/basic/BLE_uart/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
PROJECT_NAME := BLE_uart
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
4
examples/basic/BLE_uart/main/CMakeLists.txt
Normal file
4
examples/basic/BLE_uart/main/CMakeLists.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
set(COMPONENT_SRCS "main.cpp")
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||||
|
|
||||||
|
register_component()
|
4
examples/basic/BLE_uart/main/component.mk
Normal file
4
examples/basic/BLE_uart/main/component.mk
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
167
examples/basic/BLE_uart/main/main.cpp
Normal file
167
examples/basic/BLE_uart/main/main.cpp
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
/*
|
||||||
|
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) {
|
||||||
|
deviceConnected = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
void onDisconnect(BLEServer* pServer) {
|
||||||
|
deviceConnected = false;
|
||||||
|
}
|
||||||
|
/***************** New - Security handled here ********************
|
||||||
|
****** Note: these are the same return values as defaults ********/
|
||||||
|
uint32_t onPassKeyRequest(){
|
||||||
|
printf("Server PassKeyRequest\n");
|
||||||
|
return 123456;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool onConfirmPIN(uint32_t pass_key){
|
||||||
|
printf("The passkey YES/NO number: %d\n", pass_key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onAuthenticationComplete(ble_gap_conn_desc desc){
|
||||||
|
printf("Starting BLE work!\n");
|
||||||
|
}
|
||||||
|
/*******************************************************************/
|
||||||
|
};
|
||||||
|
|
||||||
|
class MyCallbacks: public BLECharacteristicCallbacks {
|
||||||
|
void onWrite(BLECharacteristic *pCharacteristic) {
|
||||||
|
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");
|
||||||
|
}
|
Loading…
Reference in a new issue