esp-nimble-cpp/examples/NimBLE_Server/main/main.cpp

219 lines
9.1 KiB
C++
Raw Permalink Normal View History

2020-08-22 17:56:19 +02:00
2024-12-09 20:58:14 +01:00
/**
* NimBLE_Server Demo:
2020-08-22 17:56:19 +02:00
*
* Demonstrates many of the available features of the NimBLE server library.
2023-05-24 23:47:14 +02:00
*
2020-08-22 17:56:19 +02:00
* Created: on March 22 2020
* Author: H2zero
2024-12-09 20:58:14 +01:00
*/
2020-08-22 17:56:19 +02:00
2024-12-09 20:58:14 +01:00
#include <NimBLEDevice.h>
2020-08-22 17:56:19 +02:00
static NimBLEServer* pServer;
/** None of these are required as they will be handled by the library with defaults. **
2023-05-24 23:47:14 +02:00
** Remove as you see fit for your needs */
2024-12-09 20:58:14 +01:00
class ServerCallbacks : public NimBLEServerCallbacks {
void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) override {
printf("Client address: %s\n", connInfo.getAddress().toString().c_str());
2023-05-24 23:47:14 +02:00
2024-12-09 20:58:14 +01:00
/**
* We can use the connection handle here to ask for different connection parameters.
2020-08-22 17:56:19 +02:00
* 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.
2024-12-09 20:58:14 +01:00
* Timeout: 10 millisecond increments.
2020-08-22 17:56:19 +02:00
*/
pServer->updateConnParams(connInfo.getConnHandle(), 24, 48, 0, 18);
2024-12-09 20:58:14 +01:00
}
2023-05-24 23:47:14 +02:00
2024-12-09 20:58:14 +01:00
void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) override {
2020-08-22 17:56:19 +02:00
printf("Client disconnected - start advertising\n");
NimBLEDevice::startAdvertising();
2024-12-09 20:58:14 +01:00
}
2024-12-09 20:58:14 +01:00
void onMTUChange(uint16_t MTU, NimBLEConnInfo& connInfo) override {
printf("MTU updated: %u for connection ID: %u\n", MTU, connInfo.getConnHandle());
2024-12-09 20:58:14 +01:00
}
2023-05-24 23:47:14 +02:00
2024-12-09 20:58:14 +01:00
/********************* Security handled here *********************/
uint32_t onPassKeyDisplay() override {
printf("Server Passkey Display\n");
2024-12-09 20:58:14 +01:00
/**
* This should return a random 6 digit number for security
2020-08-22 17:56:19 +02:00
* or make your own static passkey as done here.
*/
2023-05-24 23:47:14 +02:00
return 123456;
2024-12-09 20:58:14 +01:00
}
2020-08-22 17:56:19 +02:00
2024-12-09 20:58:14 +01:00
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);
2024-12-09 20:58:14 +01:00
}
2020-08-22 17:56:19 +02:00
2024-12-09 20:58:14 +01:00
void onAuthenticationComplete(NimBLEConnInfo& connInfo) override {
2023-05-24 23:47:14 +02:00
/** Check that encryption was successful, if not we disconnect the client */
2024-12-09 20:58:14 +01:00
if (!connInfo.isEncrypted()) {
NimBLEDevice::getServer()->disconnect(connInfo.getConnHandle());
2020-08-22 17:56:19 +02:00
printf("Encrypt connection failed - disconnecting client\n");
return;
}
2024-12-09 20:58:14 +01:00
printf("Secured connection to: %s\n", connInfo.getAddress().toString().c_str());
}
} serverCallbacks;
2020-08-22 17:56:19 +02:00
/** Handler class for characteristic actions */
2024-12-09 20:58:14 +01:00
class CharacteristicCallbacks : public NimBLECharacteristicCallbacks {
void onRead(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo) override {
2023-05-24 23:47:14 +02:00
printf("%s : onRead(), value: %s\n",
pCharacteristic->getUUID().toString().c_str(),
pCharacteristic->getValue().c_str());
}
2020-08-22 17:56:19 +02:00
2024-12-09 20:58:14 +01:00
void onWrite(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo) override {
2023-05-24 23:47:14 +02:00
printf("%s : onWrite(), value: %s\n",
pCharacteristic->getUUID().toString().c_str(),
pCharacteristic->getValue().c_str());
}
/**
2020-08-22 17:56:19 +02:00
* The value returned in code is the NimBLE host return code.
*/
2024-12-09 20:58:14 +01:00
void onStatus(NimBLECharacteristic* pCharacteristic, int code) override {
printf("Notification/Indication return code: %d, %s\n", code, NimBLEUtils::returnCodeToString(code));
}
2024-12-09 20:58:14 +01:00
/** 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: ";
str += connInfo.getAddress().toString();
if (subValue == 0) {
str += " Unsubscribed to ";
2024-12-09 20:58:14 +01:00
} else if (subValue == 1) {
str += " Subscribed to notifications for ";
} else if (subValue == 2) {
str += " Subscribed to indications for ";
2024-12-09 20:58:14 +01:00
} else if (subValue == 3) {
str += " Subscribed to notifications and indications for ";
}
str += std::string(pCharacteristic->getUUID());
printf("%s\n", str.c_str());
}
2024-12-09 20:58:14 +01:00
} chrCallbacks;
2023-05-24 23:47:14 +02:00
/** Handler class for descriptor actions */
2020-08-22 17:56:19 +02:00
class DescriptorCallbacks : public NimBLEDescriptorCallbacks {
2024-12-09 20:58:14 +01:00
void onWrite(NimBLEDescriptor* pDescriptor, NimBLEConnInfo& connInfo) override {
std::string dscVal = pDescriptor->getValue();
2024-12-09 20:58:14 +01:00
printf("Descriptor written value: %s\n", dscVal.c_str());
}
2020-08-22 17:56:19 +02:00
2024-12-09 20:58:14 +01:00
void onRead(NimBLEDescriptor* pDescriptor, NimBLEConnInfo& connInfo) override {
2020-08-22 17:56:19 +02:00
printf("%s Descriptor read\n", pDescriptor->getUUID().toString().c_str());
}
2024-12-09 20:58:14 +01:00
} dscCallbacks;
2023-05-24 23:47:14 +02:00
2024-12-09 20:58:14 +01:00
extern "C" void app_main(void) {
2020-08-22 17:56:19 +02:00
printf("Starting NimBLE Server\n");
2024-12-09 20:58:14 +01:00
/** Initialize NimBLE and set the device name */
2020-08-22 17:56:19 +02:00
NimBLEDevice::init("NimBLE");
2024-12-09 20:58:14 +01:00
/**
* Set the IO capabilities of the device, each option will trigger a different pairing method.
2020-08-22 17:56:19 +02:00
* 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
*/
2024-12-09 20:58:14 +01:00
// NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY); // use passkey
// NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO); //use numeric comparison
2020-08-22 17:56:19 +02:00
2024-12-09 20:58:14 +01:00
/**
* 2 different ways to set security - both calls achieve the same result.
* no bonding, no man in the middle protection, BLE secure connections.
2023-05-24 23:47:14 +02:00
*
* These are the default values, only shown here for demonstration.
*/
2024-12-09 20:58:14 +01:00
// NimBLEDevice::setSecurityAuth(false, false, true);
2020-08-22 17:56:19 +02:00
2024-12-09 20:58:14 +01:00
NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC);
2020-08-22 17:56:19 +02:00
pServer = NimBLEDevice::createServer();
2024-12-09 20:58:14 +01:00
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
);
2023-05-24 23:47:14 +02:00
2020-08-22 17:56:19 +02:00
pBeefCharacteristic->setValue("Burger");
pBeefCharacteristic->setCallbacks(&chrCallbacks);
2024-12-09 20:58:14 +01:00
/**
* 2902 and 2904 descriptors are a special case, when createDescriptor is called with
2020-08-22 17:56:19 +02:00
* 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();
2020-08-22 17:56:19 +02:00
pBeef2904->setFormat(NimBLE2904::FORMAT_UTF8);
pBeef2904->setCallbacks(&dscCallbacks);
2023-05-24 23:47:14 +02:00
2024-12-09 20:58:14 +01:00
NimBLEService* pBaadService = pServer->createService("BAAD");
NimBLECharacteristic* pFoodCharacteristic =
pBaadService->createCharacteristic("F00D", NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::NOTIFY);
2020-08-22 17:56:19 +02:00
pFoodCharacteristic->setValue("Fries");
pFoodCharacteristic->setCallbacks(&chrCallbacks);
2024-12-09 20:58:14 +01:00
/** 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);
2020-08-22 17:56:19 +02:00
pC01Ddsc->setValue("Send it back!");
pC01Ddsc->setCallbacks(&dscCallbacks);
2023-05-24 23:47:14 +02:00
/** Start the services when finished creating all Characteristics and Descriptors */
2020-08-22 17:56:19 +02:00
pDeadService->start();
pBaadService->start();
2024-12-09 20:58:14 +01:00
/** Create an advertising instance and add the services to the advertised data */
2020-08-22 17:56:19 +02:00
NimBLEAdvertising* pAdvertising = NimBLEDevice::getAdvertising();
2024-12-09 20:58:14 +01:00
pAdvertising->setName("NimBLE-Server");
2020-08-22 17:56:19 +02:00
pAdvertising->addServiceUUID(pDeadService->getUUID());
pAdvertising->addServiceUUID(pBaadService->getUUID());
2024-12-09 20:58:14 +01:00
/**
* If your device is battery powered you may consider setting scan response
2020-08-22 17:56:19 +02:00
* to false as it will extend battery life at the expense of less data sent.
*/
[BREAKING] - Refactor NimBLEAdvertising * General code cleanup. * `NimBLEAdvertisementData` moved to it's own .h and .cpp files. * Added new method, `NimBLEAdvertising::setPreferredParams` that takes the min and max preferred connection parameters as an alternative for `setMinPreferred` and `setMaxPreferred`. * Added new method, `NimBLEAdvertising::setAdvertisingInterval` Sets the advertisement interval for min and max to the same value instead of calling `setMinInterval` and `setMaxInterval` separately if there is not value difference. * `NimBLEAdvertisementData` payload is now stored in `std::vector<uint8_t>` instead of `std::string`. * `NimBLEAdvertisementData::getPayload` now returns `std::vector<uint8_t>` instead of `std::string`. * `NimBLEAdvertisementData::addData` now takes either a `std::vector<uint8_t>` or `uint8_t* + length` instead of `std::string` or `char + length`. * `NimBLEAdvertisementData::setName` now takes an optional `bool` parameter to indicate if the name is complete or incomplete, default = complete. * `NimBLEAdvertising::start` No longer takes a callback pointer parameter, instead the new method `NimBLEAdvertising::setAdvertisingCompleteCallback` should be used. * `NimBLEAdvertising::setAdvertisementType` has been renamed to `NimBLEAdvertising::setConnectableMode` to better reflect it's function. * `NimBLEAdvertising::setScanResponse` has been renamed to `NimBLEAdvertising::enableScanResponse` to better reflect it's function. * Scan response is no longer enabled by default. * Added new method, `NimBLEAdvertising::setDiscoverableMode` to allow applications to control the discoverability of the advertiser. * Advertising the name and TX power of the device will no longer happen by default and should be set manually by the application. * Added overload for `NimBLEAdvertising::setManufacturerData` that takes a `const uint8_t*` and , size_t` paramter. * Added overload for `NimBLEAdvertising::setServiceData` that takes `const NimBLEUUID& uuid`, ` const uint8_t* data`, ` size_t length` as parameters. * Added overload for `NimBLEAdvertising::setServiceData` that takes `const NimBLEUUID& uuid`, `const std::vector<uint8_t>&` as parameters. * All `NimBLEAdvertisementData` functions that change data values now return `bool`, true = success. * All `NimBLEAdvertising` functions that change data values now return `bool`, true = success. * `NimBLEAdvertising::setMinPreferred` and `NimBLEAdvertising::setMaxPreferred` have been removed, use `NimBLEAdvertising::setPreferredParams` instead. * All advertising data is now stored in instances of `NimBLEAdvertisingData` and vectors removed from `NimBLEAdvertising`. * `NimBLEAdvertising::setAdvertisementData` and `NimBLEAdvertising::setScanResponseData` now return `bool`, true = success. * Added new method, `NimBLEAdvertisementData::removeData`, which takes a parameter `uint8_t type`, the data type to remove. * Added new method, `NimBLEAdvertisementData::toString`, which will print the data in hex. * Added new method, `NimBLEAdvertising::getAdvertisementData`, which returns a reference to the currently set advertisement data. * Added new method, `NimBLEAdvertising::getScanData`, which returns a reference to the currently set scan response data. * Added overloads for `NimBLEAdvertising::removeServiceUUID` and `NimBLEAdvertisementData::removeServiceUUID` to accept a `const char*` * Added new method, `NimBLEAdvertising::clearData`, which will clear the advertisement and scan response data.
2024-07-12 21:04:43 +02:00
pAdvertising->enableScanResponse(true);
2020-08-22 17:56:19 +02:00
pAdvertising->start();
printf("Advertising Started\n");
2023-05-24 23:47:14 +02:00
2024-12-09 20:58:14 +01:00
/** Loop here and send notifications to connected peers */
for (;;) {
if (pServer->getConnectedCount()) {
NimBLEService* pSvc = pServer->getServiceByUUID("BAAD");
if (pSvc) {
NimBLECharacteristic* pChr = pSvc->getCharacteristic("F00D");
if (pChr) {
pChr->notify();
}
}
}
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
2020-08-22 17:56:19 +02:00
}