mirror of
https://github.com/h2zero/esp-nimble-cpp.git
synced 2025-12-25 16:18:08 +01:00
Compare commits
8 Commits
os-agnosti
...
release/1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90bd5740ff | ||
|
|
7b93b0f763 | ||
|
|
11e705f487 | ||
|
|
aeaa432553 | ||
|
|
cbebbd0dc0 | ||
|
|
89bf89f153 | ||
|
|
8cc01bb20a | ||
|
|
cee369fd92 |
@@ -39,7 +39,6 @@ idf_component_register(
|
||||
"src/NimBLEDevice.cpp"
|
||||
"src/NimBLEEddystoneTLM.cpp"
|
||||
"src/NimBLEEddystoneURL.cpp"
|
||||
"src/NimBLEExtAdvertising.cpp"
|
||||
"src/NimBLEHIDDevice.cpp"
|
||||
"src/NimBLERemoteCharacteristic.cpp"
|
||||
"src/NimBLERemoteDescriptor.cpp"
|
||||
|
||||
19
Kconfig
19
Kconfig
@@ -49,24 +49,5 @@ config NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT
|
||||
Enabling this option will display advertisment types recieved
|
||||
while scanning as text messages in the debug log.
|
||||
This will use approximately 250 bytes of flash memory.
|
||||
|
||||
config NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
bool "Enable timestamps to be stored with attribute values."
|
||||
default "n"
|
||||
help
|
||||
Enabling this option will store the timestamp when an attribute value is updated.
|
||||
This allows for checking the last update time using getTimeStamp()
|
||||
or getValue(time_t*). If disabled, the timestamp returned from these functions will be 0.
|
||||
Disabling timestamps will reduce the memory used for each value.
|
||||
|
||||
config NIMBLE_CPP_ATT_VALUE_INIT_LENGTH
|
||||
int "Initial attribute value size (bytes) for empty values."
|
||||
range 1 512
|
||||
default 20
|
||||
help
|
||||
Sets the default allocation size (bytes) for each attribute if not specified
|
||||
when the constructor is called. This is also the size used when a remote
|
||||
characteristic or descriptor is constructed before a value is read/notifed.
|
||||
Increasing this will reduce reallocations but increase memory footprint.
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
# Bluetooth 5.x features
|
||||
|
||||
## About extended advertising
|
||||
Extended advertising allows for much more capability and flexibility.
|
||||
|
||||
* Allows for 251 bytes of advertisement data and up to 1650 bytes when chained (configuration dependant) vs 31.
|
||||
|
||||
* New PHY's (physical layers) that allow for faster data rate (2M PHY) or long range/slower data rates (CODED PHY) as well as the original 1M PHY.
|
||||
|
||||
* New periodic advertising, allowing the scanning device to sync with the advertisements of a beacon. This allows for the scanning device to sleep or perform other tasks before the next expected advertisement is sent, preserving cpu cycles and power (To be implemented).
|
||||
<br>
|
||||
|
||||
## Enabling extended advertising
|
||||
Extended advertising is supported when enabled with the config option `CONFIG_BT_NIMBLE_EXT_ADV` set to a value of 1. This is done in menuconfig under `Component config > Bluetooth > NimBLE options >
|
||||
Enable extended advertising`.
|
||||
|
||||
When enabled the following will occur:
|
||||
* `NimBLEScan::start` method will scan on both the 1M PHY and the coded PHY standards automatically.
|
||||
|
||||
* `NimBLEClient::connect` will use the primary PHY the device is listening on, unless specified (see below).
|
||||
|
||||
* `NimBLEClient::setConnectPhy` becomes available to specify the PHY's to connect with (default is all).
|
||||
|
||||
* `NimBLEAdvertising` is no longer available for use and is replaced by `NimBLEExtAdvertising`. `NimBLEDevice::getAdvertising` will now return an instance of `NimBLEExtAdvertising`.
|
||||
|
||||
* `NimBLEAdvertisementData` is no longer available for use and is replaced by `NimBLEExtAdvertisement`. This new class is where everything about the advertisement is configured, including the advertisement intervals and advertisement ended callback.
|
||||
|
||||
|
||||
|
||||
@@ -6,24 +6,6 @@ Sets the number of simultaneous connections (esp controller max is 9)
|
||||
- Default value is 3
|
||||
<br/>
|
||||
|
||||
`CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED`
|
||||
|
||||
Enable/disable storing the timestamp when an attribute value is updated
|
||||
This allows for checking the last update time using getTimeStamp() or getValue(time_t*)
|
||||
If disabled, the timestamp returned from these functions will be 0.
|
||||
Disabling timestamps will reduce the memory used for each value.
|
||||
1 = Enabled, 0 = Disabled; Default = Disabled
|
||||
<br/>
|
||||
|
||||
`CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH`
|
||||
|
||||
Set the default allocation size (bytes) for each attribute.
|
||||
If not specified when the constructor is called. This is also the size used when a remote
|
||||
characteristic or descriptor is constructed before a value is read/notifed.
|
||||
Increasing this will reduce reallocations but increase memory footprint.
|
||||
Default value is 20. Range: 1 : 512 (BLE_ATT_ATTR_MAX_LEN)
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU`
|
||||
|
||||
Sets the default MTU size.
|
||||
|
||||
@@ -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 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 @@
|
||||
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,169 +0,0 @@
|
||||
|
||||
/** 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);
|
||||
|
||||
void scanEndedCB(NimBLEScanResults results);
|
||||
|
||||
#define SERVICE_UUID "ABCD"
|
||||
#define CHARACTERISTIC_UUID "1234"
|
||||
|
||||
static NimBLEAdvertisedDevice* advDevice;
|
||||
static bool doConnect = false;
|
||||
static uint32_t scanTime = 10; /* 0 = scan forever */
|
||||
|
||||
/* 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 */
|
||||
class ClientCallbacks : public NimBLEClientCallbacks {
|
||||
void onConnect(NimBLEClient* pClient) {
|
||||
printf("Connected\n");
|
||||
};
|
||||
|
||||
void onDisconnect(NimBLEClient* pClient) {
|
||||
printf("%s Disconnected - Starting scan\n", pClient->getPeerAddress().toString().c_str());
|
||||
NimBLEDevice::getScan()->start(scanTime, scanEndedCB);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* Define a class to handle the callbacks when advertisements are received */
|
||||
class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks {
|
||||
|
||||
void onResult(NimBLEAdvertisedDevice* advertisedDevice) {
|
||||
printf("Advertised Device found: %s\n", advertisedDevice->toString().c_str());
|
||||
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*/
|
||||
advDevice = advertisedDevice;
|
||||
/* stop scan before connecting */
|
||||
NimBLEDevice::getScan()->stop();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* Callback to process the results of the last scan or restart it */
|
||||
void scanEndedCB(NimBLEScanResults results){
|
||||
printf("Scan Ended\n");
|
||||
if (!doConnect) { /* Don't start the scan while connecting */
|
||||
NimBLEDevice::getScan()->start(scanTime, scanEndedCB);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Handles the provisioning of clients and connects / interfaces with the server */
|
||||
bool connectToServer() {
|
||||
NimBLEClient* pClient = nullptr;
|
||||
|
||||
pClient = NimBLEDevice::createClient();
|
||||
pClient->setClientCallbacks(new ClientCallbacks, false);
|
||||
|
||||
/* 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
|
||||
* Combine these with OR ("|"), eg BLE_GAP_LE_PHY_1M_MASK | BLE_GAP_LE_PHY_2M_MASK | BLE_GAP_LE_PHY_CODED_MASK;
|
||||
*/
|
||||
pClient->setConnectPhy(connectPhys);
|
||||
|
||||
/** Set how long we are willing to wait for the connection to complete (seconds), default is 30. */
|
||||
pClient->setConnectTimeout(10);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
printf("ABCD service not found.\n");
|
||||
}
|
||||
|
||||
NimBLEDevice::deleteClient(pClient);
|
||||
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) {
|
||||
/* Found a device we want to connect to, do it now */
|
||||
if (connectToServer()) {
|
||||
printf("Success!, scanning for more!\n");
|
||||
} else {
|
||||
printf("Failed to connect, starting scan\n");
|
||||
}
|
||||
|
||||
doConnect = false;
|
||||
NimBLEDevice::getScan()->start(scanTime, scanEndedCB);
|
||||
}
|
||||
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->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallbacks());
|
||||
|
||||
/* 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 seconds) 0 = forever
|
||||
* Optional callback for when scanning stops.
|
||||
*/
|
||||
pScan->start(scanTime, scanEndedCB);
|
||||
|
||||
printf("Scanning for peripherals\n");
|
||||
}
|
||||
@@ -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 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 @@
|
||||
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,139 +0,0 @@
|
||||
/** NimBLE Extended Server Demo:
|
||||
*
|
||||
* Demonstrates the Bluetooth 5.x extended advertising capabilities.
|
||||
*
|
||||
* This demo will advertise a long data string on the CODED and 1M Phy's and
|
||||
* starts a server allowing connection over either PHY's. It will advertise for
|
||||
* 5 seconds then sleep for 20 seconds, if a client connects it will sleep once
|
||||
* it has disconnected then repeats.
|
||||
*
|
||||
* Created: on April 2 2022
|
||||
* Author: H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#include "NimBLEDevice.h"
|
||||
#include "esp_sleep.h"
|
||||
|
||||
extern "C" void app_main(void);
|
||||
|
||||
#define SERVICE_UUID "ABCD"
|
||||
#define CHARACTERISTIC_UUID "1234"
|
||||
|
||||
/* Time in milliseconds to advertise */
|
||||
static uint32_t advTime = 5000;
|
||||
|
||||
/* 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 */
|
||||
static uint8_t primaryPhy = BLE_HCI_LE_PHY_CODED;
|
||||
|
||||
/* 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 */
|
||||
class ServerCallbacks: public NimBLEServerCallbacks {
|
||||
void onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) {
|
||||
printf("Client connected: %s\n", NimBLEAddress(desc->peer_ota_addr).toString().c_str());
|
||||
};
|
||||
|
||||
void onDisconnect(NimBLEServer* pServer) {
|
||||
printf("Client disconnected - sleeping for %u seconds\n", sleepSeconds);
|
||||
esp_deep_sleep_start();
|
||||
};
|
||||
};
|
||||
|
||||
/* Callback class to handle advertising events */
|
||||
class advertisingCallbacks: public NimBLEExtAdvertisingCallbacks {
|
||||
void onStopped(NimBLEExtAdvertising* pAdv, int reason, uint8_t inst_id) {
|
||||
/* Check the reason advertising stopped, don't sleep if client is connecting */
|
||||
printf("Advertising instance %u stopped\n", inst_id);
|
||||
switch (reason) {
|
||||
case 0:
|
||||
printf("Client connecting\n");
|
||||
return;
|
||||
case BLE_HS_ETIMEOUT:
|
||||
printf("Time expired - sleeping for %u seconds\n", sleepSeconds);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
};
|
||||
|
||||
void app_main (void) {
|
||||
NimBLEDevice::init("Extended advertiser");
|
||||
|
||||
/* Create the server and add the services/characteristics/descriptors */
|
||||
NimBLEServer *pServer = NimBLEDevice::createServer();
|
||||
pServer->setCallbacks(new ServerCallbacks);
|
||||
|
||||
NimBLEService *pService = pServer->createService(SERVICE_UUID);
|
||||
NimBLECharacteristic *pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID,
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE |
|
||||
NIMBLE_PROPERTY::NOTIFY);
|
||||
|
||||
pCharacteristic->setValue("Hello World");
|
||||
|
||||
/* Start the services */
|
||||
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 */
|
||||
extAdv.setConnectable(true);
|
||||
|
||||
/* 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 of data in a single advertisement,\r\n"
|
||||
"or up to 1650 bytes with chaining.\r\n"
|
||||
"This example message is 226 bytes long "
|
||||
"and is using CODED_PHY for long range."));
|
||||
|
||||
extAdv.setCompleteServices16({NimBLEUUID(SERVICE_UUID)});
|
||||
|
||||
/* 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);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Note: It is safe to create the advertisement as a local variable if setInstanceData
|
||||
* 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
|
||||
* and a duration in milliseconds or a max number of advertisements to send (or both).
|
||||
*/
|
||||
if (pAdvertising->start(0, advTime)) {
|
||||
printf("Started advertising\n");
|
||||
} else {
|
||||
printf("Failed to start advertising\n");
|
||||
}
|
||||
} else {
|
||||
printf("Failed to register advertisment data\n");
|
||||
}
|
||||
|
||||
esp_sleep_enable_timer_wakeup(sleepSeconds * 1000000);
|
||||
}
|
||||
@@ -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 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 @@
|
||||
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,170 +0,0 @@
|
||||
/** NimBLE Multi Advertiser Demo:
|
||||
*
|
||||
* Demonstrates the Bluetooth 5.x extended advertising capabilities.
|
||||
*
|
||||
* This demo will advertise 2 advertisements, and extended scannable instance
|
||||
* and a connectable legacy instance. They will advertise for 5 seconds then
|
||||
* sleep for 20 seconds. The extended scannable instance will use the scan
|
||||
* request callback to update it's data when a scan response is requested.
|
||||
*
|
||||
* Created: on April 9 2022
|
||||
* Author: H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#include "NimBLEDevice.h"
|
||||
#include "esp_sleep.h"
|
||||
|
||||
extern "C" void app_main(void);
|
||||
|
||||
#define SERVICE_UUID "ABCD"
|
||||
#define CHARACTERISTIC_UUID "1234"
|
||||
|
||||
/* Time in milliseconds to advertise */
|
||||
static uint32_t advTime = 5000;
|
||||
|
||||
/* 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 */
|
||||
static uint8_t primaryPhy = BLE_HCI_LE_PHY_CODED;
|
||||
|
||||
/* 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 */
|
||||
class ServerCallbacks: public NimBLEServerCallbacks {
|
||||
void onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) {
|
||||
printf("Client connected: %s\n", NimBLEAddress(desc->peer_ota_addr).toString().c_str());
|
||||
};
|
||||
|
||||
void onDisconnect(NimBLEServer* pServer) {
|
||||
printf("Client disconnected\n");
|
||||
// if still advertising we won't sleep yet.
|
||||
if (!pServer->getAdvertising()->isAdvertising()) {
|
||||
printf("Sleeping for %u seconds\n", sleepTime);
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/* Callback class to handle advertising events */
|
||||
class advCallbacks: public NimBLEExtAdvertisingCallbacks {
|
||||
void onStopped(NimBLEExtAdvertising* pAdv, int reason, uint8_t inst_id) {
|
||||
/* Check the reason advertising stopped, don't sleep if client is connecting */
|
||||
printf("Advertising instance %u stopped\n", inst_id);
|
||||
switch (reason) {
|
||||
case 0:
|
||||
printf(" client connecting\n");
|
||||
return;
|
||||
case BLE_HS_ETIMEOUT:
|
||||
printf("Time expired - sleeping for %u seconds\n", sleepTime);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
|
||||
bool m_updatedSR = false;
|
||||
|
||||
void onScanRequest(NimBLEExtAdvertising* pAdv, uint8_t inst_id, NimBLEAddress addr) {
|
||||
printf("Scan request for instance %u\n", inst_id);
|
||||
// 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);
|
||||
m_updatedSR = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void app_main (void) {
|
||||
NimBLEDevice::init("Multi advertiser");
|
||||
|
||||
/* Create a server for our legacy advertiser */
|
||||
NimBLEServer *pServer = NimBLEDevice::createServer();
|
||||
pServer->setCallbacks(new ServerCallbacks);
|
||||
|
||||
NimBLEService *pService = pServer->createService(SERVICE_UUID);
|
||||
NimBLECharacteristic *pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID,
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE |
|
||||
NIMBLE_PROPERTY::NOTIFY);
|
||||
|
||||
pCharacteristic->setValue("Hello World");
|
||||
|
||||
/* Start the service */
|
||||
pService->start();
|
||||
|
||||
/* Create our multi advertising instances */
|
||||
|
||||
// extended scannable instance advertising on coded and 1m PHY's.
|
||||
NimBLEExtAdvertisement extScannable(primaryPhy, secondaryPhy);
|
||||
|
||||
// Legacy advertising as a connectable device.
|
||||
NimBLEExtAdvertisement legacyConnectable;
|
||||
|
||||
// Optional scan response data.
|
||||
NimBLEExtAdvertisement legacyScanResponse;
|
||||
|
||||
/* As per Bluetooth specification, extended advertising cannot be both scannable and connectable */
|
||||
extScannable.setScannable(true);
|
||||
extScannable.setConnectable(false);
|
||||
|
||||
/* 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. */
|
||||
extScannable.enableScanRequestCallback(true);
|
||||
|
||||
/* Optional custom address for this advertisment. */
|
||||
legacyConnectable.setAddress(NimBLEAddress("DE:AD:BE:EF:BA:AD"));
|
||||
|
||||
/* Set the advertising data. */
|
||||
legacyConnectable.setName("Legacy");
|
||||
legacyConnectable.setCompleteServices16({NimBLEUUID(SERVICE_UUID)});
|
||||
|
||||
/* Set the legacy and connectable flags. */
|
||||
legacyConnectable.setLegacyAdvertising(true);
|
||||
legacyConnectable.setConnectable(true);
|
||||
|
||||
/* Put some data in the scan response if desired. */
|
||||
legacyScanResponse.setServiceData(NimBLEUUID(SERVICE_UUID), "Legacy SR");
|
||||
|
||||
/* Get the advertising ready */
|
||||
NimBLEExtAdvertising* pAdvertising = NimBLEDevice::getAdvertising();
|
||||
|
||||
/* Set the callbacks to handle advertising events */
|
||||
pAdvertising->setCallbacks(new advCallbacks);
|
||||
|
||||
/* 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 ) &&
|
||||
pAdvertising->setScanResponseData( 1, legacyScanResponse )) {
|
||||
/*
|
||||
* `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)) {
|
||||
printf("Started advertising\n");
|
||||
} else {
|
||||
printf("Failed to start advertising\n");
|
||||
}
|
||||
} else {
|
||||
printf("Failed to register advertisment data\n");
|
||||
}
|
||||
|
||||
esp_sleep_enable_timer_wakeup(sleepTime * 1000000);
|
||||
}
|
||||
20
pkg.yml
20
pkg.yml
@@ -1,20 +0,0 @@
|
||||
pkg.name: esp-nimble-cpp
|
||||
pkg.type: lib
|
||||
pkg.description: NimBLE CPP wrapper
|
||||
pkg.author: "Ryan Powell"
|
||||
pkg.homepage: "http://mynewt.apache.org/"
|
||||
pkg.keywords:
|
||||
|
||||
pkg.deps:
|
||||
- "@apache-mynewt-nimble/nimble"
|
||||
- "@apache-mynewt-nimble/nimble/host"
|
||||
- "@apache-mynewt-nimble/nimble/host/services/gap"
|
||||
- "@apache-mynewt-nimble/nimble/host/services/gatt"
|
||||
- "@apache-mynewt-nimble/nimble/host/store/config"
|
||||
- "@apache-mynewt-nimble/nimble/host/util"
|
||||
|
||||
pkg.source_dirs:
|
||||
- src
|
||||
|
||||
pkg.include_dirs:
|
||||
- src
|
||||
@@ -20,8 +20,6 @@
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
static const char* LOG_TAG = "NimBLEAdvertisedDevice";
|
||||
|
||||
|
||||
@@ -71,7 +69,7 @@ uint8_t NimBLEAdvertisedDevice::getAdvType() {
|
||||
* @return The appearance of the advertised device.
|
||||
*/
|
||||
uint16_t NimBLEAdvertisedDevice::getAppearance() {
|
||||
size_t data_loc = 0;
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_APPEARANCE, 0, &data_loc) > 0) {
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
@@ -89,7 +87,7 @@ uint16_t NimBLEAdvertisedDevice::getAppearance() {
|
||||
* @return The advertisement interval in 0.625ms units.
|
||||
*/
|
||||
uint16_t NimBLEAdvertisedDevice::getAdvInterval() {
|
||||
size_t data_loc = 0;
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_ADV_ITVL, 0, &data_loc) > 0) {
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
@@ -107,7 +105,7 @@ uint16_t NimBLEAdvertisedDevice::getAdvInterval() {
|
||||
* @return The preferred min connection interval in 1.25ms units.
|
||||
*/
|
||||
uint16_t NimBLEAdvertisedDevice::getMinInterval() {
|
||||
size_t data_loc = 0;
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE, 0, &data_loc) > 0) {
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
@@ -125,7 +123,7 @@ uint16_t NimBLEAdvertisedDevice::getMinInterval() {
|
||||
* @return The preferred max connection interval in 1.25ms units.
|
||||
*/
|
||||
uint16_t NimBLEAdvertisedDevice::getMaxInterval() {
|
||||
size_t data_loc = 0;
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE, 0, &data_loc) > 0) {
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
@@ -143,7 +141,7 @@ uint16_t NimBLEAdvertisedDevice::getMaxInterval() {
|
||||
* @return The manufacturer data of the advertised device.
|
||||
*/
|
||||
std::string NimBLEAdvertisedDevice::getManufacturerData() {
|
||||
size_t data_loc = 0;
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_MFG_DATA, 0, &data_loc) > 0) {
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
@@ -161,7 +159,7 @@ std::string NimBLEAdvertisedDevice::getManufacturerData() {
|
||||
* @return The URI data.
|
||||
*/
|
||||
std::string NimBLEAdvertisedDevice::getURI() {
|
||||
size_t data_loc = 0;
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_URI, 0, &data_loc) > 0) {
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
@@ -179,7 +177,7 @@ std::string NimBLEAdvertisedDevice::getURI() {
|
||||
* @return The name of the advertised device.
|
||||
*/
|
||||
std::string NimBLEAdvertisedDevice::getName() {
|
||||
size_t data_loc = 0;
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_COMP_NAME, 0, &data_loc) > 0 ||
|
||||
findAdvField(BLE_HS_ADV_TYPE_INCOMP_NAME, 0, &data_loc) > 0)
|
||||
@@ -216,7 +214,7 @@ NimBLEScan* NimBLEAdvertisedDevice::getScan() {
|
||||
* @brief Get the number of target addresses.
|
||||
* @return The number of addresses.
|
||||
*/
|
||||
uint8_t NimBLEAdvertisedDevice::getTargetAddressCount() {
|
||||
size_t NimBLEAdvertisedDevice::getTargetAddressCount() {
|
||||
uint8_t count = 0;
|
||||
|
||||
count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR);
|
||||
@@ -234,7 +232,7 @@ uint8_t NimBLEAdvertisedDevice::getTargetAddressCount() {
|
||||
NimBLEAddress NimBLEAdvertisedDevice::getTargetAddress(uint8_t index) {
|
||||
ble_hs_adv_field *field = nullptr;
|
||||
uint8_t count = 0;
|
||||
size_t data_loc = ULONG_MAX;
|
||||
uint8_t data_loc = 0xFF;
|
||||
|
||||
index++;
|
||||
count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR, index, &data_loc);
|
||||
@@ -244,7 +242,7 @@ NimBLEAddress NimBLEAdvertisedDevice::getTargetAddress(uint8_t index) {
|
||||
count = findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR, index, &data_loc);
|
||||
}
|
||||
|
||||
if(count > 0 && data_loc != ULONG_MAX) {
|
||||
if(count > 0 && data_loc != 0xFF) {
|
||||
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length < index * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN) {
|
||||
index -= count - field->length / BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN;
|
||||
@@ -266,9 +264,9 @@ NimBLEAddress NimBLEAdvertisedDevice::getTargetAddress(uint8_t index) {
|
||||
std::string NimBLEAdvertisedDevice::getServiceData(uint8_t index) {
|
||||
ble_hs_adv_field *field = nullptr;
|
||||
uint8_t bytes;
|
||||
size_t data_loc = findServiceData(index, &bytes);
|
||||
uint8_t data_loc = findServiceData(index, &bytes);
|
||||
|
||||
if(data_loc != ULONG_MAX) {
|
||||
if(data_loc != 0xFF) {
|
||||
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length > bytes) {
|
||||
return std::string((char*)(field->value + bytes), field->length - bytes - 1);
|
||||
@@ -288,9 +286,9 @@ std::string NimBLEAdvertisedDevice::getServiceData(const NimBLEUUID &uuid) {
|
||||
ble_hs_adv_field *field = nullptr;
|
||||
uint8_t bytes;
|
||||
uint8_t index = 0;
|
||||
size_t data_loc = findServiceData(index, &bytes);
|
||||
size_t plSize = m_payload.size() - 2;
|
||||
uint8_t data_loc = findServiceData(index, &bytes);
|
||||
uint8_t uuidBytes = uuid.bitSize() / 8;
|
||||
uint8_t plSize = m_payload.size() - 2;
|
||||
|
||||
while(data_loc < plSize) {
|
||||
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
@@ -315,9 +313,9 @@ std::string NimBLEAdvertisedDevice::getServiceData(const NimBLEUUID &uuid) {
|
||||
NimBLEUUID NimBLEAdvertisedDevice::getServiceDataUUID(uint8_t index) {
|
||||
ble_hs_adv_field *field = nullptr;
|
||||
uint8_t bytes;
|
||||
size_t data_loc = findServiceData(index, &bytes);
|
||||
uint8_t data_loc = findServiceData(index, &bytes);
|
||||
|
||||
if(data_loc != ULONG_MAX) {
|
||||
if(data_loc != 0xFF) {
|
||||
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length >= bytes) {
|
||||
return NimBLEUUID(field->value, bytes, false);
|
||||
@@ -332,10 +330,10 @@ NimBLEUUID NimBLEAdvertisedDevice::getServiceDataUUID(uint8_t index) {
|
||||
* @brief Find the service data at the index.
|
||||
* @param [in] index The index of the service data to find.
|
||||
* @param [in] bytes A pointer to storage for the number of the bytes in the UUID.
|
||||
* @return The index in the vector where the data is located, ULONG_MAX if not found.
|
||||
* @return The index in the vector where the data is located, 0xFF if not found.
|
||||
*/
|
||||
size_t NimBLEAdvertisedDevice::findServiceData(uint8_t index, uint8_t *bytes) {
|
||||
size_t data_loc = 0;
|
||||
uint8_t NimBLEAdvertisedDevice::findServiceData(uint8_t index, uint8_t *bytes) {
|
||||
uint8_t data_loc = 0;
|
||||
uint8_t found = 0;
|
||||
|
||||
*bytes = 0;
|
||||
@@ -360,7 +358,7 @@ size_t NimBLEAdvertisedDevice::findServiceData(uint8_t index, uint8_t *bytes) {
|
||||
return data_loc;
|
||||
}
|
||||
|
||||
return ULONG_MAX;
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
|
||||
@@ -368,7 +366,7 @@ size_t NimBLEAdvertisedDevice::findServiceData(uint8_t index, uint8_t *bytes) {
|
||||
* @brief Get the count of advertised service data UUIDS
|
||||
* @return The number of service data UUIDS in the vector.
|
||||
*/
|
||||
uint8_t NimBLEAdvertisedDevice::getServiceDataCount() {
|
||||
size_t NimBLEAdvertisedDevice::getServiceDataCount() {
|
||||
uint8_t count = 0;
|
||||
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID16);
|
||||
@@ -386,7 +384,7 @@ uint8_t NimBLEAdvertisedDevice::getServiceDataCount() {
|
||||
*/
|
||||
NimBLEUUID NimBLEAdvertisedDevice::getServiceUUID(uint8_t index) {
|
||||
uint8_t count = 0;
|
||||
size_t data_loc = 0;
|
||||
uint8_t data_loc = 0;
|
||||
uint8_t uuidBytes = 0;
|
||||
uint8_t type = BLE_HS_ADV_TYPE_INCOMP_UUIDS16;
|
||||
ble_hs_adv_field *field = nullptr;
|
||||
@@ -433,7 +431,7 @@ NimBLEUUID NimBLEAdvertisedDevice::getServiceUUID(uint8_t index) {
|
||||
* @brief Get the number of services advertised
|
||||
* @return The count of services in the advertising packet.
|
||||
*/
|
||||
uint8_t NimBLEAdvertisedDevice::getServiceUUIDCount() {
|
||||
size_t NimBLEAdvertisedDevice::getServiceUUIDCount() {
|
||||
uint8_t count = 0;
|
||||
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS16);
|
||||
@@ -469,7 +467,7 @@ bool NimBLEAdvertisedDevice::isAdvertisingService(const NimBLEUUID &uuid) {
|
||||
* @return The TX Power of the advertised device.
|
||||
*/
|
||||
int8_t NimBLEAdvertisedDevice::getTXPower() {
|
||||
size_t data_loc = 0;
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_TX_PWR_LVL, 0, &data_loc) > 0) {
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
@@ -583,60 +581,17 @@ bool NimBLEAdvertisedDevice::haveTXPower() {
|
||||
} // haveTXPower
|
||||
|
||||
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
/**
|
||||
* @brief Get the set ID of the extended advertisement.
|
||||
* @return The set ID.
|
||||
*/
|
||||
uint8_t NimBLEAdvertisedDevice::getSetId() {
|
||||
return m_sid;
|
||||
} // getSetId
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the primary PHY used by this advertisement.
|
||||
* @return The PHY type, one of:
|
||||
* * BLE_HCI_LE_PHY_1M
|
||||
* * BLE_HCI_LE_PHY_CODED
|
||||
*/
|
||||
uint8_t NimBLEAdvertisedDevice::getPrimaryPhy() {
|
||||
return m_primPhy;
|
||||
} // getPrimaryPhy
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the primary PHY used by this advertisement.
|
||||
* @return The PHY type, one of:
|
||||
* * BLE_HCI_LE_PHY_1M
|
||||
* * BLE_HCI_LE_PHY_2M
|
||||
* * BLE_HCI_LE_PHY_CODED
|
||||
*/
|
||||
uint8_t NimBLEAdvertisedDevice::getSecondaryPhy() {
|
||||
return m_secPhy;
|
||||
} // getSecondaryPhy
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the periodic interval of the advertisement.
|
||||
* @return The periodic advertising interval, 0 if not periodic advertising.
|
||||
*/
|
||||
uint16_t NimBLEAdvertisedDevice::getPeriodicInterval() {
|
||||
return m_periodicItvl;
|
||||
} // getPeriodicInterval
|
||||
#endif
|
||||
|
||||
|
||||
uint8_t NimBLEAdvertisedDevice::findAdvField(uint8_t type, uint8_t index, size_t * data_loc) {
|
||||
uint8_t NimBLEAdvertisedDevice::findAdvField(uint8_t type, uint8_t index, uint8_t *data_loc) {
|
||||
ble_hs_adv_field *field = nullptr;
|
||||
size_t length = m_payload.size();
|
||||
size_t data = 0;
|
||||
uint8_t count = 0;
|
||||
uint8_t data = 0;
|
||||
uint8_t length = m_payload.size();
|
||||
uint8_t count = 0;
|
||||
|
||||
if (length < 3) {
|
||||
if(length < 2) {
|
||||
return count;
|
||||
}
|
||||
|
||||
while (length > 2) {
|
||||
while (length > 1) {
|
||||
field = (ble_hs_adv_field*)&m_payload[data];
|
||||
|
||||
if (field->length >= length) {
|
||||
@@ -644,7 +599,7 @@ uint8_t NimBLEAdvertisedDevice::findAdvField(uint8_t type, uint8_t index, size_t
|
||||
}
|
||||
|
||||
if (field->type == type) {
|
||||
switch (type) {
|
||||
switch(type) {
|
||||
case BLE_HS_ADV_TYPE_INCOMP_UUIDS16:
|
||||
case BLE_HS_ADV_TYPE_COMP_UUIDS16:
|
||||
count += field->length / 2;
|
||||
@@ -670,8 +625,8 @@ uint8_t NimBLEAdvertisedDevice::findAdvField(uint8_t type, uint8_t index, size_t
|
||||
break;
|
||||
}
|
||||
|
||||
if (data_loc != nullptr) {
|
||||
if (index == 0 || count >= index) {
|
||||
if(data_loc != nullptr) {
|
||||
if(index == 0 || count >= index) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -681,7 +636,7 @@ uint8_t NimBLEAdvertisedDevice::findAdvField(uint8_t type, uint8_t index, size_t
|
||||
data += 1 + field->length;
|
||||
}
|
||||
|
||||
if (data_loc != nullptr && field != nullptr) {
|
||||
if(data_loc != nullptr && field != nullptr) {
|
||||
*data_loc = data;
|
||||
}
|
||||
|
||||
@@ -702,13 +657,8 @@ void NimBLEAdvertisedDevice::setAddress(NimBLEAddress address) {
|
||||
* @brief Set the adFlag for this device.
|
||||
* @param [in] advType The advertisement flag data from the advertisement.
|
||||
*/
|
||||
void NimBLEAdvertisedDevice::setAdvType(uint8_t advType, bool isLegacyAdv) {
|
||||
void NimBLEAdvertisedDevice::setAdvType(uint8_t advType) {
|
||||
m_advType = advType;
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
m_isLegacyAdv = isLegacyAdv;
|
||||
#else
|
||||
(void)isLegacyAdv;
|
||||
#endif
|
||||
} // setAdvType
|
||||
|
||||
|
||||
@@ -753,10 +703,10 @@ std::string NimBLEAdvertisedDevice::toString() {
|
||||
res += val;
|
||||
}
|
||||
|
||||
if (haveServiceData()) {
|
||||
uint8_t count = getServiceDataCount();
|
||||
if(haveServiceData()) {
|
||||
size_t count = getServiceDataCount();
|
||||
res += "\nService Data:";
|
||||
for(uint8_t i = 0; i < count; i++) {
|
||||
for(size_t i = 0; i < count; i++) {
|
||||
res += "\nUUID: " + std::string(getServiceDataUUID(i));
|
||||
res += ", Data: " + getServiceData(i);
|
||||
}
|
||||
@@ -831,34 +781,5 @@ size_t NimBLEAdvertisedDevice::getPayloadLength() {
|
||||
return m_payload.size();
|
||||
} // getPayloadLength
|
||||
|
||||
|
||||
/**
|
||||
* @brief Check if this device is advertising as connectable.
|
||||
* @return True if the device is connectable.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::isConnectable() {
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
if (m_isLegacyAdv) {
|
||||
return m_advType == BLE_HCI_ADV_RPT_EVTYPE_ADV_IND ||
|
||||
m_advType == BLE_HCI_ADV_RPT_EVTYPE_DIR_IND;
|
||||
}
|
||||
#endif
|
||||
return (m_advType & BLE_HCI_ADV_CONN_MASK) ||
|
||||
(m_advType & BLE_HCI_ADV_DIRECT_MASK);
|
||||
} // isConnectable
|
||||
|
||||
|
||||
/**
|
||||
* @brief Check if this advertisement is a legacy or extended type
|
||||
* @return True if legacy (Bluetooth 4.x), false if extended (bluetooth 5.x).
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::isLegacyAdvertisement() {
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
return m_isLegacyAdv;
|
||||
# else
|
||||
return true;
|
||||
#endif
|
||||
} // isLegacyAdvertisement
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ public:
|
||||
std::string getName();
|
||||
int getRSSI();
|
||||
NimBLEScan* getScan();
|
||||
uint8_t getServiceDataCount();
|
||||
size_t getServiceDataCount();
|
||||
std::string getServiceData(uint8_t index = 0);
|
||||
std::string getServiceData(const NimBLEUUID &uuid);
|
||||
|
||||
@@ -111,9 +111,9 @@ public:
|
||||
|
||||
NimBLEUUID getServiceDataUUID(uint8_t index = 0);
|
||||
NimBLEUUID getServiceUUID(uint8_t index = 0);
|
||||
uint8_t getServiceUUIDCount();
|
||||
size_t getServiceUUIDCount();
|
||||
NimBLEAddress getTargetAddress(uint8_t index = 0);
|
||||
uint8_t getTargetAddressCount();
|
||||
size_t getTargetAddressCount();
|
||||
int8_t getTXPower();
|
||||
uint8_t* getPayload();
|
||||
uint8_t getAdvLength();
|
||||
@@ -133,30 +133,16 @@ public:
|
||||
bool haveTargetAddress();
|
||||
bool haveURI();
|
||||
std::string toString();
|
||||
bool isConnectable();
|
||||
bool isLegacyAdvertisement();
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
uint8_t getSetId();
|
||||
uint8_t getPrimaryPhy();
|
||||
uint8_t getSecondaryPhy();
|
||||
uint16_t getPeriodicInterval();
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class NimBLEScan;
|
||||
|
||||
void setAddress(NimBLEAddress address);
|
||||
void setAdvType(uint8_t advType, bool isLegacyAdv);
|
||||
void setAdvType(uint8_t advType);
|
||||
void setPayload(const uint8_t *payload, uint8_t length, bool append);
|
||||
void setRSSI(int rssi);
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
void setSetId(uint8_t sid) { m_sid = sid; }
|
||||
void setPrimaryPhy(uint8_t phy) { m_primPhy = phy; }
|
||||
void setSecondaryPhy(uint8_t phy) { m_secPhy = phy; }
|
||||
void setPeriodicInterval(uint16_t itvl) { m_periodicItvl = itvl; }
|
||||
#endif
|
||||
uint8_t findAdvField(uint8_t type, uint8_t index = 0, size_t * data_loc = nullptr);
|
||||
size_t findServiceData(uint8_t index, uint8_t* bytes);
|
||||
uint8_t findAdvField(uint8_t type, uint8_t index = 0, uint8_t *data_loc = nullptr);
|
||||
uint8_t findServiceData(uint8_t index, uint8_t* bytes);
|
||||
|
||||
NimBLEAddress m_address = NimBLEAddress("");
|
||||
uint8_t m_advType;
|
||||
@@ -164,13 +150,6 @@ private:
|
||||
time_t m_timestamp;
|
||||
bool m_callbackSent;
|
||||
uint8_t m_advLength;
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
bool m_isLegacyAdv;
|
||||
uint8_t m_sid;
|
||||
uint8_t m_primPhy;
|
||||
uint8_t m_secPhy;
|
||||
uint16_t m_periodicItvl;
|
||||
#endif
|
||||
|
||||
std::vector<uint8_t> m_payload;
|
||||
};
|
||||
|
||||
@@ -14,9 +14,7 @@
|
||||
*
|
||||
*/
|
||||
#include "nimconfig.h"
|
||||
#if (defined(CONFIG_BT_ENABLED) && \
|
||||
defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) && \
|
||||
!CONFIG_BT_NIMBLE_EXT_ADV) || defined(_DOXYGEN_)
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
@@ -414,7 +412,7 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
|
||||
// If already advertising just return
|
||||
if(ble_gap_adv_active()) {
|
||||
NIMBLE_LOGW(LOG_TAG, "Advertising already active");
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save the duration incase of host reset so we can restart with the same params
|
||||
@@ -627,7 +625,7 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
|
||||
&m_advParams,
|
||||
(pServer != nullptr) ? NimBLEServer::handleGapEvent :
|
||||
NimBLEAdvertising::handleGapEvent,
|
||||
(void*)this);
|
||||
(pServer != nullptr) ? (void*)pServer : (void*)this);
|
||||
#else
|
||||
rc = ble_gap_adv_start(NimBLEDevice::m_own_addr_type, NULL, duration,
|
||||
&m_advParams, NimBLEAdvertising::handleGapEvent, this);
|
||||
@@ -636,10 +634,6 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case BLE_HS_EALREADY:
|
||||
NIMBLE_LOGI(LOG_TAG, "Advertisement Already active");
|
||||
break;
|
||||
|
||||
case BLE_HS_EINVAL:
|
||||
NIMBLE_LOGE(LOG_TAG, "Unable to advertise - Duration too long");
|
||||
break;
|
||||
@@ -662,26 +656,24 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< Advertising start");
|
||||
return (rc == 0 || rc == BLE_HS_EALREADY);
|
||||
return (rc == 0);
|
||||
} // start
|
||||
|
||||
|
||||
/**
|
||||
* @brief Stop advertising.
|
||||
* @return True if advertising stopped successfully.
|
||||
*/
|
||||
bool NimBLEAdvertising::stop() {
|
||||
void NimBLEAdvertising::stop() {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> stop");
|
||||
|
||||
int rc = ble_gap_adv_stop();
|
||||
if (rc != 0 && rc != BLE_HS_EALREADY) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_adv_stop rc=%d %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< stop");
|
||||
return true;
|
||||
} // stop
|
||||
|
||||
|
||||
@@ -1034,4 +1026,4 @@ std::string NimBLEAdvertisementData::getPayload() {
|
||||
return m_payload;
|
||||
} // getPayload
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && !CONFIG_BT_NIMBLE_EXT_ADV */
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER */
|
||||
|
||||
@@ -15,9 +15,7 @@
|
||||
#ifndef MAIN_BLEADVERTISING_H_
|
||||
#define MAIN_BLEADVERTISING_H_
|
||||
#include "nimconfig.h"
|
||||
#if (defined(CONFIG_BT_ENABLED) && \
|
||||
defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) && \
|
||||
!CONFIG_BT_NIMBLE_EXT_ADV) || defined(_DOXYGEN_)
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "host/ble_gap.h"
|
||||
@@ -91,7 +89,7 @@ public:
|
||||
void addServiceUUID(const char* serviceUUID);
|
||||
void removeServiceUUID(const NimBLEUUID &serviceUUID);
|
||||
bool start(uint32_t duration = 0, void (*advCompleteCB)(NimBLEAdvertising *pAdv) = nullptr);
|
||||
bool stop();
|
||||
void stop();
|
||||
void setAppearance(uint16_t appearance);
|
||||
void setName(const std::string &name);
|
||||
void setManufacturerData(const std::string &data);
|
||||
@@ -113,7 +111,6 @@ public:
|
||||
|
||||
private:
|
||||
friend class NimBLEDevice;
|
||||
friend class NimBLEServer;
|
||||
|
||||
void onHostSync();
|
||||
static int handleGapEvent(struct ble_gap_event *event, void *arg);
|
||||
@@ -137,5 +134,5 @@ private:
|
||||
std::vector<uint8_t> m_uri;
|
||||
};
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && !CONFIG_BT_NIMBLE_EXT_ADV */
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER */
|
||||
#endif /* MAIN_BLEADVERTISING_H_ */
|
||||
|
||||
@@ -1,447 +0,0 @@
|
||||
/*
|
||||
* NimBLEAttValue.h
|
||||
*
|
||||
* Created: on March 18, 2021
|
||||
* Author H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MAIN_NIMBLEATTVALUE_H_
|
||||
#define MAIN_NIMBLEATTVALUE_H_
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#ifdef NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
#include "NimBLELog.h"
|
||||
|
||||
/**** FIX COMPILATION ****/
|
||||
#undef min
|
||||
#undef max
|
||||
/**************************/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifndef CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
# define CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED 0
|
||||
#endif
|
||||
|
||||
#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
# include <time.h>
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH)
|
||||
# define CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH 20
|
||||
#elif CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH > BLE_ATT_ATTR_MAX_LEN
|
||||
# error CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH cannot be larger than 512 (BLE_ATT_ATTR_MAX_LEN)
|
||||
#elif CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH < 1
|
||||
# error CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH cannot be less than 1; Range = 1 : 512
|
||||
#endif
|
||||
|
||||
|
||||
/* Used to determine if the type passed to a template has a c_str() and length() method. */
|
||||
template <typename T, typename = void, typename = void>
|
||||
struct Has_c_str_len : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct Has_c_str_len<T, decltype(void(std::declval<T &>().c_str())),
|
||||
decltype(void(std::declval<T &>().length()))> : std::true_type {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief A specialized container class to hold BLE attribute values.
|
||||
* @details This class is designed to be more memory efficient than using\n
|
||||
* standard container types for value storage, while being convertable to\n
|
||||
* many different container classes.
|
||||
*/
|
||||
class NimBLEAttValue
|
||||
{
|
||||
uint8_t* m_attr_value = nullptr;
|
||||
uint16_t m_attr_max_len = 0;
|
||||
uint16_t m_attr_len = 0;
|
||||
uint16_t m_capacity = 0;
|
||||
#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
time_t m_timestamp = 0;
|
||||
#endif
|
||||
void deepCopy(const NimBLEAttValue & source);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor.
|
||||
* @param[in] init_len The initial size in bytes.
|
||||
* @param[in] max_len The max size in bytes that the value can be.
|
||||
*/
|
||||
NimBLEAttValue(uint16_t init_len = CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH,
|
||||
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
|
||||
|
||||
/**
|
||||
* @brief Construct with an initial value from a buffer.
|
||||
* @param value A pointer to the initial value to set.
|
||||
* @param[in] len The size in bytes of the value to set.
|
||||
* @param[in] max_len The max size in bytes that the value can be.
|
||||
*/
|
||||
NimBLEAttValue(const uint8_t *value, uint16_t len,
|
||||
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
|
||||
|
||||
/**
|
||||
* @brief Construct with an initializer list.
|
||||
* @param list An initializer list containing the initial value to set.
|
||||
* @param[in] max_len The max size in bytes that the value can be.
|
||||
*/
|
||||
NimBLEAttValue(std::initializer_list<uint8_t> list,
|
||||
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
|
||||
:NimBLEAttValue(list.begin(), (uint16_t)list.size(), max_len){}
|
||||
|
||||
/**
|
||||
* @brief Construct with an initial value from a const char string.
|
||||
* @param value A pointer to the initial value to set.
|
||||
* @param[in] max_len The max size in bytes that the value can be.
|
||||
*/
|
||||
NimBLEAttValue(const char *value, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
|
||||
:NimBLEAttValue((uint8_t*)value, (uint16_t)strlen(value), max_len){}
|
||||
|
||||
/**
|
||||
* @brief Construct with an initial value from a std::string.
|
||||
* @param str A std::string containing to the initial value to set.
|
||||
* @param[in] max_len The max size in bytes that the value can be.
|
||||
*/
|
||||
NimBLEAttValue(const std::string str, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
|
||||
:NimBLEAttValue((uint8_t*)str.data(), (uint16_t)str.length(), max_len){}
|
||||
|
||||
/**
|
||||
* @brief Construct with an initial value from a std::vector<uint8_t>.
|
||||
* @param vec A std::vector<uint8_t> containing to the initial value to set.
|
||||
* @param[in] max_len The max size in bytes that the value can be.
|
||||
*/
|
||||
NimBLEAttValue(const std::vector<uint8_t> vec, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
|
||||
:NimBLEAttValue(&vec[0], (uint16_t)vec.size(), max_len){}
|
||||
|
||||
#ifdef NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
|
||||
/**
|
||||
* @brief Construct with an initial value from an Arduino String.
|
||||
* @param str An Arduino String containing to the initial value to set.
|
||||
* @param[in] max_len The max size in bytes that the value can be.
|
||||
*/
|
||||
NimBLEAttValue(const String str, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
|
||||
:NimBLEAttValue((uint8_t*)str.c_str(), str.length(), max_len){}
|
||||
#endif
|
||||
|
||||
/** @brief Copy constructor */
|
||||
NimBLEAttValue(const NimBLEAttValue & source) { deepCopy(source); }
|
||||
|
||||
/** @brief Move constructor */
|
||||
NimBLEAttValue(NimBLEAttValue && source) { *this = std::move(source); }
|
||||
|
||||
/** @brief Destructor */
|
||||
~NimBLEAttValue();
|
||||
|
||||
/** @brief Returns the max size in bytes */
|
||||
uint16_t max_size() const { return m_attr_max_len; }
|
||||
|
||||
/** @brief Returns the currently allocated capacity in bytes */
|
||||
uint16_t capacity() const { return m_capacity; }
|
||||
|
||||
/** @brief Returns the current length of the value in bytes */
|
||||
uint16_t length() const { return m_attr_len; }
|
||||
|
||||
/** @brief Returns the current size of the value in bytes */
|
||||
uint16_t size() const { return m_attr_len; }
|
||||
|
||||
/** @brief Returns a pointer to the internal buffer of the value */
|
||||
const uint8_t* data() const { return m_attr_value; }
|
||||
|
||||
/** @brief Returns a pointer to the internal buffer of the value as a const char* */
|
||||
const char* c_str() const { return (const char*)m_attr_value; }
|
||||
|
||||
/** @brief Iterator begin */
|
||||
const uint8_t* begin() const { return m_attr_value; }
|
||||
|
||||
/** @brief Iterator end */
|
||||
const uint8_t* end() const { return m_attr_value + m_attr_len; }
|
||||
|
||||
#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
/** @brief Returns a timestamp of when the value was last updated */
|
||||
time_t getTimeStamp() const { return m_timestamp; }
|
||||
|
||||
/** @brief Set the timestamp to the current time */
|
||||
void setTimeStamp() { m_timestamp = time(nullptr); }
|
||||
|
||||
/**
|
||||
* @brief Set the timestamp to the specified time
|
||||
* @param[in] t The timestamp value to set
|
||||
*/
|
||||
void setTimeStamp(time_t t) { m_timestamp = t; }
|
||||
#else
|
||||
time_t getTimeStamp() const { return 0; }
|
||||
void setTimeStamp() { }
|
||||
void setTimeStamp(time_t t) { }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Set the value from a buffer
|
||||
* @param[in] value A ponter to a buffer containing the value.
|
||||
* @param[in] len The length of the value in bytes.
|
||||
* @returns True if successful.
|
||||
*/
|
||||
bool setValue(const uint8_t *value, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief Set value to the value of const char*.
|
||||
* @param [in] s A ponter to a const char value to set.
|
||||
*/
|
||||
bool setValue(const char* s) {
|
||||
return setValue((uint8_t*)s, (uint16_t)strlen(s)); }
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the value buffer with timestamp.
|
||||
* @param[in] timestamp A ponter to a time_t variable to store the timestamp.
|
||||
* @returns A pointer to the internal value buffer.
|
||||
*/
|
||||
const uint8_t* getValue(time_t *timestamp);
|
||||
|
||||
/**
|
||||
* @brief Append data to the value.
|
||||
* @param[in] value A ponter to a data buffer with the value to append.
|
||||
* @param[in] len The length of the value to append in bytes.
|
||||
* @returns A reference to the appended NimBLEAttValue.
|
||||
*/
|
||||
NimBLEAttValue& append(const uint8_t *value, uint16_t len);
|
||||
|
||||
|
||||
/*********************** Template Functions ************************/
|
||||
|
||||
/**
|
||||
* @brief Template to set value to the value of <type\>val.
|
||||
* @param [in] s The <type\>value to set.
|
||||
* @details Only used for types without a `c_str()` method.
|
||||
*/
|
||||
template<typename T>
|
||||
#ifdef _DOXYGEN_
|
||||
bool
|
||||
#else
|
||||
typename std::enable_if<!Has_c_str_len<T>::value, bool>::type
|
||||
#endif
|
||||
setValue(const T &s) {
|
||||
return setValue((uint8_t*)&s, sizeof(T));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to set value to the value of <type\>val.
|
||||
* @param [in] s The <type\>value to set.
|
||||
* @details Only used if the <type\> has a `c_str()` method.
|
||||
*/
|
||||
template<typename T>
|
||||
#ifdef _DOXYGEN_
|
||||
bool
|
||||
#else
|
||||
typename std::enable_if<Has_c_str_len<T>::value, bool>::type
|
||||
#endif
|
||||
setValue(const T & s) {
|
||||
return setValue((uint8_t*)s.c_str(), (uint16_t)s.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to return the value as a <type\>.
|
||||
* @tparam T The type to convert the data to.
|
||||
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
|
||||
* @param [in] skipSizeCheck If true it will skip checking if the data size is less than\n
|
||||
* <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is\n
|
||||
* less than <tt>sizeof(<type\>)</tt>.
|
||||
* @details <b>Use:</b> <tt>getValue<type>(×tamp, skipSizeCheck);</tt>
|
||||
*/
|
||||
template<typename T>
|
||||
T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
|
||||
if(!skipSizeCheck && size() < sizeof(T)) {
|
||||
return T();
|
||||
}
|
||||
return *((T *)getValue(timestamp));
|
||||
}
|
||||
|
||||
|
||||
/*********************** Operators ************************/
|
||||
|
||||
/** @brief Subscript operator */
|
||||
uint8_t operator [](int pos) const {
|
||||
assert(pos < m_attr_len && "out of range"); return m_attr_value[pos]; }
|
||||
|
||||
/** @brief Operator; Get the value as a std::vector<uint8_t>. */
|
||||
operator std::vector<uint8_t>() const {
|
||||
return std::vector<uint8_t>(m_attr_value, m_attr_value + m_attr_len); }
|
||||
|
||||
/** @brief Operator; Get the value as a std::string. */
|
||||
operator std::string() const {
|
||||
return std::string((char*)m_attr_value, m_attr_len); }
|
||||
|
||||
/** @brief Operator; Get the value as a const uint8_t*. */
|
||||
operator const uint8_t*() const { return m_attr_value; }
|
||||
|
||||
/** @brief Operator; Append another NimBLEAttValue. */
|
||||
NimBLEAttValue& operator +=(const NimBLEAttValue & source) {
|
||||
return append(source.data(), source.size()); }
|
||||
|
||||
/** @brief Operator; Set the value from a std::string source. */
|
||||
NimBLEAttValue& operator =(const std::string & source) {
|
||||
setValue((uint8_t*)source.data(), (uint16_t)source.size()); return *this; }
|
||||
|
||||
/** @brief Move assignment operator */
|
||||
NimBLEAttValue& operator =(NimBLEAttValue && source);
|
||||
|
||||
/** @brief Copy assignment operator */
|
||||
NimBLEAttValue& operator =(const NimBLEAttValue & source);
|
||||
|
||||
/** @brief Equality operator */
|
||||
bool operator ==(const NimBLEAttValue & source) {
|
||||
return (m_attr_len == source.size()) ?
|
||||
memcmp(m_attr_value, source.data(), m_attr_len) == 0 : false; }
|
||||
|
||||
/** @brief Inequality operator */
|
||||
bool operator !=(const NimBLEAttValue & source){ return !(*this == source); }
|
||||
|
||||
#ifdef NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
|
||||
/** @brief Operator; Get the value as an Arduino String value. */
|
||||
operator String() const { return String((char*)m_attr_value); }
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
inline NimBLEAttValue::NimBLEAttValue(uint16_t init_len, uint16_t max_len) {
|
||||
m_attr_value = (uint8_t*)calloc(init_len + 1, 1);
|
||||
assert(m_attr_value && "No Mem");
|
||||
m_attr_max_len = std::min(BLE_ATT_ATTR_MAX_LEN, (int)max_len);
|
||||
m_attr_len = 0;
|
||||
m_capacity = init_len;
|
||||
setTimeStamp(0);
|
||||
}
|
||||
|
||||
inline NimBLEAttValue::NimBLEAttValue(const uint8_t *value, uint16_t len, uint16_t max_len)
|
||||
: NimBLEAttValue(len, max_len) {
|
||||
memcpy(m_attr_value, value, len);
|
||||
m_attr_value[len] = '\0';
|
||||
m_attr_len = len;
|
||||
}
|
||||
|
||||
inline NimBLEAttValue::~NimBLEAttValue() {
|
||||
if(m_attr_value != nullptr) {
|
||||
free(m_attr_value);
|
||||
}
|
||||
}
|
||||
|
||||
inline NimBLEAttValue& NimBLEAttValue::operator =(NimBLEAttValue && source) {
|
||||
if (this != &source){
|
||||
free(m_attr_value);
|
||||
|
||||
m_attr_value = source.m_attr_value;
|
||||
m_attr_max_len = source.m_attr_max_len;
|
||||
m_attr_len = source.m_attr_len;
|
||||
m_capacity = source.m_capacity;
|
||||
setTimeStamp(source.getTimeStamp());
|
||||
source.m_attr_value = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline NimBLEAttValue& NimBLEAttValue::operator =(const NimBLEAttValue & source) {
|
||||
if (this != &source) {
|
||||
deepCopy(source);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void NimBLEAttValue::deepCopy(const NimBLEAttValue & source) {
|
||||
uint8_t* res = (uint8_t*)realloc( m_attr_value, source.m_capacity + 1);
|
||||
assert(res && "deepCopy: realloc failed");
|
||||
|
||||
ble_npl_hw_enter_critical();
|
||||
m_attr_value = res;
|
||||
m_attr_max_len = source.m_attr_max_len;
|
||||
m_attr_len = source.m_attr_len;
|
||||
m_capacity = source.m_capacity;
|
||||
setTimeStamp(source.getTimeStamp());
|
||||
memcpy(m_attr_value, source.m_attr_value, m_attr_len + 1);
|
||||
ble_npl_hw_exit_critical(0);
|
||||
}
|
||||
|
||||
inline const uint8_t* NimBLEAttValue::getValue(time_t *timestamp) {
|
||||
if(timestamp != nullptr) {
|
||||
#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
*timestamp = m_timestamp;
|
||||
#else
|
||||
*timestamp = 0;
|
||||
#endif
|
||||
}
|
||||
return m_attr_value;
|
||||
}
|
||||
|
||||
inline bool NimBLEAttValue::setValue(const uint8_t *value, uint16_t len) {
|
||||
if (len > m_attr_max_len) {
|
||||
NIMBLE_LOGE("NimBLEAttValue", "value exceeds max, len=%u, max=%u",
|
||||
len, m_attr_max_len);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t *res = m_attr_value;
|
||||
if (len > m_capacity) {
|
||||
res = (uint8_t*)realloc(m_attr_value, (len + 1));
|
||||
m_capacity = len;
|
||||
}
|
||||
assert(res && "setValue: realloc failed");
|
||||
|
||||
#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
time_t t = time(nullptr);
|
||||
#else
|
||||
time_t t = 0;
|
||||
#endif
|
||||
|
||||
ble_npl_hw_enter_critical();
|
||||
m_attr_value = res;
|
||||
memcpy(m_attr_value, value, len);
|
||||
m_attr_value[len] = '\0';
|
||||
m_attr_len = len;
|
||||
setTimeStamp(t);
|
||||
ble_npl_hw_exit_critical(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline NimBLEAttValue& NimBLEAttValue::append(const uint8_t *value, uint16_t len) {
|
||||
if (len < 1) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
if ((m_attr_len + len) > m_attr_max_len) {
|
||||
NIMBLE_LOGE("NimBLEAttValue", "val > max, len=%u, max=%u",
|
||||
len, m_attr_max_len);
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint8_t* res = m_attr_value;
|
||||
uint16_t new_len = m_attr_len + len;
|
||||
if (new_len > m_capacity) {
|
||||
res = (uint8_t*)realloc(m_attr_value, (new_len + 1));
|
||||
m_capacity = new_len;
|
||||
}
|
||||
assert(res && "append: realloc failed");
|
||||
|
||||
#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
time_t t = time(nullptr);
|
||||
#else
|
||||
time_t t = 0;
|
||||
#endif
|
||||
|
||||
ble_npl_hw_enter_critical();
|
||||
m_attr_value = res;
|
||||
memcpy(m_attr_value + m_attr_len, value, len);
|
||||
m_attr_len = new_len;
|
||||
m_attr_value[m_attr_len] = '\0';
|
||||
setTimeStamp(t);
|
||||
ble_npl_hw_exit_critical(0);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif /*(CONFIG_BT_ENABLED) */
|
||||
#endif /* MAIN_NIMBLEATTVALUE_H_ */
|
||||
@@ -30,29 +30,26 @@ static const char* LOG_TAG = "NimBLECharacteristic";
|
||||
* @brief Construct a characteristic
|
||||
* @param [in] uuid - UUID (const char*) for the characteristic.
|
||||
* @param [in] properties - Properties for the characteristic.
|
||||
* @param [in] max_len - The maximum length in bytes that the characteristic value can hold. (Default: 512 bytes for esp32, 20 for all others).
|
||||
* @param [in] pService - pointer to the service instance this characteristic belongs to.
|
||||
*/
|
||||
NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties,
|
||||
uint16_t max_len, NimBLEService* pService)
|
||||
: NimBLECharacteristic(NimBLEUUID(uuid), properties, max_len, pService) {
|
||||
NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties, NimBLEService* pService)
|
||||
: NimBLECharacteristic(NimBLEUUID(uuid), properties, pService) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a characteristic
|
||||
* @param [in] uuid - UUID for the characteristic.
|
||||
* @param [in] properties - Properties for the characteristic.
|
||||
* @param [in] max_len - The maximum length in bytes that the characteristic value can hold. (Default: 512 bytes for esp32, 20 for all others).
|
||||
* @param [in] pService - pointer to the service instance this characteristic belongs to.
|
||||
*/
|
||||
NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t properties,
|
||||
uint16_t max_len, NimBLEService* pService)
|
||||
: m_value(std::min(CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH , (int)max_len), max_len) {
|
||||
NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t properties, NimBLEService* pService) {
|
||||
m_uuid = uuid;
|
||||
m_handle = NULL_HANDLE;
|
||||
m_properties = properties;
|
||||
m_pCallbacks = &defaultCallback;
|
||||
m_pService = pService;
|
||||
m_value = "";
|
||||
m_timestamp = 0;
|
||||
m_removed = 0;
|
||||
} // NimBLECharacteristic
|
||||
|
||||
@@ -234,14 +231,17 @@ NimBLEUUID NimBLECharacteristic::getUUID() {
|
||||
|
||||
/**
|
||||
* @brief Retrieve the current value of the characteristic.
|
||||
* @return The NimBLEAttValue containing the current characteristic value.
|
||||
* @return A std::string containing the current characteristic value.
|
||||
*/
|
||||
NimBLEAttValue NimBLECharacteristic::getValue(time_t *timestamp) {
|
||||
std::string NimBLECharacteristic::getValue(time_t *timestamp) {
|
||||
ble_npl_hw_enter_critical();
|
||||
std::string retVal = m_value;
|
||||
if(timestamp != nullptr) {
|
||||
m_value.getValue(timestamp);
|
||||
*timestamp = m_timestamp;
|
||||
}
|
||||
ble_npl_hw_exit_critical(0);
|
||||
|
||||
return m_value;
|
||||
return retVal;
|
||||
} // getValue
|
||||
|
||||
|
||||
@@ -250,7 +250,10 @@ NimBLEAttValue NimBLECharacteristic::getValue(time_t *timestamp) {
|
||||
* @return The length of the current characteristic data.
|
||||
*/
|
||||
size_t NimBLECharacteristic::getDataLength() {
|
||||
return m_value.size();
|
||||
ble_npl_hw_enter_critical();
|
||||
size_t len = m_value.length();
|
||||
ble_npl_hw_exit_critical(0);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
@@ -283,26 +286,25 @@ int NimBLECharacteristic::handleGapEvent(uint16_t conn_handle, uint16_t attr_han
|
||||
}
|
||||
|
||||
ble_npl_hw_enter_critical();
|
||||
rc = os_mbuf_append(ctxt->om, pCharacteristic->m_value.data(), pCharacteristic->m_value.size());
|
||||
rc = os_mbuf_append(ctxt->om, (uint8_t*)pCharacteristic->m_value.data(),
|
||||
pCharacteristic->m_value.length());
|
||||
ble_npl_hw_exit_critical(0);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
case BLE_GATT_ACCESS_OP_WRITE_CHR: {
|
||||
uint16_t att_max_len = pCharacteristic->m_value.max_size();
|
||||
|
||||
if (ctxt->om->om_len > att_max_len) {
|
||||
if (ctxt->om->om_len > BLE_ATT_ATTR_MAX_LEN) {
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
|
||||
uint8_t buf[att_max_len];
|
||||
uint8_t buf[BLE_ATT_ATTR_MAX_LEN];
|
||||
size_t len = ctxt->om->om_len;
|
||||
memcpy(buf, ctxt->om->om_data,len);
|
||||
|
||||
os_mbuf *next;
|
||||
next = SLIST_NEXT(ctxt->om, om_next);
|
||||
while(next != NULL){
|
||||
if((len + next->om_len) > att_max_len) {
|
||||
if((len + next->om_len) > BLE_ATT_ATTR_MAX_LEN) {
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
memcpy(&buf[len], next->om_data, next->om_len);
|
||||
@@ -382,58 +384,36 @@ void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send an indication.
|
||||
* @brief Send an indication.\n
|
||||
* An indication is a transmission of up to the first 20 bytes of the characteristic value.\n
|
||||
* An indication will block waiting for a positive confirmation from the client.
|
||||
*/
|
||||
void NimBLECharacteristic::indicate() {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> indicate: length: %d", getDataLength());
|
||||
notify(false);
|
||||
NIMBLE_LOGD(LOG_TAG, "<< indicate");
|
||||
} // indicate
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send an indication.
|
||||
* @param[in] value A pointer to the data to send.
|
||||
* @param[in] length The length of the data to send.
|
||||
*/
|
||||
void NimBLECharacteristic::indicate(const uint8_t* value, size_t length) {
|
||||
notify(value, length, false);
|
||||
} // indicate
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send an indication.
|
||||
* @param[in] value A std::vector<uint8_t> containing the value to send as the notification value.
|
||||
*/
|
||||
void NimBLECharacteristic::indicate(const std::vector<uint8_t>& value) {
|
||||
notify(value.data(), value.size(), false);
|
||||
} // indicate
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send a notification or indication.
|
||||
* @brief Send a notification.\n
|
||||
* A notification is a transmission of up to the first 20 bytes of the characteristic value.\n
|
||||
* A notification will not block; it is a fire and forget.
|
||||
* @param[in] is_notification if true sends a notification, false sends an indication.
|
||||
*/
|
||||
void NimBLECharacteristic::notify(bool is_notification) {
|
||||
notify(m_value.data(), m_value.length(), is_notification);
|
||||
} // notify
|
||||
|
||||
notify(getValue(), is_notification);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send a notification or indication.
|
||||
* @param[in] value A std::vector<uint8_t> containing the value to send as the notification value.
|
||||
* @brief Send a notification.\n
|
||||
* A notification is a transmission of up to the first 20 bytes of the characteristic value.\n
|
||||
* A notification will not block; it is a fire and forget.
|
||||
* @param[in] value An optional value to send as the notification, else the current characteristic value is used.
|
||||
* @param[in] is_notification if true sends a notification, false sends an indication.
|
||||
*/
|
||||
void NimBLECharacteristic::notify(const std::vector<uint8_t>& value, bool is_notification) {
|
||||
notify(value.data(), value.size(), is_notification);
|
||||
} // notify
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send a notification or indication.
|
||||
* @param[in] value A pointer to the data to send.
|
||||
* @param[in] length The length of the data to send.
|
||||
* @param[in] is_notification if true sends a notification, false sends an indication.
|
||||
*/
|
||||
void NimBLECharacteristic::notify(const uint8_t* value, size_t length, bool is_notification) {
|
||||
void NimBLECharacteristic::notify(std::string value, bool is_notification) {
|
||||
size_t length = value.length();
|
||||
NIMBLE_LOGD(LOG_TAG, ">> notify: length: %d", length);
|
||||
|
||||
if(!(m_properties & NIMBLE_PROPERTY::NOTIFY) &&
|
||||
@@ -492,7 +472,7 @@ void NimBLECharacteristic::notify(const uint8_t* value, size_t length, bool is_n
|
||||
// don't create the m_buf until we are sure to send the data or else
|
||||
// we could be allocating a buffer that doesn't get released.
|
||||
// We also must create it in each loop iteration because it is consumed with each host call.
|
||||
os_mbuf *om = ble_hs_mbuf_from_flat(value, length);
|
||||
os_mbuf *om = ble_hs_mbuf_from_flat((uint8_t*)value.data(), length);
|
||||
|
||||
if(!is_notification && (m_properties & NIMBLE_PROPERTY::INDICATE)) {
|
||||
if(!NimBLEDevice::getServer()->setIndicateWait(it.first)) {
|
||||
@@ -536,30 +516,40 @@ NimBLECharacteristicCallbacks* NimBLECharacteristic::getCallbacks() {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the value of the characteristic from a data buffer .
|
||||
* @param [in] data The data buffer to set for the characteristic.
|
||||
* @param [in] length The number of bytes in the data buffer.
|
||||
* @brief Set the value of the characteristic.
|
||||
* @param [in] data The data to set for the characteristic.
|
||||
* @param [in] length The length of the data in bytes.
|
||||
*/
|
||||
void NimBLECharacteristic::setValue(const uint8_t* data, size_t length) {
|
||||
#if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 4
|
||||
char* pHex = NimBLEUtils::buildHexData(nullptr, data, length);
|
||||
NIMBLE_LOGD(LOG_TAG, ">> setValue: length=%d, data=%s, characteristic UUID=%s",
|
||||
length, pHex, getUUID().toString().c_str());
|
||||
NIMBLE_LOGD(LOG_TAG, ">> setValue: length=%d, data=%s, characteristic UUID=%s", length, pHex, getUUID().toString().c_str());
|
||||
free(pHex);
|
||||
#endif
|
||||
|
||||
m_value.setValue(data, length);
|
||||
if (length > BLE_ATT_ATTR_MAX_LEN) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, BLE_ATT_ATTR_MAX_LEN);
|
||||
return;
|
||||
}
|
||||
|
||||
time_t t = time(nullptr);
|
||||
ble_npl_hw_enter_critical();
|
||||
m_value = std::string((char*)data, length);
|
||||
m_timestamp = t;
|
||||
ble_npl_hw_exit_critical(0);
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< setValue");
|
||||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the value of the characteristic from a `std::vector<uint8_t>`.\n
|
||||
* @param [in] vec The std::vector<uint8_t> reference to set the characteristic value from.
|
||||
* @brief Set the value of the characteristic from string data.\n
|
||||
* We set the value of the characteristic from the bytes contained in the string.
|
||||
* @param [in] value the std::string value of the characteristic.
|
||||
*/
|
||||
void NimBLECharacteristic::setValue(const std::vector<uint8_t>& vec) {
|
||||
return setValue((uint8_t*)&vec[0], vec.size());
|
||||
}// setValue
|
||||
void NimBLECharacteristic::setValue(const std::string &value) {
|
||||
setValue((uint8_t*)(value.data()), value.length());
|
||||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -44,7 +44,6 @@ typedef enum {
|
||||
|
||||
#include "NimBLEService.h"
|
||||
#include "NimBLEDescriptor.h"
|
||||
#include "NimBLEAttValue.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -66,13 +65,11 @@ public:
|
||||
uint16_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN,
|
||||
NimBLEService* pService = nullptr);
|
||||
NimBLECharacteristic(const NimBLEUUID &uuid,
|
||||
uint16_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN,
|
||||
NimBLEService* pService = nullptr);
|
||||
|
||||
~NimBLECharacteristic();
|
||||
@@ -80,93 +77,66 @@ public:
|
||||
uint16_t getHandle();
|
||||
NimBLEUUID getUUID();
|
||||
std::string toString();
|
||||
|
||||
void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
|
||||
NimBLECharacteristicCallbacks*
|
||||
getCallbacks();
|
||||
|
||||
void indicate();
|
||||
void indicate(const uint8_t* value, size_t length);
|
||||
void indicate(const std::vector<uint8_t>& value);
|
||||
void notify(bool is_notification = true);
|
||||
void notify(const uint8_t* value, size_t length, bool is_notification = true);
|
||||
void notify(const std::vector<uint8_t>& value, bool is_notification = true);
|
||||
void notify(std::string value, bool is_notification = true);
|
||||
|
||||
size_t getSubscribedCount();
|
||||
|
||||
NimBLEDescriptor* createDescriptor(const char* uuid,
|
||||
uint32_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = 100);
|
||||
NimBLEDescriptor* createDescriptor(const NimBLEUUID &uuid,
|
||||
uint32_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = 100);
|
||||
|
||||
void addDescriptor(NimBLEDescriptor *pDescriptor);
|
||||
NimBLEDescriptor* getDescriptorByUUID(const char* uuid);
|
||||
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &uuid);
|
||||
NimBLEDescriptor* getDescriptorByHandle(uint16_t handle);
|
||||
void removeDescriptor(NimBLEDescriptor *pDescriptor, bool deleteDsc = false);
|
||||
NimBLEService* getService();
|
||||
uint16_t getProperties();
|
||||
NimBLEAttValue getValue(time_t *timestamp = nullptr);
|
||||
|
||||
std::string getValue(time_t *timestamp = nullptr);
|
||||
size_t getDataLength();
|
||||
void setValue(const uint8_t* data, size_t size);
|
||||
void setValue(const std::vector<uint8_t>& vec);
|
||||
void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
|
||||
NimBLEDescriptor* createDescriptor(const char* uuid,
|
||||
uint32_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);;
|
||||
NimBLEDescriptor* createDescriptor(const NimBLEUUID &uuid,
|
||||
uint32_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
|
||||
|
||||
NimBLECharacteristicCallbacks* getCallbacks();
|
||||
|
||||
|
||||
/*********************** Template Functions ************************/
|
||||
|
||||
/**
|
||||
* @brief Template to set the characteristic value to <type\>val.
|
||||
* @param [in] s The value to set.
|
||||
*/
|
||||
template<typename T>
|
||||
void setValue(const T &s) { m_value.setValue<T>(s); }
|
||||
|
||||
/**
|
||||
* @brief Template to convert the characteristic data to <type\>.
|
||||
* @brief A template to convert the characteristic data to <type\>.
|
||||
* @tparam T The type to convert the data to.
|
||||
* @param [in] timestamp (Optional) A pointer to a time_t struct to store the time the value was read.
|
||||
* @param [in] skipSizeCheck (Optional) If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
|
||||
* @param [in] skipSizeCheck If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||
* less than <tt>sizeof(<type\>)</tt>.
|
||||
* @details <b>Use:</b> <tt>getValue<type>(×tamp, skipSizeCheck);</tt>
|
||||
*/
|
||||
template<typename T>
|
||||
T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
|
||||
return m_value.getValue<T>(timestamp, skipSizeCheck);
|
||||
T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
|
||||
std::string value = getValue();
|
||||
if(!skipSizeCheck && value.size() < sizeof(T)) return T();
|
||||
const char *pData = value.data();
|
||||
return *((T *)pData);
|
||||
}
|
||||
|
||||
void setValue(const uint8_t* data, size_t size);
|
||||
void setValue(const std::string &value);
|
||||
/**
|
||||
* @brief Template to send a notification from a class type that has a c_str() and length() method.
|
||||
* @tparam T The a reference to a class containing the data to send.
|
||||
* @param[in] value The <type\>value to set.
|
||||
* @param[in] is_notification if true sends a notification, false sends an indication.
|
||||
* @details Only used if the <type\> has a `c_str()` method.
|
||||
* @brief Convenience template to set the characteristic value to <type\>val.
|
||||
* @param [in] s The value to set.
|
||||
*/
|
||||
template<typename T>
|
||||
#ifdef _DOXYGEN_
|
||||
void
|
||||
#else
|
||||
typename std::enable_if<Has_c_str_len<T>::value, void>::type
|
||||
#endif
|
||||
notify(const T& value, bool is_notification = true) {
|
||||
notify((uint8_t*)value.c_str(), value.length(), is_notification);
|
||||
void setValue(const T &s) {
|
||||
setValue((uint8_t*)&s, sizeof(T));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to send an indication from a class type that has a c_str() and length() method.
|
||||
* @tparam T The a reference to a class containing the data to send.
|
||||
* @param[in] value The <type\>value to set.
|
||||
* @details Only used if the <type\> has a `c_str()` method.
|
||||
*/
|
||||
template<typename T>
|
||||
#ifdef _DOXYGEN_
|
||||
void
|
||||
#else
|
||||
typename std::enable_if<Has_c_str_len<T>::value, void>::type
|
||||
#endif
|
||||
indicate(const T& value) {
|
||||
indicate((uint8_t*)value.c_str(), value.length());
|
||||
}
|
||||
NimBLEService* getService();
|
||||
uint16_t getProperties();
|
||||
|
||||
private:
|
||||
|
||||
@@ -183,8 +153,9 @@ private:
|
||||
uint16_t m_properties;
|
||||
NimBLECharacteristicCallbacks* m_pCallbacks;
|
||||
NimBLEService* m_pService;
|
||||
NimBLEAttValue m_value;
|
||||
std::string m_value;
|
||||
std::vector<NimBLEDescriptor*> m_dscVec;
|
||||
time_t m_timestamp;
|
||||
uint8_t m_removed;
|
||||
|
||||
std::vector<std::pair<uint16_t, uint16_t>> m_subscribedVec;
|
||||
@@ -217,7 +188,7 @@ public:
|
||||
ERROR_INDICATE_FAILURE
|
||||
}Status;
|
||||
|
||||
virtual ~NimBLECharacteristicCallbacks();
|
||||
virtual ~NimBLECharacteristicCallbacks();
|
||||
virtual void onRead(NimBLECharacteristic* pCharacteristic);
|
||||
virtual void onRead(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc);
|
||||
virtual void onWrite(NimBLECharacteristic* pCharacteristic);
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <climits>
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
//#include "nimble/nimble_port.h"
|
||||
#include "nimble/nimble_port.h"
|
||||
#else
|
||||
#include "nimble/porting/nimble/include/nimble/nimble_port.h"
|
||||
#endif
|
||||
@@ -65,11 +65,6 @@ NimBLEClient::NimBLEClient(const NimBLEAddress &peerAddress) : m_peerAddress(pee
|
||||
m_pTaskData = nullptr;
|
||||
m_connEstablished = false;
|
||||
m_lastErr = 0;
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
m_phyMask = BLE_GAP_LE_PHY_1M_MASK |
|
||||
BLE_GAP_LE_PHY_2M_MASK |
|
||||
BLE_GAP_LE_PHY_CODED_MASK;
|
||||
#endif
|
||||
|
||||
m_pConnParams.scan_itvl = 16; // Scan interval in 0.625ms units (NimBLE Default)
|
||||
m_pConnParams.scan_window = 16; // Scan window in 0.625ms units (NimBLE Default)
|
||||
@@ -81,11 +76,7 @@ NimBLEClient::NimBLEClient(const NimBLEAddress &peerAddress) : m_peerAddress(pee
|
||||
m_pConnParams.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; // Maximum length of connection event in 0.625ms units
|
||||
|
||||
memset(&m_dcTimer, 0, sizeof(m_dcTimer));
|
||||
#ifndef MYNEWT
|
||||
ble_npl_callout_init(&m_dcTimer, nimble_port_get_dflt_eventq(),
|
||||
#else
|
||||
ble_npl_callout_init(&m_dcTimer, ble_npl_eventq_dflt_get(),
|
||||
#endif
|
||||
NimBLEClient::dcTimerCb, this);
|
||||
} // NimBLEClient
|
||||
|
||||
@@ -103,7 +94,7 @@ NimBLEClient::~NimBLEClient() {
|
||||
delete m_pClientCallbacks;
|
||||
}
|
||||
|
||||
//ble_npl_callout_deinit(&m_dcTimer);
|
||||
ble_npl_callout_deinit(&m_dcTimer);
|
||||
|
||||
} // ~NimBLEClient
|
||||
|
||||
@@ -219,7 +210,8 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
||||
m_peerAddress = address;
|
||||
}
|
||||
|
||||
ble_task_data_t taskData = {this, nullptr, -1, nullptr};
|
||||
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
|
||||
m_pTaskData = &taskData;
|
||||
int rc = 0;
|
||||
|
||||
@@ -228,22 +220,9 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
||||
* Loop on BLE_HS_EBUSY if the scan hasn't stopped yet.
|
||||
*/
|
||||
do {
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
rc = ble_gap_ext_connect(NimBLEDevice::m_own_addr_type,
|
||||
&peerAddr_t,
|
||||
m_connectTimeout,
|
||||
m_phyMask,
|
||||
&m_pConnParams,
|
||||
&m_pConnParams,
|
||||
&m_pConnParams,
|
||||
NimBLEClient::handleGapEvent,
|
||||
this);
|
||||
|
||||
#else
|
||||
rc = ble_gap_connect(NimBLEDevice::m_own_addr_type, &peerAddr_t,
|
||||
m_connectTimeout, &m_pConnParams,
|
||||
NimBLEClient::handleGapEvent, this);
|
||||
#endif
|
||||
switch (rc) {
|
||||
case 0:
|
||||
break;
|
||||
@@ -285,7 +264,12 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!NimBLEDevice::taskWait(m_pTaskData, m_connectTimeout + 1000)) {
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
// Wait for the connect timeout time +1 second for the connection to complete
|
||||
if(ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(m_connectTimeout + 1000)) == pdFALSE) {
|
||||
m_pTaskData = nullptr;
|
||||
// If a connection was made but no response from MTU exchange; disconnect
|
||||
if(isConnected()) {
|
||||
@@ -301,7 +285,6 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
||||
return false;
|
||||
|
||||
} else if(taskData.rc != 0){
|
||||
m_pTaskData = nullptr;
|
||||
m_lastErr = taskData.rc;
|
||||
NIMBLE_LOGE(LOG_TAG, "Connection failed; status=%d %s",
|
||||
taskData.rc,
|
||||
@@ -313,7 +296,6 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
m_pTaskData = nullptr;
|
||||
NIMBLE_LOGI(LOG_TAG, "Connection established");
|
||||
}
|
||||
|
||||
@@ -336,12 +318,12 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
||||
* @return True on success.
|
||||
*/
|
||||
bool NimBLEClient::secureConnection() {
|
||||
ble_task_data_t taskData = {this, nullptr, -1, nullptr};
|
||||
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
|
||||
|
||||
int retryCount = 1;
|
||||
|
||||
do {
|
||||
taskData.rc = -1;
|
||||
m_pTaskData = &taskData;
|
||||
|
||||
int rc = NimBLEDevice::startSecurity(m_conn_id);
|
||||
@@ -350,13 +332,13 @@ bool NimBLEClient::secureConnection() {
|
||||
m_pTaskData = nullptr;
|
||||
return false;
|
||||
}
|
||||
\
|
||||
if (!NimBLEDevice::taskWait(m_pTaskData, 10 * 1000)) {
|
||||
break;
|
||||
}
|
||||
} while (taskData.rc == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING) && retryCount--);
|
||||
|
||||
m_pTaskData = nullptr;
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
} while (taskData.rc == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING) && retryCount--);
|
||||
|
||||
if(taskData.rc != 0){
|
||||
m_lastErr = taskData.rc;
|
||||
@@ -415,21 +397,6 @@ int NimBLEClient::disconnect(uint8_t reason) {
|
||||
} // disconnect
|
||||
|
||||
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
/**
|
||||
* @brief Set the PHY types to use when connecting to a server.
|
||||
* @param [in] mask A bitmask indicating what PHYS to connect with.\n
|
||||
* The available bits are:
|
||||
* * 0x01 BLE_GAP_LE_PHY_1M_MASK
|
||||
* * 0x02 BLE_GAP_LE_PHY_2M_MASK
|
||||
* * 0x04 BLE_GAP_LE_PHY_CODED_MASK
|
||||
*/
|
||||
void NimBLEClient::setConnectPhy(uint8_t mask) {
|
||||
m_phyMask = mask;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the connection paramaters to use when connecting to a server.
|
||||
* @param [in] minInterval The minimum connection interval in 1.25ms units.
|
||||
@@ -734,7 +701,8 @@ bool NimBLEClient::retrieveServices(const NimBLEUUID *uuid_filter) {
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
ble_task_data_t taskData = {this, nullptr, -1, nullptr};
|
||||
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
|
||||
|
||||
if(uuid_filter == nullptr) {
|
||||
rc = ble_gattc_disc_all_svcs(m_conn_id, NimBLEClient::serviceDiscoveredCB, &taskData);
|
||||
@@ -749,12 +717,13 @@ bool NimBLEClient::retrieveServices(const NimBLEUUID *uuid_filter) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!NimBLEDevice::taskWait(&taskData, 10 * 1000)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Retrieve services timeout");
|
||||
m_lastErr = taskData.rc;
|
||||
return false;
|
||||
}
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
|
||||
// wait until we have all the services
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
m_lastErr = taskData.rc;
|
||||
|
||||
if(taskData.rc == 0){
|
||||
@@ -789,21 +758,26 @@ int NimBLEClient::serviceDiscoveredCB(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rc = error->status;
|
||||
|
||||
if (rc == 0) {
|
||||
if(error->status == 0) {
|
||||
// Found a service - add it to the vector
|
||||
NimBLERemoteService* pRemoteService = new NimBLERemoteService(client, service);
|
||||
client->m_servicesVector.push_back(pRemoteService);
|
||||
} else if (rc != BLE_HS_EDONE) {
|
||||
NIMBLE_LOGE(LOG_TAG, "serviceDiscoveredCB() rc=%d %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
return 0;
|
||||
}
|
||||
|
||||
NimBLEDevice::taskComplete(pTaskData, rc == BLE_HS_EDONE ? 0 : rc);
|
||||
if(error->status == BLE_HS_EDONE) {
|
||||
pTaskData->rc = 0;
|
||||
} else {
|
||||
NIMBLE_LOGE(LOG_TAG, "characteristicDiscCB() rc=%d %s",
|
||||
error->status,
|
||||
NimBLEUtils::returnCodeToString(error->status));
|
||||
pTaskData->rc = error->status;
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG,"<< Service Discovered");
|
||||
return rc;
|
||||
xTaskNotifyGive(pTaskData->task);
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG,"<< << Service Discovered");
|
||||
return error->status;
|
||||
}
|
||||
|
||||
|
||||
@@ -813,11 +787,11 @@ int NimBLEClient::serviceDiscoveredCB(
|
||||
* @param [in] characteristicUUID The characteristic whose value we wish to read.
|
||||
* @returns characteristic value or an empty string if not found
|
||||
*/
|
||||
NimBLEAttValue NimBLEClient::getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID) {
|
||||
std::string NimBLEClient::getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> getValue: serviceUUID: %s, characteristicUUID: %s",
|
||||
serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||
|
||||
NimBLEAttValue ret;
|
||||
std::string ret = "";
|
||||
NimBLERemoteService* pService = getService(serviceUUID);
|
||||
|
||||
if(pService != nullptr) {
|
||||
@@ -827,7 +801,7 @@ NimBLEAttValue NimBLEClient::getValue(const NimBLEUUID &serviceUUID, const NimBL
|
||||
}
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< getValue");
|
||||
NIMBLE_LOGD(LOG_TAG, "<<getValue");
|
||||
return ret;
|
||||
} // getValue
|
||||
|
||||
@@ -841,7 +815,7 @@ NimBLEAttValue NimBLEClient::getValue(const NimBLEUUID &serviceUUID, const NimBL
|
||||
* @returns true if successful otherwise false
|
||||
*/
|
||||
bool NimBLEClient::setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID,
|
||||
const NimBLEAttValue &value, bool response)
|
||||
const std::string &value, bool response)
|
||||
{
|
||||
NIMBLE_LOGD(LOG_TAG, ">> setValue: serviceUUID: %s, characteristicUUID: %s",
|
||||
serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||
@@ -902,7 +876,7 @@ uint16_t NimBLEClient::getMTU() {
|
||||
* @param [in] arg A pointer to the client instance that registered for this callback.
|
||||
*/
|
||||
/*STATIC*/
|
||||
int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||
int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||
NimBLEClient* client = (NimBLEClient*)arg;
|
||||
int rc;
|
||||
|
||||
@@ -1021,7 +995,11 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||
(*characteristic)->toString().c_str());
|
||||
|
||||
uint32_t data_len = OS_MBUF_PKTLEN(event->notify_rx.om);
|
||||
(*characteristic)->m_value.setValue(event->notify_rx.om->om_data, data_len);
|
||||
time_t t = time(nullptr);
|
||||
ble_npl_hw_enter_critical();
|
||||
(*characteristic)->m_value = std::string((char *)event->notify_rx.om->om_data, data_len);
|
||||
(*characteristic)->m_timestamp = t;
|
||||
ble_npl_hw_exit_critical(0);
|
||||
|
||||
if ((*characteristic)->m_notifyCallback != nullptr) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s",
|
||||
@@ -1176,7 +1154,10 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||
} // Switch
|
||||
|
||||
if(client->m_pTaskData != nullptr) {
|
||||
NimBLEDevice::taskComplete(client->m_pTaskData, rc);
|
||||
client->m_pTaskData->rc = rc;
|
||||
if(client->m_pTaskData->task) {
|
||||
xTaskNotifyGive(client->m_pTaskData->task);
|
||||
}
|
||||
client->m_pTaskData = nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "NimBLEUUID.h"
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLEConnInfo.h"
|
||||
#include "NimBLEAttValue.h"
|
||||
#include "NimBLEAdvertisedDevice.h"
|
||||
#include "NimBLERemoteService.h"
|
||||
|
||||
@@ -52,9 +51,9 @@ public:
|
||||
NimBLERemoteService* getService(const NimBLEUUID &uuid);
|
||||
void deleteServices();
|
||||
size_t deleteService(const NimBLEUUID &uuid);
|
||||
NimBLEAttValue getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID);
|
||||
std::string getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID);
|
||||
bool setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID,
|
||||
const NimBLEAttValue &value, bool response = false);
|
||||
const std::string &value, bool response = false);
|
||||
NimBLERemoteCharacteristic* getCharacteristic(const uint16_t handle);
|
||||
bool isConnected();
|
||||
void setClientCallbacks(NimBLEClientCallbacks *pClientCallbacks,
|
||||
@@ -73,9 +72,6 @@ public:
|
||||
void discoverAttributes();
|
||||
NimBLEConnInfo getConnInfo();
|
||||
int getLastError();
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
void setConnectPhy(uint8_t mask);
|
||||
#endif
|
||||
|
||||
private:
|
||||
NimBLEClient(const NimBLEAddress &peerAddress);
|
||||
@@ -101,9 +97,6 @@ private:
|
||||
NimBLEClientCallbacks* m_pClientCallbacks;
|
||||
ble_task_data_t* m_pTaskData;
|
||||
ble_npl_callout m_dcTimer;
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
uint8_t m_phyMask;
|
||||
#endif
|
||||
|
||||
std::vector<NimBLERemoteService*> m_servicesVector;
|
||||
|
||||
|
||||
@@ -28,32 +28,27 @@ static NimBLEDescriptorCallbacks defaultCallbacks;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct a descriptor
|
||||
* @param [in] uuid - UUID (const char*) for the descriptor.
|
||||
* @param [in] properties - Properties for the descriptor.
|
||||
* @param [in] max_len - The maximum length in bytes that the descriptor value can hold. (Default: 512 bytes for esp32, 20 for all others).
|
||||
* @param [in] pCharacteristic - pointer to the characteristic instance this descriptor belongs to.
|
||||
* @brief NimBLEDescriptor constructor.
|
||||
*/
|
||||
NimBLEDescriptor::NimBLEDescriptor(const char* uuid, uint16_t properties, uint16_t max_len,
|
||||
NimBLECharacteristic* pCharacteristic)
|
||||
: NimBLEDescriptor(NimBLEUUID(uuid), properties, max_len, pCharacteristic) {
|
||||
NimBLECharacteristic* pCharacteristic)
|
||||
: NimBLEDescriptor(NimBLEUUID(uuid), max_len, properties, pCharacteristic) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct a descriptor
|
||||
* @param [in] uuid - UUID (const char*) for the descriptor.
|
||||
* @param [in] properties - Properties for the descriptor.
|
||||
* @param [in] max_len - The maximum length in bytes that the descriptor value can hold. (Default: 512 bytes for esp32, 20 for all others).
|
||||
* @param [in] pCharacteristic - pointer to the characteristic instance this descriptor belongs to.
|
||||
* @brief NimBLEDescriptor constructor.
|
||||
*/
|
||||
NimBLEDescriptor::NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties, uint16_t max_len,
|
||||
NimBLECharacteristic* pCharacteristic)
|
||||
: m_value(std::min(CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH , (int)max_len), max_len) {
|
||||
{
|
||||
m_uuid = uuid;
|
||||
m_value.attr_len = 0; // Initial length is 0.
|
||||
m_value.attr_max_len = max_len; // Maximum length of the data.
|
||||
m_handle = NULL_HANDLE; // Handle is initially unknown.
|
||||
m_pCharacteristic = pCharacteristic;
|
||||
m_pCallbacks = &defaultCallbacks; // No initial callback.
|
||||
m_value.attr_value = (uint8_t*) calloc(max_len,1); // Allocate storage for the value.
|
||||
m_properties = 0;
|
||||
m_removed = 0;
|
||||
|
||||
@@ -89,6 +84,7 @@ NimBLEDescriptor::NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties, uint16_
|
||||
* @brief NimBLEDescriptor destructor.
|
||||
*/
|
||||
NimBLEDescriptor::~NimBLEDescriptor() {
|
||||
free(m_value.attr_value); // Release the storage we created in the constructor.
|
||||
} // ~NimBLEDescriptor
|
||||
|
||||
/**
|
||||
@@ -105,7 +101,7 @@ uint16_t NimBLEDescriptor::getHandle() {
|
||||
* @return The length (in bytes) of the value of this descriptor.
|
||||
*/
|
||||
size_t NimBLEDescriptor::getLength() {
|
||||
return m_value.size();
|
||||
return m_value.attr_len;
|
||||
} // getLength
|
||||
|
||||
|
||||
@@ -119,14 +115,10 @@ NimBLEUUID NimBLEDescriptor::getUUID() {
|
||||
|
||||
/**
|
||||
* @brief Get the value of this descriptor.
|
||||
* @return The NimBLEAttValue of this descriptor.
|
||||
* @return A pointer to the value of this descriptor.
|
||||
*/
|
||||
NimBLEAttValue NimBLEDescriptor::getValue(time_t *timestamp) {
|
||||
if (timestamp != nullptr) {
|
||||
m_value.getValue(timestamp);
|
||||
}
|
||||
|
||||
return m_value;
|
||||
uint8_t* NimBLEDescriptor::getValue() {
|
||||
return m_value.attr_value;
|
||||
} // getValue
|
||||
|
||||
|
||||
@@ -135,7 +127,7 @@ NimBLEAttValue NimBLEDescriptor::getValue(time_t *timestamp) {
|
||||
* @return A std::string instance containing a copy of the descriptor's value.
|
||||
*/
|
||||
std::string NimBLEDescriptor::getStringValue() {
|
||||
return std::string(m_value);
|
||||
return std::string((char *) m_value.attr_value, m_value.attr_len);
|
||||
}
|
||||
|
||||
|
||||
@@ -171,25 +163,23 @@ int NimBLEDescriptor::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||
}
|
||||
|
||||
ble_npl_hw_enter_critical();
|
||||
rc = os_mbuf_append(ctxt->om, pDescriptor->m_value.data(), pDescriptor->m_value.size());
|
||||
rc = os_mbuf_append(ctxt->om, pDescriptor->getValue(), pDescriptor->getLength());
|
||||
ble_npl_hw_exit_critical(0);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
case BLE_GATT_ACCESS_OP_WRITE_DSC: {
|
||||
uint16_t att_max_len = pDescriptor->m_value.max_size();
|
||||
|
||||
if (ctxt->om->om_len > att_max_len) {
|
||||
if (ctxt->om->om_len > pDescriptor->m_value.attr_max_len) {
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
|
||||
uint8_t buf[att_max_len];
|
||||
uint8_t buf[pDescriptor->m_value.attr_max_len];
|
||||
size_t len = ctxt->om->om_len;
|
||||
memcpy(buf, ctxt->om->om_data,len);
|
||||
os_mbuf *next;
|
||||
next = SLIST_NEXT(ctxt->om, om_next);
|
||||
while(next != NULL){
|
||||
if((len + next->om_len) > att_max_len) {
|
||||
if((len + next->om_len) > pDescriptor->m_value.attr_max_len) {
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
memcpy(&buf[len], next->om_data, next->om_len);
|
||||
@@ -241,19 +231,27 @@ void NimBLEDescriptor::setHandle(uint16_t handle) {
|
||||
* @param [in] length The length of the data in bytes.
|
||||
*/
|
||||
void NimBLEDescriptor::setValue(const uint8_t* data, size_t length) {
|
||||
m_value.setValue(data, length);
|
||||
if (length > m_value.attr_max_len) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, m_value.attr_max_len);
|
||||
return;
|
||||
}
|
||||
|
||||
ble_npl_hw_enter_critical();
|
||||
m_value.attr_len = length;
|
||||
memcpy(m_value.attr_value, data, length);
|
||||
ble_npl_hw_exit_critical(0);
|
||||
|
||||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the value of the descriptor from a `std::vector<uint8_t>`.\n
|
||||
* @param [in] vec The std::vector<uint8_t> reference to set the descriptor value from.
|
||||
* @brief Set the value of the descriptor.
|
||||
* @param [in] value The value of the descriptor in string form.
|
||||
*/
|
||||
void NimBLEDescriptor::setValue(const std::vector<uint8_t>& vec) {
|
||||
return setValue((uint8_t*)&vec[0], vec.size());
|
||||
void NimBLEDescriptor::setValue(const std::string &value) {
|
||||
setValue((uint8_t*) value.data(), value.length());
|
||||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the characteristic this descriptor belongs to.
|
||||
* @param [in] pChar A pointer to the characteristic this descriptior belongs to.
|
||||
|
||||
@@ -20,10 +20,17 @@
|
||||
|
||||
#include "NimBLECharacteristic.h"
|
||||
#include "NimBLEUUID.h"
|
||||
#include "NimBLEAttValue.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t attr_max_len; /*!< attribute max value length */
|
||||
uint16_t attr_len; /*!< attribute current value length */
|
||||
uint8_t *attr_value; /*!< the pointer to attribute value */
|
||||
} attr_value_t;
|
||||
|
||||
class NimBLEService;
|
||||
class NimBLECharacteristic;
|
||||
class NimBLEDescriptorCallbacks;
|
||||
@@ -47,36 +54,24 @@ public:
|
||||
uint16_t getHandle();
|
||||
NimBLEUUID getUUID();
|
||||
std::string toString();
|
||||
|
||||
void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks);
|
||||
NimBLECharacteristic* getCharacteristic();
|
||||
|
||||
size_t getLength();
|
||||
NimBLEAttValue getValue(time_t *timestamp = nullptr);
|
||||
uint8_t* getValue();
|
||||
std::string getStringValue();
|
||||
|
||||
void setValue(const uint8_t* data, size_t size);
|
||||
void setValue(const std::vector<uint8_t>& vec);
|
||||
|
||||
/*********************** Template Functions ************************/
|
||||
void setValue(const std::string &value);
|
||||
NimBLECharacteristic* getCharacteristic();
|
||||
|
||||
/**
|
||||
* @brief Template to set the characteristic value to <type\>val.
|
||||
* @brief Convenience template to set the descriptor value to <type\>val.
|
||||
* @param [in] s The value to set.
|
||||
*/
|
||||
template<typename T>
|
||||
void setValue(const T &s) { m_value.setValue<T>(s); }
|
||||
|
||||
/**
|
||||
* @brief Template to convert the descriptor data to <type\>.
|
||||
* @tparam T The type to convert the data to.
|
||||
* @param [in] timestamp (Optional) A pointer to a time_t struct to store the time the value was read.
|
||||
* @param [in] skipSizeCheck (Optional) If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @details <b>Use:</b> <tt>getValue<type>(×tamp, skipSizeCheck);</tt>
|
||||
*/
|
||||
template<typename T>
|
||||
T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
|
||||
return m_value.getValue<T>(timestamp, skipSizeCheck);
|
||||
void setValue(const T &s) {
|
||||
setValue((uint8_t*)&s, sizeof(T));
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -94,7 +89,7 @@ private:
|
||||
NimBLEDescriptorCallbacks* m_pCallbacks;
|
||||
NimBLECharacteristic* m_pCharacteristic;
|
||||
uint8_t m_properties;
|
||||
NimBLEAttValue m_value;
|
||||
attr_value_t m_value;
|
||||
uint8_t m_removed;
|
||||
}; // NimBLEDescriptor
|
||||
|
||||
|
||||
@@ -35,15 +35,7 @@
|
||||
# include "nimble/esp_port/esp-hci/include/esp_nimble_hci.h"
|
||||
# endif
|
||||
#else
|
||||
# include "controller/ble_phy.h"
|
||||
# include "host/ble_hs.h"
|
||||
# include "host/util/util.h"
|
||||
# include "services/gap/ble_svc_gap.h"
|
||||
# include "services/gatt/ble_svc_gatt.h"
|
||||
//#include "porting/nimble/include/nimble/nimble_port.h"
|
||||
#include "os/os.h"
|
||||
|
||||
|
||||
# include "nimble/nimble/controller/include/controller/ble_phy.h"
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_NIMBLE_CPP_IDF
|
||||
@@ -77,11 +69,7 @@ NimBLEServer* NimBLEDevice::m_pServer = nullptr;
|
||||
uint32_t NimBLEDevice::m_passkey = 123456;
|
||||
bool NimBLEDevice::m_synced = false;
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
NimBLEExtAdvertising* NimBLEDevice::m_bleAdvertising = nullptr;
|
||||
# else
|
||||
NimBLEAdvertising* NimBLEDevice::m_bleAdvertising = nullptr;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
gap_event_handler NimBLEDevice::m_customGapHandler = nullptr;
|
||||
@@ -126,45 +114,6 @@ uint8_t NimBLEDevice::m_scanFilterMode = CONFIG_BTDM_SCAN_DU
|
||||
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
/**
|
||||
* @brief Get the instance of the advertising object.
|
||||
* @return A pointer to the advertising object.
|
||||
*/
|
||||
NimBLEExtAdvertising* NimBLEDevice::getAdvertising() {
|
||||
if(m_bleAdvertising == nullptr) {
|
||||
m_bleAdvertising = new NimBLEExtAdvertising();
|
||||
}
|
||||
return m_bleAdvertising;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convenience function to begin advertising.
|
||||
* @param [in] inst_id The extended advertisement instance ID to start.
|
||||
* @param [in] duration How long to advertise for in milliseconds, 0 = forever (default).
|
||||
* @param [in] max_events Maximum number of advertisement events to send, 0 = no limit (default).
|
||||
* @return True if advertising started successfully.
|
||||
*/
|
||||
bool NimBLEDevice::startAdvertising(uint8_t inst_id,
|
||||
int duration,
|
||||
int max_events) {
|
||||
return getAdvertising()->start(inst_id, duration, max_events);
|
||||
} // startAdvertising
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convenience function to stop advertising a data set.
|
||||
* @param [in] inst_id The extended advertisement instance ID to stop advertising.
|
||||
* @return True if advertising stopped successfully.
|
||||
*/
|
||||
bool NimBLEDevice::stopAdvertising(uint8_t inst_id) {
|
||||
return getAdvertising()->stop(inst_id);
|
||||
} // stopAdvertising
|
||||
|
||||
# endif
|
||||
|
||||
# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
|
||||
/**
|
||||
* @brief Get the instance of the advertising object.
|
||||
* @return A pointer to the advertising object.
|
||||
@@ -179,19 +128,17 @@ NimBLEAdvertising* NimBLEDevice::getAdvertising() {
|
||||
|
||||
/**
|
||||
* @brief Convenience function to begin advertising.
|
||||
* @return True if advertising started successfully.
|
||||
*/
|
||||
bool NimBLEDevice::startAdvertising() {
|
||||
return getAdvertising()->start();
|
||||
void NimBLEDevice::startAdvertising() {
|
||||
getAdvertising()->start();
|
||||
} // startAdvertising
|
||||
# endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convenience function to stop all advertising.
|
||||
* @return True if advertising stopped successfully.
|
||||
* @brief Convenience function to stop advertising.
|
||||
*/
|
||||
bool NimBLEDevice::stopAdvertising() {
|
||||
return getAdvertising()->stop();
|
||||
void NimBLEDevice::stopAdvertising() {
|
||||
getAdvertising()->stop();
|
||||
} // stopAdvertising
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
|
||||
@@ -257,7 +204,7 @@ bool NimBLEDevice::deleteClient(NimBLEClient* pClient) {
|
||||
}
|
||||
|
||||
while(pClient->isConnected()) {
|
||||
os_time_delay(1);
|
||||
taskYIELD();
|
||||
}
|
||||
// Since we set the flag to false the app will not get a callback
|
||||
// in the disconnect event so we call it here for good measure.
|
||||
@@ -269,7 +216,7 @@ bool NimBLEDevice::deleteClient(NimBLEClient* pClient) {
|
||||
return false;
|
||||
}
|
||||
while(pClient->m_pTaskData != nullptr) {
|
||||
os_time_delay(1);
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,13 +379,12 @@ int NimBLEDevice::getPower(esp_ble_power_type_t powerType) {
|
||||
#else
|
||||
|
||||
void NimBLEDevice::setPower(int dbm) {
|
||||
//ble_phy_txpwr_set(dbm);
|
||||
ble_phy_txpwr_set(dbm);
|
||||
}
|
||||
|
||||
|
||||
int NimBLEDevice::getPower() {
|
||||
// return ble_phy_txpwr_get();
|
||||
return 0;
|
||||
return ble_phy_txpwr_get();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -813,8 +759,7 @@ void NimBLEDevice::onSync(void)
|
||||
|
||||
// Yield for houskeeping before returning to operations.
|
||||
// Occasionally triggers exception without.
|
||||
//taskYIELD();
|
||||
os_time_delay(1);
|
||||
taskYIELD();
|
||||
|
||||
m_synced = true;
|
||||
|
||||
@@ -833,6 +778,7 @@ void NimBLEDevice::onSync(void)
|
||||
}
|
||||
} // onSync
|
||||
|
||||
|
||||
/**
|
||||
* @brief The main host task.
|
||||
*/
|
||||
@@ -842,21 +788,12 @@ void NimBLEDevice::host_task(void *param)
|
||||
NIMBLE_LOGI(LOG_TAG, "BLE Host Task Started");
|
||||
|
||||
/* This function will return only when nimble_port_stop() is executed */
|
||||
#ifndef MYNEWT
|
||||
nimble_port_run();
|
||||
|
||||
nimble_port_freertos_deinit();
|
||||
#else
|
||||
while (1) {
|
||||
os_eventq_run(os_eventq_dflt_get());
|
||||
}
|
||||
#endif
|
||||
} // host_task
|
||||
|
||||
|
||||
static struct os_task ble_nimble_task;
|
||||
static os_stack_t ble_nimble_stack[1024];
|
||||
|
||||
/**
|
||||
* @brief Initialize the %BLE environment.
|
||||
* @param [in] deviceName The device name of the device.
|
||||
@@ -898,10 +835,7 @@ void NimBLEDevice::init(const std::string &deviceName) {
|
||||
ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BLE));
|
||||
ESP_ERROR_CHECK(esp_nimble_hci_init());
|
||||
#endif
|
||||
|
||||
#ifndef MYNEWT
|
||||
nimble_port_init();
|
||||
#endif
|
||||
|
||||
// Setup callbacks for host events
|
||||
ble_hs_cfg.reset_cb = NimBLEDevice::onReset;
|
||||
@@ -920,18 +854,15 @@ void NimBLEDevice::init(const std::string &deviceName) {
|
||||
// Set the device name.
|
||||
rc = ble_svc_gap_device_name_set(deviceName.c_str());
|
||||
assert(rc == 0);
|
||||
#ifndef MYNEWT
|
||||
|
||||
ble_store_config_init();
|
||||
|
||||
nimble_port_freertos_init(NimBLEDevice::host_task);
|
||||
#else
|
||||
os_task_init(&ble_nimble_task, "ble_nimble_task", NimBLEDevice::host_task, NULL, 8,
|
||||
OS_WAIT_FOREVER, ble_nimble_stack, 1024);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Wait for host and controller to sync before returning and accepting new tasks
|
||||
while(!m_synced){
|
||||
os_time_delay(1);
|
||||
taskYIELD();
|
||||
}
|
||||
|
||||
initialized = true; // Set the initialization flag to ensure we are only initialized once.
|
||||
@@ -945,14 +876,9 @@ void NimBLEDevice::init(const std::string &deviceName) {
|
||||
*/
|
||||
/* STATIC */
|
||||
void NimBLEDevice::deinit(bool clearAll) {
|
||||
#ifndef MYNEWT
|
||||
int ret = nimble_port_stop();
|
||||
if (ret == 0) {
|
||||
nimble_port_deinit();
|
||||
#else
|
||||
int ret = ble_hs_shutdown(0);
|
||||
if (ret == 0) {
|
||||
#endif
|
||||
#ifdef ESP_PLATFORM
|
||||
ret = esp_nimble_hci_and_controller_deinit();
|
||||
if (ret != ESP_OK) {
|
||||
|
||||
@@ -23,11 +23,7 @@
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
# include "NimBLEExtAdvertising.h"
|
||||
# else
|
||||
# include "NimBLEAdvertising.h"
|
||||
# endif
|
||||
#include "NimBLEAdvertising.h"
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
@@ -143,18 +139,9 @@ public:
|
||||
static void removeIgnored(const NimBLEAddress &address);
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
static NimBLEExtAdvertising* getAdvertising();
|
||||
static bool startAdvertising(uint8_t inst_id,
|
||||
int duration = 0,
|
||||
int max_events = 0);
|
||||
static bool stopAdvertising(uint8_t inst_id);
|
||||
static bool stopAdvertising();
|
||||
# else
|
||||
static NimBLEAdvertising* getAdvertising();
|
||||
static bool startAdvertising();
|
||||
static bool stopAdvertising();
|
||||
# endif
|
||||
static NimBLEAdvertising* getAdvertising();
|
||||
static void startAdvertising();
|
||||
static void stopAdvertising();
|
||||
#endif
|
||||
|
||||
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
@@ -175,31 +162,6 @@ public:
|
||||
static NimBLEAddress getBondedAddress(int index);
|
||||
#endif
|
||||
|
||||
static bool taskWait(ble_task_data_t* td, uint32_t waitms ) {
|
||||
#if 0 //defined INC_FREERTOS_H
|
||||
td->task = xTaskGetCurrentTaskHandle();
|
||||
# ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(td->task, ULONG_MAX);
|
||||
# endif
|
||||
// Wait for the connect timeout time +1 second for the connection to complete
|
||||
return ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(waitms));
|
||||
#else
|
||||
ble_npl_time_t ticks = ble_npl_time_ms_to_ticks32(waitms);
|
||||
while(td->rc < 0 && --ticks){
|
||||
ble_npl_time_delay(1);
|
||||
}
|
||||
return (ticks > 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void taskComplete(ble_task_data_t* td, int rc) {
|
||||
td->rc = rc;
|
||||
#if 0 //defined INC_FREERTOS_H
|
||||
xTaskNotifyGive(td->task);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
friend class NimBLEClient;
|
||||
@@ -216,10 +178,6 @@ private:
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
friend class NimBLEAdvertising;
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
friend class NimBLEExtAdvertising;
|
||||
friend class NimBLEExtAdvertisement;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static void onReset(int reason);
|
||||
@@ -236,11 +194,7 @@ private:
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
static NimBLEExtAdvertising* m_bleAdvertising;
|
||||
# else
|
||||
static NimBLEAdvertising* m_bleAdvertising;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
@@ -1,870 +0,0 @@
|
||||
/*
|
||||
* NimBLEExtAdvertising.cpp
|
||||
*
|
||||
* Created: on February 6, 2022
|
||||
* Author H2zero
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && \
|
||||
defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) && \
|
||||
CONFIG_BT_NIMBLE_EXT_ADV
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#else
|
||||
#include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h"
|
||||
#endif
|
||||
#include "NimBLEExtAdvertising.h"
|
||||
#include "NimBLEDevice.h"
|
||||
#include "NimBLEServer.h"
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
static NimBLEExtAdvertisingCallbacks defaultCallbacks;
|
||||
static const char* LOG_TAG = "NimBLEExtAdvertising";
|
||||
|
||||
|
||||
/**
|
||||
* @brief Destructor: deletes callback instances if requested.
|
||||
*/
|
||||
NimBLEExtAdvertising::~NimBLEExtAdvertising() {
|
||||
if(m_deleteCallbacks && m_pCallbacks != &defaultCallbacks) {
|
||||
delete m_pCallbacks;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Register the extended advertisement data.
|
||||
* @param [in] inst_id The extended advertisement instance ID to assign to this data.
|
||||
* @param [in] adv The extended advertisement instance with the data to set.
|
||||
* @return True if advertising started successfully.
|
||||
*/
|
||||
bool NimBLEExtAdvertising::setInstanceData(uint8_t inst_id, NimBLEExtAdvertisement& adv) {
|
||||
adv.m_params.sid = inst_id;
|
||||
|
||||
// Legacy advertising as connectable requires the scannable flag also.
|
||||
if (adv.m_params.legacy_pdu && adv.m_params.connectable) {
|
||||
adv.m_params.scannable = true;
|
||||
}
|
||||
|
||||
// If connectable or not scannable disable the callback for scan response requests
|
||||
if (adv.m_params.connectable || !adv.m_params.scannable) {
|
||||
adv.m_params.scan_req_notif = false;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
NimBLEServer* pServer = NimBLEDevice::getServer();
|
||||
if (pServer != nullptr) {
|
||||
if (!pServer->m_gattsStarted) {
|
||||
pServer->start();
|
||||
}
|
||||
}
|
||||
|
||||
int rc = ble_gap_ext_adv_configure(inst_id,
|
||||
&adv.m_params,
|
||||
NULL,
|
||||
(pServer != nullptr) ? NimBLEServer::handleGapEvent :
|
||||
NimBLEExtAdvertising::handleGapEvent,
|
||||
NULL);
|
||||
#else
|
||||
int rc = ble_gap_ext_adv_configure(inst_id,
|
||||
&data.m_params,
|
||||
NULL,
|
||||
NimBLEExtAdvertising::handleGapEvent,
|
||||
NULL);
|
||||
#endif
|
||||
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Advertising config error: rc = %d", rc);
|
||||
} else {
|
||||
os_mbuf *buf;
|
||||
buf = os_msys_get_pkthdr(adv.m_payload.size(), 0);
|
||||
if (!buf) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Data buffer allocation failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = os_mbuf_append(buf, &adv.m_payload[0], adv.m_payload.size());
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Unable to copy data: rc = %d", rc);
|
||||
return false;
|
||||
} else {
|
||||
if (adv.m_params.scannable && !adv.m_params.legacy_pdu) {
|
||||
rc = ble_gap_ext_adv_rsp_set_data(inst_id, buf);
|
||||
} else {
|
||||
rc = ble_gap_ext_adv_set_data(inst_id, buf);
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Invalid advertisement data: rc = %d", rc);
|
||||
} else {
|
||||
if (adv.m_advAddress != NimBLEAddress("")) {
|
||||
ble_addr_t addr;
|
||||
memcpy(&addr.val, adv.m_advAddress.getNative(), 6);
|
||||
// Custom advertising address must be random.
|
||||
addr.type = BLE_OWN_ADDR_RANDOM;
|
||||
rc = ble_gap_ext_adv_set_addr(inst_id, &addr);
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Error setting advertisement address: rc = %d", rc);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (rc == 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the scan response data for a legacy advertisement.
|
||||
* @param [in] inst_id The extended advertisement instance ID to assign to this data.
|
||||
* @param [in] lsr A reference to a NimBLEExtAdvertisement that contains the data.
|
||||
*/
|
||||
bool NimBLEExtAdvertising::setScanResponseData(uint8_t inst_id, NimBLEExtAdvertisement & lsr) {
|
||||
os_mbuf *buf = os_msys_get_pkthdr(lsr.m_payload.size(), 0);
|
||||
if (!buf) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Data buffer allocation failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
int rc = os_mbuf_append(buf, &lsr.m_payload[0], lsr.m_payload.size());
|
||||
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Unable to copy scan data: rc = %d", rc);
|
||||
return false;
|
||||
} else {
|
||||
rc = ble_gap_ext_adv_rsp_set_data(inst_id, buf);
|
||||
}
|
||||
return (rc == 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Start extended advertising.
|
||||
* @param [in] inst_id The extended advertisement instance ID to start.
|
||||
* @param [in] duration How long to advertise for in milliseconds, 0 = forever (default).
|
||||
* @param [in] max_events Maximum number of advertisement events to send, 0 = no limit (default).
|
||||
* @return True if advertising started successfully.
|
||||
*/
|
||||
bool NimBLEExtAdvertising::start(uint8_t inst_id, int duration, int max_events) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> Extended Advertising start");
|
||||
|
||||
// If Host is not synced we cannot start advertising.
|
||||
if(!NimBLEDevice::m_synced) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Host reset, wait for sync.");
|
||||
return false;
|
||||
}
|
||||
|
||||
int rc = ble_gap_ext_adv_start(inst_id, duration / 10, max_events);
|
||||
|
||||
switch (rc) {
|
||||
case 0:
|
||||
m_advStatus[inst_id] = true;
|
||||
break;
|
||||
|
||||
case BLE_HS_EINVAL:
|
||||
NIMBLE_LOGE(LOG_TAG, "Unable to advertise - Value Error");
|
||||
break;
|
||||
|
||||
case BLE_HS_EALREADY:
|
||||
NIMBLE_LOGI(LOG_TAG, "Advertisement Already active");
|
||||
break;
|
||||
|
||||
case BLE_HS_ETIMEOUT_HCI:
|
||||
case BLE_HS_EOS:
|
||||
case BLE_HS_ECONTROLLER:
|
||||
case BLE_HS_ENOTSYNCED:
|
||||
NIMBLE_LOGE(LOG_TAG, "Unable to advertise - Host Reset");
|
||||
break;
|
||||
|
||||
default:
|
||||
NIMBLE_LOGE(LOG_TAG, "Error enabling advertising; rc=%d, %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
break;
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< Extended Advertising start");
|
||||
return (rc == 0 || rc == BLE_HS_EALREADY);
|
||||
} // start
|
||||
|
||||
|
||||
/**
|
||||
* @brief Stop and remove this instance data from the advertisement set.
|
||||
* @param [in] inst_id The extended advertisement instance to stop advertising.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEExtAdvertising::removeInstance(uint8_t inst_id) {
|
||||
if (stop(inst_id)) {
|
||||
int rc = ble_gap_ext_adv_remove(inst_id);
|
||||
if (rc != 0 && rc != BLE_HS_EALREADY) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_ext_adv_remove rc = %d %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} // removeInstance
|
||||
|
||||
|
||||
/**
|
||||
* @brief Stop and remove all advertising instance data.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEExtAdvertising::removeAll() {
|
||||
if (stop()) {
|
||||
int rc = ble_gap_ext_adv_clear();
|
||||
if (rc == 0 || rc == BLE_HS_EALREADY) {
|
||||
return true;
|
||||
} else {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_ext_adv_clear rc = %d %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} // removeAll
|
||||
|
||||
|
||||
/**
|
||||
* @brief Stop advertising this instance data.
|
||||
* @param [in] inst_id The extended advertisement instance to stop advertising.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEExtAdvertising::stop(uint8_t inst_id) {
|
||||
int rc = ble_gap_ext_adv_stop(inst_id);
|
||||
if (rc != 0 && rc != BLE_HS_EALREADY) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_ext_adv_stop rc = %d %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_advStatus[inst_id] = false;
|
||||
return true;
|
||||
} // stop
|
||||
|
||||
|
||||
/**
|
||||
* @brief Stop all advertisements.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEExtAdvertising::stop() {
|
||||
int rc = ble_gap_ext_adv_clear();
|
||||
if (rc != 0 && rc != BLE_HS_EALREADY) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_ext_adv_stop rc = %d %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
return false;
|
||||
}
|
||||
|
||||
for(auto it : m_advStatus) {
|
||||
it = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} // stop
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set a callback to call when the advertisement stops.
|
||||
* @param [in] pCallbacks A pointer to a callback to be invoked when an advertisment stops.
|
||||
* @param [in] deleteCallbacks if true callback class will be deleted when advertising is destructed.
|
||||
*/
|
||||
void NimBLEExtAdvertising::setCallbacks(NimBLEExtAdvertisingCallbacks* pCallbacks,
|
||||
bool deleteCallbacks) {
|
||||
if (pCallbacks != nullptr){
|
||||
m_pCallbacks = pCallbacks;
|
||||
m_deleteCallbacks = deleteCallbacks;
|
||||
} else {
|
||||
m_pCallbacks = &defaultCallbacks;
|
||||
}
|
||||
} // setCallbacks
|
||||
|
||||
|
||||
/**
|
||||
* @brief Check if currently advertising.
|
||||
* @param [in] inst_id The instance ID of the advertised data to get the status of.
|
||||
* @return True if advertising is active.
|
||||
*/
|
||||
bool NimBLEExtAdvertising::isActive(uint8_t inst_id) {
|
||||
return m_advStatus[inst_id];
|
||||
} // isAdvertising
|
||||
|
||||
|
||||
/**
|
||||
* @brief Check if any instances are currently advertising.
|
||||
* @return True if any instance is active.
|
||||
*/
|
||||
bool NimBLEExtAdvertising::isAdvertising() {
|
||||
for (auto it : m_advStatus) {
|
||||
if (it) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} // isAdvertising
|
||||
|
||||
|
||||
/*
|
||||
* Host reset seems to clear advertising data,
|
||||
* we need clear the flag so it reloads it.
|
||||
*/
|
||||
void NimBLEExtAdvertising::onHostSync() {
|
||||
NIMBLE_LOGD(LOG_TAG, "Host re-synced");
|
||||
for(auto it : m_advStatus) {
|
||||
it = false;
|
||||
}
|
||||
} // onHostSync
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handler for gap events when not using peripheral role.
|
||||
* @param [in] event the event data.
|
||||
* @param [in] arg pointer to the advertising instance.
|
||||
*/
|
||||
/*STATIC*/
|
||||
int NimBLEExtAdvertising::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||
(void)arg;
|
||||
NimBLEExtAdvertising* pAdv = NimBLEDevice::getAdvertising();
|
||||
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_ADV_COMPLETE: {
|
||||
switch (event->adv_complete.reason) {
|
||||
// Don't call the callback if host reset, we want to
|
||||
// preserve the active flag until re-sync to restart advertising.
|
||||
case BLE_HS_ETIMEOUT_HCI:
|
||||
case BLE_HS_EOS:
|
||||
case BLE_HS_ECONTROLLER:
|
||||
case BLE_HS_ENOTSYNCED:
|
||||
NIMBLE_LOGC(LOG_TAG, "host reset, rc = %d", event->adv_complete.reason);
|
||||
NimBLEDevice::onReset(event->adv_complete.reason);
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pAdv->m_advStatus[event->adv_complete.instance] = false;
|
||||
pAdv->m_pCallbacks->onStopped(pAdv, event->adv_complete.reason,
|
||||
event->adv_complete.instance);
|
||||
break;
|
||||
}
|
||||
|
||||
case BLE_GAP_EVENT_SCAN_REQ_RCVD: {
|
||||
pAdv->m_pCallbacks->onScanRequest(pAdv, event->scan_req_rcvd.instance,
|
||||
NimBLEAddress(event->scan_req_rcvd.scan_addr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
} // handleGapEvent
|
||||
|
||||
|
||||
/** Default callback handlers */
|
||||
void NimBLEExtAdvertisingCallbacks::onStopped(NimBLEExtAdvertising *pAdv,
|
||||
int reason, uint8_t inst_id) {
|
||||
NIMBLE_LOGD("NimBLEExtAdvertisingCallbacks", "onStopped: Default");
|
||||
} // onStopped
|
||||
|
||||
|
||||
void NimBLEExtAdvertisingCallbacks::onScanRequest(NimBLEExtAdvertising *pAdv,
|
||||
uint8_t inst_id, NimBLEAddress addr) {
|
||||
NIMBLE_LOGD("NimBLEExtAdvertisingCallbacks", "onScanRequest: Default");
|
||||
} // onScanRequest
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct a BLE extended advertisement.
|
||||
* @param [in] priPhy The primary Phy to advertise on, can be one of:
|
||||
* * BLE_HCI_LE_PHY_1M
|
||||
* * BLE_HCI_LE_PHY_CODED
|
||||
* @param [in] secPhy The secondary Phy to advertise on, can be one of:
|
||||
* * BLE_HCI_LE_PHY_1M
|
||||
* * BLE_HCI_LE_PHY_2M
|
||||
* * BLE_HCI_LE_PHY_CODED
|
||||
*/
|
||||
NimBLEExtAdvertisement::NimBLEExtAdvertisement(uint8_t priPhy, uint8_t secPhy)
|
||||
: m_advAddress("")
|
||||
{
|
||||
memset (&m_params, 0, sizeof(m_params));
|
||||
m_params.own_addr_type = NimBLEDevice::m_own_addr_type;
|
||||
m_params.primary_phy = priPhy;
|
||||
m_params.secondary_phy = secPhy;
|
||||
m_params.tx_power = 127;
|
||||
} // NimBLEExtAdvertisement
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets wether the advertisement should use legacy (BLE 4.0, 31 bytes max) advertising.
|
||||
* @param [in] val true = using legacy advertising.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setLegacyAdvertising(bool val) {
|
||||
m_params.legacy_pdu = val;
|
||||
} // setLegacyAdvertising
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets wether the advertisement has scan response data available.
|
||||
* @param [in] val true = scan response is available.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setScannable(bool val) {
|
||||
m_params.scannable = val;
|
||||
} // setScannable
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets the transmission power level for this advertisement.
|
||||
* @param [in] dbm the transmission power to use in dbm.
|
||||
* @details The allowable value range depends on device hardware. \n
|
||||
* The ESP32C3 and ESP32S3 have a range of -27 to +18.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setTxPower(int8_t dbm) {
|
||||
m_params.tx_power = dbm;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets wether this advertisement should advertise as a connectable device.
|
||||
* @param [in] val True = connectable.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setConnectable(bool val) {
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
m_params.connectable = val;
|
||||
#endif
|
||||
} // setConnectable
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the address to use for this advertisement.
|
||||
* @param [in] addr The address to use.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setAddress(const NimBLEAddress & addr) {
|
||||
m_advAddress = addr;
|
||||
// Must use random address type.
|
||||
m_params.own_addr_type = BLE_OWN_ADDR_RANDOM;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets The primary channels to advertise on.
|
||||
* @param [in] ch37 Advertise on channel 37.
|
||||
* @param [in] ch38 Advertise on channel 38.
|
||||
* @param [in] ch39 Advertise on channel 39.
|
||||
* @details This will set a bitmask using the input parameters to allow different \n
|
||||
* combinations. If all inputs are false then all 3 channels will be used.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setPrimaryChannels(bool ch37, bool ch38, bool ch39) {
|
||||
m_params.channel_map = (ch37 | (ch38 << 1) | (ch39 << 2));
|
||||
} // setPrimaryChannels
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the filtering for the scan filter.
|
||||
* @param [in] scanRequestWhitelistOnly If true, only allow scan requests from those on the white list.
|
||||
* @param [in] connectWhitelistOnly If true, only allow connections from those on the white list.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly) {
|
||||
if (!scanRequestWhitelistOnly && !connectWhitelistOnly) {
|
||||
m_params.filter_policy = BLE_HCI_ADV_FILT_NONE;
|
||||
return;
|
||||
}
|
||||
if (scanRequestWhitelistOnly && !connectWhitelistOnly) {
|
||||
m_params.filter_policy = BLE_HCI_ADV_FILT_SCAN;
|
||||
return;
|
||||
}
|
||||
if (!scanRequestWhitelistOnly && connectWhitelistOnly) {
|
||||
m_params.filter_policy = BLE_HCI_ADV_FILT_CONN;
|
||||
return;
|
||||
}
|
||||
if (scanRequestWhitelistOnly && connectWhitelistOnly) {
|
||||
m_params.filter_policy = BLE_HCI_ADV_FILT_BOTH;
|
||||
return;
|
||||
}
|
||||
} // setScanFilter
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets the peer to directly advertise to.
|
||||
* @param [in] addr The address of the peer to direct the advertisements.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setDirectedPeer(const NimBLEAddress & addr) {
|
||||
ble_addr_t peerAddr;
|
||||
memcpy(&peerAddr.val, addr.getNative(), 6);
|
||||
peerAddr.type = addr.getType();
|
||||
m_params.peer = peerAddr;
|
||||
} // setDirectedPeer
|
||||
|
||||
|
||||
/**
|
||||
* @brief Enable or disable direct advertisements to the peer set with `NimBLEExtAdvertisement::setDirectedPeer`
|
||||
* @param [in] val true = send directed advertisements to peer.
|
||||
* @param [in] high_duty true = use fast advertising rate, default - true.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setDirected(bool val, bool high_duty) {
|
||||
m_params.directed = val;
|
||||
m_params.high_duty_directed = high_duty;
|
||||
} // setDirected
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the minimum advertising interval.
|
||||
* @param [in] mininterval Minimum value for advertising interval in 0.625ms units, 0 = use default.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setMinInterval(uint32_t mininterval) {
|
||||
m_params.itvl_min = mininterval;
|
||||
} // setMinInterval
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the maximum advertising interval.
|
||||
* @param [in] maxinterval Maximum value for advertising interval in 0.625ms units, 0 = use default.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setMaxInterval(uint32_t maxinterval) {
|
||||
m_params.itvl_max = maxinterval;
|
||||
} // setMaxInterval
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the primary advertising PHY to use
|
||||
* @param [in] phy Can be one of following constants:
|
||||
* * BLE_HCI_LE_PHY_1M
|
||||
* * BLE_HCI_LE_PHY_CODED
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setPrimaryPhy(uint8_t phy) {
|
||||
m_params.primary_phy = phy;
|
||||
} // setPrimaryPhy
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the secondary advertising PHY to use
|
||||
* @param [in] phy Can be one of following constants:
|
||||
* * BLE_HCI_LE_PHY_1M
|
||||
* * BLE_HCI_LE_PHY_2M
|
||||
* * BLE_HCI_LE_PHY_CODED
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setSecondaryPhy(uint8_t phy) {
|
||||
m_params.secondary_phy = phy;
|
||||
} // setSecondaryPhy
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets whether the advertisement should be anonymous.
|
||||
* @param [in] val Set to true to enable anonymous advertising.
|
||||
*
|
||||
* @details Anonymous advertising omits the device's address from the advertisement.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setAnonymous(bool val) {
|
||||
m_params.anonymous = val;
|
||||
} // setAnonymous
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets whether the scan response request callback should be called.
|
||||
* @param [in] enable If true the scan response request callback will be called for this advertisement.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::enableScanRequestCallback(bool enable) {
|
||||
m_params.scan_req_notif = enable;
|
||||
} // enableScanRequestCallback
|
||||
|
||||
|
||||
/**
|
||||
* @brief Clears the data stored in this instance, does not change settings.
|
||||
* @details This will clear all data but preserves advertising parameter settings.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::clearData() {
|
||||
std::vector<uint8_t> swap;
|
||||
std::swap(m_payload, swap);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the size of the current data.
|
||||
*/
|
||||
size_t NimBLEExtAdvertisement::getDataSize() {
|
||||
return m_payload.size();
|
||||
} // getDataSize
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the advertisement data.
|
||||
* @param [in] data The data to be set as the payload.
|
||||
* @param [in] length The size of data.
|
||||
* @details This will completely replace any data that was previously set.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setData(const uint8_t * data, size_t length) {
|
||||
m_payload.assign(data, data + length);
|
||||
} // setData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Add data to the payload to be advertised.
|
||||
* @param [in] data The data to be added to the payload.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::addData(const std::string &data) {
|
||||
addData((uint8_t*)data.data(), data.length());
|
||||
} // addData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Add data to the payload to be advertised.
|
||||
* @param [in] data The data to be added to the payload.
|
||||
* @param [in] length The size of data to be added to the payload.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::addData(const uint8_t * data, size_t length) {
|
||||
m_payload.insert(m_payload.end(), data, data + length);
|
||||
} // addData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the appearance.
|
||||
* @param [in] appearance The appearance code value.
|
||||
*
|
||||
* See also:
|
||||
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setAppearance(uint16_t appearance) {
|
||||
char cdata[2];
|
||||
cdata[0] = 3;
|
||||
cdata[1] = BLE_HS_ADV_TYPE_APPEARANCE; // 0x19
|
||||
addData(std::string(cdata, 2) + std::string((char*) &appearance, 2));
|
||||
} // setAppearance
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the advertisement flags.
|
||||
* @param [in] flag The flags to be set in the advertisement.
|
||||
* * BLE_HS_ADV_F_DISC_LTD
|
||||
* * BLE_HS_ADV_F_DISC_GEN
|
||||
* * BLE_HS_ADV_F_BREDR_UNSUP - must always use with NimBLE
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setFlags(uint8_t flag) {
|
||||
char cdata[3];
|
||||
cdata[0] = 2;
|
||||
cdata[1] = BLE_HS_ADV_TYPE_FLAGS; // 0x01
|
||||
cdata[2] = flag | BLE_HS_ADV_F_BREDR_UNSUP;
|
||||
addData(std::string(cdata, 3));
|
||||
} // setFlags
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set manufacturer specific data.
|
||||
* @param [in] data The manufacturer data to advertise.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setManufacturerData(const std::string &data) {
|
||||
char cdata[2];
|
||||
cdata[0] = data.length() + 1;
|
||||
cdata[1] = BLE_HS_ADV_TYPE_MFG_DATA ; // 0xff
|
||||
addData(std::string(cdata, 2) + data);
|
||||
} // setManufacturerData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the URI to advertise.
|
||||
* @param [in] uri The uri to advertise.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setURI(const std::string &uri) {
|
||||
char cdata[2];
|
||||
cdata[0] = uri.length() + 1;
|
||||
cdata[1] = BLE_HS_ADV_TYPE_URI;
|
||||
addData(std::string(cdata, 2) + uri);
|
||||
} // setURI
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the complete name of this device.
|
||||
* @param [in] name The name to advertise.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setName(const std::string &name) {
|
||||
char cdata[2];
|
||||
cdata[0] = name.length() + 1;
|
||||
cdata[1] = BLE_HS_ADV_TYPE_COMP_NAME; // 0x09
|
||||
addData(std::string(cdata, 2) + name);
|
||||
} // setName
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set a single service to advertise as a complete list of services.
|
||||
* @param [in] uuid The service to advertise.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setCompleteServices(const NimBLEUUID &uuid) {
|
||||
setServices(true, uuid.bitSize(), {uuid});
|
||||
} // setCompleteServices
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the complete list of 16 bit services to advertise.
|
||||
* @param [in] v_uuid A vector of 16 bit UUID's to advertise.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setCompleteServices16(const std::vector<NimBLEUUID>& v_uuid) {
|
||||
setServices(true, 16, v_uuid);
|
||||
} // setCompleteServices16
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the complete list of 32 bit services to advertise.
|
||||
* @param [in] v_uuid A vector of 32 bit UUID's to advertise.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setCompleteServices32(const std::vector<NimBLEUUID>& v_uuid) {
|
||||
setServices(true, 32, v_uuid);
|
||||
} // setCompleteServices32
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set a single service to advertise as a partial list of services.
|
||||
* @param [in] uuid The service to advertise.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setPartialServices(const NimBLEUUID &uuid) {
|
||||
setServices(false, uuid.bitSize(), {uuid});
|
||||
} // setPartialServices
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the partial list of services to advertise.
|
||||
* @param [in] v_uuid A vector of 16 bit UUID's to advertise.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setPartialServices16(const std::vector<NimBLEUUID>& v_uuid) {
|
||||
setServices(false, 16, v_uuid);
|
||||
} // setPartialServices16
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the partial list of services to advertise.
|
||||
* @param [in] v_uuid A vector of 32 bit UUID's to advertise.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setPartialServices32(const std::vector<NimBLEUUID>& v_uuid) {
|
||||
setServices(false, 32, v_uuid);
|
||||
} // setPartialServices32
|
||||
|
||||
|
||||
/**
|
||||
* @brief Utility function to create the list of service UUID's from a vector.
|
||||
* @param [in] complete If true the vector is the complete set of services.
|
||||
* @param [in] size The bit size of the UUID's in the vector. (16, 32, or 128).
|
||||
* @param [in] v_uuid The vector of service UUID's to advertise.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setServices(const bool complete, const uint8_t size,
|
||||
const std::vector<NimBLEUUID> &v_uuid)
|
||||
{
|
||||
char cdata[2];
|
||||
cdata[0] = (size / 8) * v_uuid.size() + 1;
|
||||
switch(size) {
|
||||
case 16:
|
||||
cdata[1] = complete ? BLE_HS_ADV_TYPE_COMP_UUIDS16 : BLE_HS_ADV_TYPE_INCOMP_UUIDS16;
|
||||
break;
|
||||
case 32:
|
||||
cdata[1] = complete ? BLE_HS_ADV_TYPE_COMP_UUIDS32 : BLE_HS_ADV_TYPE_INCOMP_UUIDS32;
|
||||
break;
|
||||
case 128:
|
||||
cdata[1] = complete ? BLE_HS_ADV_TYPE_COMP_UUIDS128 : BLE_HS_ADV_TYPE_INCOMP_UUIDS128;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
std::string uuids;
|
||||
|
||||
for(auto &it : v_uuid){
|
||||
if(it.bitSize() != size) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Service UUID(%d) invalid", size);
|
||||
return;
|
||||
} else {
|
||||
switch(size) {
|
||||
case 16:
|
||||
uuids += std::string((char*)&it.getNative()->u16.value, 2);
|
||||
break;
|
||||
case 32:
|
||||
uuids += std::string((char*)&it.getNative()->u32.value, 4);
|
||||
break;
|
||||
case 128:
|
||||
uuids += std::string((char*)&it.getNative()->u128.value, 16);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addData(std::string(cdata, 2) + uuids);
|
||||
} // setServices
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the service data (UUID + data)
|
||||
* @param [in] uuid The UUID to set with the service data.
|
||||
* @param [in] data The data to be associated with the service data advertised.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setServiceData(const NimBLEUUID &uuid, const std::string &data) {
|
||||
char cdata[2];
|
||||
switch (uuid.bitSize()) {
|
||||
case 16: {
|
||||
// [Len] [0x16] [UUID16] data
|
||||
cdata[0] = data.length() + 3;
|
||||
cdata[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID16; // 0x16
|
||||
addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u16.value, 2) + data);
|
||||
break;
|
||||
}
|
||||
|
||||
case 32: {
|
||||
// [Len] [0x20] [UUID32] data
|
||||
cdata[0] = data.length() + 5;
|
||||
cdata[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID32; // 0x20
|
||||
addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u32.value, 4) + data);
|
||||
break;
|
||||
}
|
||||
|
||||
case 128: {
|
||||
// [Len] [0x21] [UUID128] data
|
||||
cdata[0] = data.length() + 17;
|
||||
cdata[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID128; // 0x21
|
||||
addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u128.value, 16) + data);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
} // setServiceData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the short name.
|
||||
* @param [in] name The short name of the device.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setShortName(const std::string &name) {
|
||||
char cdata[2];
|
||||
cdata[0] = name.length() + 1;
|
||||
cdata[1] = BLE_HS_ADV_TYPE_INCOMP_NAME; // 0x08
|
||||
addData(std::string(cdata, 2) + name);
|
||||
} // setShortName
|
||||
|
||||
|
||||
/**
|
||||
* @brief Adds Tx power level to the advertisement data.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::addTxPower() {
|
||||
m_params.include_tx_power = 1;
|
||||
} // addTxPower
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the preferred connection interval parameters.
|
||||
* @param [in] min The minimum interval desired.
|
||||
* @param [in] max The maximum interval desired.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setPreferredParams(uint16_t min, uint16_t max) {
|
||||
uint8_t data[6];
|
||||
data[0] = BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1;
|
||||
data[1] = BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE;
|
||||
data[2] = min;
|
||||
data[3] = min >> 8;
|
||||
data[4] = max;
|
||||
data[5] = max >> 8;
|
||||
addData(data, 6);
|
||||
} // setPreferredParams
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && CONFIG_BT_NIMBLE_EXT_ADV */
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* NimBLEExtAdvertising.h
|
||||
*
|
||||
* Created: on February 6, 2022
|
||||
* Author H2zero
|
||||
*/
|
||||
|
||||
#ifndef MAIN_BLEEXTADVERTISING_H_
|
||||
#define MAIN_BLEEXTADVERTISING_H_
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && \
|
||||
defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) && \
|
||||
CONFIG_BT_NIMBLE_EXT_ADV
|
||||
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include "host/ble_gap.h"
|
||||
# else
|
||||
# include "nimble/nimble/host/include/host/ble_gap.h"
|
||||
# endif
|
||||
|
||||
/**** FIX COMPILATION ****/
|
||||
#undef min
|
||||
#undef max
|
||||
/**************************/
|
||||
|
||||
#include "NimBLEAddress.h"
|
||||
#include "NimBLEUUID.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class NimBLEExtAdvertisingCallbacks;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Extended advertisement data
|
||||
*/
|
||||
class NimBLEExtAdvertisement {
|
||||
public:
|
||||
NimBLEExtAdvertisement(uint8_t priPhy = BLE_HCI_LE_PHY_1M,
|
||||
uint8_t secPhy = BLE_HCI_LE_PHY_1M);
|
||||
void setAppearance(uint16_t appearance);
|
||||
void setCompleteServices(const NimBLEUUID &uuid);
|
||||
void setCompleteServices16(const std::vector<NimBLEUUID> &v_uuid);
|
||||
void setCompleteServices32(const std::vector<NimBLEUUID> &v_uuid);
|
||||
void setFlags(uint8_t flag);
|
||||
void setManufacturerData(const std::string &data);
|
||||
void setURI(const std::string &uri);
|
||||
void setName(const std::string &name);
|
||||
void setPartialServices(const NimBLEUUID &uuid);
|
||||
void setPartialServices16(const std::vector<NimBLEUUID> &v_uuid);
|
||||
void setPartialServices32(const std::vector<NimBLEUUID> &v_uuid);
|
||||
void setServiceData(const NimBLEUUID &uuid, const std::string &data);
|
||||
void setShortName(const std::string &name);
|
||||
void setData(const uint8_t * data, size_t length);
|
||||
void addData(const std::string &data);
|
||||
void addData(const uint8_t * data, size_t length);
|
||||
void addTxPower();
|
||||
void setPreferredParams(uint16_t min, uint16_t max);
|
||||
void setLegacyAdvertising(bool val);
|
||||
void setConnectable(bool val);
|
||||
void setScannable(bool val);
|
||||
void setMinInterval(uint32_t mininterval);
|
||||
void setMaxInterval(uint32_t maxinterval);
|
||||
void setPrimaryPhy(uint8_t phy);
|
||||
void setSecondaryPhy(uint8_t phy);
|
||||
void setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly);
|
||||
void setDirectedPeer(const NimBLEAddress & addr);
|
||||
void setDirected(bool val, bool high_duty = true);
|
||||
void setAnonymous(bool val);
|
||||
void setPrimaryChannels(bool ch37, bool ch38, bool ch39);
|
||||
void setTxPower(int8_t dbm);
|
||||
void setAddress(const NimBLEAddress & addr);
|
||||
void enableScanRequestCallback(bool enable);
|
||||
void clearData();
|
||||
size_t getDataSize();
|
||||
|
||||
private:
|
||||
friend class NimBLEExtAdvertising;
|
||||
|
||||
void setServices(const bool complete, const uint8_t size,
|
||||
const std::vector<NimBLEUUID> &v_uuid);
|
||||
|
||||
std::vector<uint8_t> m_payload;
|
||||
ble_gap_ext_adv_params m_params;
|
||||
NimBLEAddress m_advAddress;
|
||||
}; // NimBLEExtAdvertisement
|
||||
|
||||
|
||||
/**
|
||||
* @brief Extended advertising class.
|
||||
*/
|
||||
class NimBLEExtAdvertising {
|
||||
public:
|
||||
/**
|
||||
* @brief Construct an extended advertising object.
|
||||
*/
|
||||
NimBLEExtAdvertising() :m_advStatus(CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES + 1, false) {}
|
||||
~NimBLEExtAdvertising();
|
||||
bool start(uint8_t inst_id, int duration = 0, int max_events = 0);
|
||||
bool setInstanceData(uint8_t inst_id, NimBLEExtAdvertisement& adv);
|
||||
bool setScanResponseData(uint8_t inst_id, NimBLEExtAdvertisement & data);
|
||||
bool removeInstance(uint8_t inst_id);
|
||||
bool removeAll();
|
||||
bool stop(uint8_t inst_id);
|
||||
bool stop();
|
||||
bool isActive(uint8_t inst_id);
|
||||
bool isAdvertising();
|
||||
void setCallbacks(NimBLEExtAdvertisingCallbacks* callbacks,
|
||||
bool deleteCallbacks = true);
|
||||
|
||||
private:
|
||||
friend class NimBLEDevice;
|
||||
friend class NimBLEServer;
|
||||
|
||||
void onHostSync();
|
||||
static int handleGapEvent(struct ble_gap_event *event, void *arg);
|
||||
|
||||
bool m_scanResp;
|
||||
bool m_deleteCallbacks;
|
||||
NimBLEExtAdvertisingCallbacks* m_pCallbacks;
|
||||
ble_gap_ext_adv_params m_advParams;
|
||||
std::vector<bool> m_advStatus;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callbacks associated with NimBLEExtAdvertising class.
|
||||
*/
|
||||
class NimBLEExtAdvertisingCallbacks {
|
||||
public:
|
||||
virtual ~NimBLEExtAdvertisingCallbacks() {};
|
||||
|
||||
/**
|
||||
* @brief Handle an advertising stop event.
|
||||
* @param [in] pAdv A convenience pointer to the extended advertising interface.
|
||||
* @param [in] reason The reason code for stopping the advertising.
|
||||
* @param [in] inst_id The instance ID of the advertisement that was stopped.
|
||||
*/
|
||||
virtual void onStopped(NimBLEExtAdvertising *pAdv, int reason, uint8_t inst_id);
|
||||
|
||||
/**
|
||||
* @brief Handle a scan response request.
|
||||
* This is called when a scanning device requests a scan response.
|
||||
* @param [in] pAdv A convenience pointer to the extended advertising interface.
|
||||
* @param [in] inst_id The instance ID of the advertisement that the scan response request was made.
|
||||
* @param [in] addr The address of the device making the request.
|
||||
*/
|
||||
virtual void onScanRequest(NimBLEExtAdvertising *pAdv, uint8_t inst_id, NimBLEAddress addr);
|
||||
}; // NimBLEExtAdvertisingCallbacks
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && CONFIG_BT_NIMBLE_EXT_ADV */
|
||||
#endif /* MAIN_BLEADVERTISING_H_ */
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#if 0 // using esp-idf
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF) // using esp-idf
|
||||
# include "esp_log.h"
|
||||
# ifndef CONFIG_NIMBLE_CPP_LOG_LEVEL
|
||||
# define CONFIG_NIMBLE_CPP_LOG_LEVEL 0
|
||||
@@ -39,8 +39,8 @@
|
||||
NIMBLE_CPP_LOG_PRINT(ESP_LOG_ERROR, tag, format, ##__VA_ARGS__)
|
||||
|
||||
#else // using Arduino
|
||||
# include "syscfg/syscfg.h"
|
||||
# include "console/console.h"
|
||||
# include "nimble/porting/nimble/include/syscfg/syscfg.h"
|
||||
# include "nimble/console/console.h"
|
||||
# ifndef CONFIG_NIMBLE_CPP_LOG_LEVEL
|
||||
# if defined(ARDUINO_ARCH_ESP32) && defined(CORE_DEBUG_LEVEL)
|
||||
# define CONFIG_NIMBLE_CPP_LOG_LEVEL CORE_DEBUG_LEVEL
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
#include "NimBLERemoteCharacteristic.h"
|
||||
#include "NimBLEDevice.h"
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
@@ -59,6 +58,7 @@ static const char* LOG_TAG = "NimBLERemoteCharacteristic";
|
||||
m_charProp = chr->properties;
|
||||
m_pRemoteService = pRemoteService;
|
||||
m_notifyCallback = nullptr;
|
||||
m_timestamp = 0;
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< NimBLERemoteCharacteristic(): %s", m_uuid.toString().c_str());
|
||||
} // NimBLERemoteCharacteristic
|
||||
@@ -180,7 +180,14 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
|
||||
* Else if rc == 0, just return 0 to continue the discovery until we get BLE_HS_EDONE.
|
||||
* If we get any other error code tell the application to abort by returning non-zero in the rc.
|
||||
*/
|
||||
NimBLEDevice::taskComplete(pTaskData, rc == BLE_HS_EDONE ? 0 : rc);
|
||||
if (rc == BLE_HS_EDONE) {
|
||||
pTaskData->rc = 0;
|
||||
xTaskNotifyGive(pTaskData->task);
|
||||
} else if(rc != 0) {
|
||||
// Error; abort discovery.
|
||||
pTaskData->rc = rc;
|
||||
xTaskNotifyGive(pTaskData->task);
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG,"<< Descriptor Discovered. status: %d", pTaskData->rc);
|
||||
return rc;
|
||||
@@ -210,9 +217,11 @@ int NimBLERemoteCharacteristic::nextCharCB(uint16_t conn_handle,
|
||||
rc = BLE_HS_EDONE;
|
||||
} else if (rc == BLE_HS_EDONE) {
|
||||
pChar->m_endHandle = pChar->getRemoteService()->getEndHandle();
|
||||
} else {
|
||||
pTaskData->rc = rc;
|
||||
}
|
||||
|
||||
NimBLEDevice::taskComplete(pTaskData, rc == BLE_HS_EDONE ? 0 : rc);
|
||||
xTaskNotifyGive(pTaskData->task);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -230,7 +239,8 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
ble_task_data_t taskData = {this, nullptr, -1, nullptr};
|
||||
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
|
||||
|
||||
// If we don't know the end handle of this characteristic retrieve the next one in the service
|
||||
// The end handle is the next characteristic definition handle -1.
|
||||
@@ -245,10 +255,11 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!NimBLEDevice::taskWait(&taskData, 10 * 1000)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Find end handle timeout");
|
||||
return false;
|
||||
}
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
if (taskData.rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Could not retrieve end handle rc=%d", taskData.rc);
|
||||
@@ -256,11 +267,6 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt
|
||||
}
|
||||
}
|
||||
|
||||
if (m_handle == m_endHandle) {
|
||||
return true;
|
||||
}
|
||||
|
||||
taskData.rc = -1;
|
||||
desc_filter_t filter = {uuid_filter, &taskData};
|
||||
|
||||
rc = ble_gattc_disc_all_dscs(getRemoteService()->getClient()->getConnId(),
|
||||
@@ -274,10 +280,11 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!NimBLEDevice::taskWait(&taskData, 10 * 1000)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Discover Descriptors timeout");
|
||||
return false;
|
||||
}
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
if (taskData.rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Failed to retrieve descriptors; startHandle:%d endHandle:%d taskData.rc=%d",
|
||||
@@ -424,12 +431,15 @@ NimBLEUUID NimBLERemoteCharacteristic::getUUID() {
|
||||
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
|
||||
* @return The value of the remote characteristic.
|
||||
*/
|
||||
NimBLEAttValue NimBLERemoteCharacteristic::getValue(time_t *timestamp) {
|
||||
std::string NimBLERemoteCharacteristic::getValue(time_t *timestamp) {
|
||||
ble_npl_hw_enter_critical();
|
||||
std::string value = m_value;
|
||||
if(timestamp != nullptr) {
|
||||
*timestamp = m_value.getTimeStamp();
|
||||
*timestamp = m_timestamp;
|
||||
}
|
||||
ble_npl_hw_exit_critical(0);
|
||||
|
||||
return m_value;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
@@ -477,12 +487,12 @@ float NimBLERemoteCharacteristic::readFloat() {
|
||||
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
|
||||
* @return The value of the remote characteristic.
|
||||
*/
|
||||
NimBLEAttValue NimBLERemoteCharacteristic::readValue(time_t *timestamp) {
|
||||
std::string NimBLERemoteCharacteristic::readValue(time_t *timestamp) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> readValue(): uuid: %s, handle: %d 0x%.2x",
|
||||
getUUID().toString().c_str(), getHandle(), getHandle());
|
||||
|
||||
NimBLEClient* pClient = getRemoteService()->getClient();
|
||||
NimBLEAttValue value;
|
||||
std::string value;
|
||||
|
||||
if (!pClient->isConnected()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Disconnected");
|
||||
@@ -491,8 +501,10 @@ NimBLEAttValue NimBLERemoteCharacteristic::readValue(time_t *timestamp) {
|
||||
|
||||
int rc = 0;
|
||||
int retryCount = 1;
|
||||
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||
ble_task_data_t taskData = {this, cur_task, 0, &value};
|
||||
|
||||
do {
|
||||
ble_task_data_t taskData = {this, nullptr, -1, &value};
|
||||
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
|
||||
NimBLERemoteCharacteristic::onReadCB,
|
||||
&taskData);
|
||||
@@ -502,10 +514,11 @@ NimBLEAttValue NimBLERemoteCharacteristic::readValue(time_t *timestamp) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (!NimBLEDevice::taskWait(&taskData, 10 * 1000)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "readValue timeout");
|
||||
return value;
|
||||
}
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
rc = taskData.rc;
|
||||
|
||||
switch(rc){
|
||||
@@ -530,11 +543,14 @@ NimBLEAttValue NimBLERemoteCharacteristic::readValue(time_t *timestamp) {
|
||||
}
|
||||
} while(rc != 0 && retryCount--);
|
||||
|
||||
value.setTimeStamp();
|
||||
time_t t = time(nullptr);
|
||||
ble_npl_hw_enter_critical();
|
||||
m_value = value;
|
||||
m_timestamp = t;
|
||||
if(timestamp != nullptr) {
|
||||
*timestamp = value.getTimeStamp();
|
||||
*timestamp = m_timestamp;
|
||||
}
|
||||
ble_npl_hw_exit_critical(0);
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< readValue length: %d rc=%d", value.length(), rc);
|
||||
return value;
|
||||
@@ -559,23 +575,25 @@ int NimBLERemoteCharacteristic::onReadCB(uint16_t conn_handle,
|
||||
|
||||
NIMBLE_LOGI(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
|
||||
|
||||
NimBLEAttValue *valBuf = (NimBLEAttValue*)pTaskData->buf;
|
||||
std::string *strBuf = (std::string*)pTaskData->buf;
|
||||
int rc = error->status;
|
||||
|
||||
if(rc == 0) {
|
||||
if(attr) {
|
||||
uint16_t data_len = OS_MBUF_PKTLEN(attr->om);
|
||||
if((valBuf->size() + data_len) > BLE_ATT_ATTR_MAX_LEN) {
|
||||
if(((*strBuf).length() + data_len) > BLE_ATT_ATTR_MAX_LEN) {
|
||||
rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
} else {
|
||||
NIMBLE_LOGD(LOG_TAG, "Got %u bytes", data_len);
|
||||
valBuf->append(attr->om->om_data, data_len);
|
||||
(*strBuf) += std::string((char*) attr->om->om_data, data_len);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NimBLEDevice::taskComplete(pTaskData, rc);
|
||||
pTaskData->rc = rc;
|
||||
xTaskNotifyGive(pTaskData->task);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -718,33 +736,22 @@ std::string NimBLERemoteCharacteristic::toString() {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write a new value to the remote characteristic from a std::vector<uint8_t>.
|
||||
* @param [in] vec A std::vector<uint8_t> value to write to the remote characteristic.
|
||||
* @param [in] response Whether we require a response from the write.
|
||||
* @return false if not connected or otherwise cannot perform write.
|
||||
* @brief Write the new value for the characteristic.
|
||||
* @param [in] newValue The new value to write.
|
||||
* @param [in] response Do we expect a response?
|
||||
* @return false if not connected or cant perform write for some reason.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::writeValue(const std::vector<uint8_t>& vec, bool response) {
|
||||
return writeValue((uint8_t*)&vec[0], vec.size(), response);
|
||||
bool NimBLERemoteCharacteristic::writeValue(const std::string &newValue, bool response) {
|
||||
return writeValue((uint8_t*)newValue.c_str(), newValue.length(), response);
|
||||
} // writeValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write a new value to the remote characteristic from a const char*.
|
||||
* @param [in] char_s A character string to write to the remote characteristic.
|
||||
* @param [in] response Whether we require a response from the write.
|
||||
* @return false if not connected or otherwise cannot perform write.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::writeValue(const char* char_s, bool response) {
|
||||
return writeValue((uint8_t*)char_s, strlen(char_s), response);
|
||||
} // writeValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write a new value to the remote characteristic from a data buffer.
|
||||
* @brief Write the new value for the characteristic from a data buffer.
|
||||
* @param [in] data A pointer to a data buffer.
|
||||
* @param [in] length The length of the data in the data buffer.
|
||||
* @param [in] response Whether we require a response from the write.
|
||||
* @return false if not connected or otherwise cannot perform write.
|
||||
* @return false if not connected or cant perform write for some reason.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length, bool response) {
|
||||
|
||||
@@ -768,8 +775,10 @@ bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length,
|
||||
return (rc==0);
|
||||
}
|
||||
|
||||
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
|
||||
|
||||
do {
|
||||
ble_task_data_t taskData = {this, nullptr, -1, nullptr};
|
||||
if(length > mtu) {
|
||||
NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length);
|
||||
os_mbuf *om = ble_hs_mbuf_from_flat(data, length);
|
||||
@@ -782,17 +791,16 @@ bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length,
|
||||
NimBLERemoteCharacteristic::onWriteCB,
|
||||
&taskData);
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Error: Failed to write characteristic; rc=%d", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!NimBLEDevice::taskWait(&taskData, 10 * 1000)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Write value timeout");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
rc = taskData.rc;
|
||||
|
||||
switch(rc){
|
||||
@@ -838,10 +846,11 @@ int NimBLERemoteCharacteristic::onWriteCB(uint16_t conn_handle,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rc = error->status;
|
||||
NIMBLE_LOGI(LOG_TAG, "Write complete; status=%d conn_handle=%d", rc, conn_handle);
|
||||
NIMBLE_LOGI(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle);
|
||||
|
||||
pTaskData->rc = error->status;
|
||||
xTaskNotifyGive(pTaskData->task);
|
||||
|
||||
NimBLEDevice::taskComplete(pTaskData, rc == BLE_HS_EDONE ? 0 : rc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include "NimBLELog.h"
|
||||
|
||||
class NimBLERemoteService;
|
||||
class NimBLERemoteDescriptor;
|
||||
@@ -61,15 +60,47 @@ public:
|
||||
uint16_t getHandle();
|
||||
uint16_t getDefHandle();
|
||||
NimBLEUUID getUUID();
|
||||
NimBLEAttValue readValue(time_t *timestamp = nullptr);
|
||||
std::string toString();
|
||||
NimBLERemoteService* getRemoteService();
|
||||
std::string readValue(time_t *timestamp = nullptr);
|
||||
|
||||
/**
|
||||
* @brief A template to convert the remote characteristic data to <type\>.
|
||||
* @tparam T The type to convert the data to.
|
||||
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
|
||||
* @param [in] skipSizeCheck If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||
* less than <tt>sizeof(<type\>)</tt>.
|
||||
* @details <b>Use:</b> <tt>readValue<type>(×tamp, skipSizeCheck);</tt>
|
||||
*/
|
||||
template<typename T>
|
||||
T readValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
|
||||
std::string value = readValue(timestamp);
|
||||
if(!skipSizeCheck && value.size() < sizeof(T)) return T();
|
||||
const char *pData = value.data();
|
||||
return *((T *)pData);
|
||||
}
|
||||
|
||||
uint8_t readUInt8() __attribute__ ((deprecated("Use template readValue<uint8_t>()")));
|
||||
uint16_t readUInt16() __attribute__ ((deprecated("Use template readValue<uint16_t>()")));
|
||||
uint32_t readUInt32() __attribute__ ((deprecated("Use template readValue<uint32_t>()")));
|
||||
float readFloat() __attribute__ ((deprecated("Use template readValue<float>()")));
|
||||
NimBLEAttValue getValue(time_t *timestamp = nullptr);
|
||||
std::string getValue(time_t *timestamp = nullptr);
|
||||
|
||||
/**
|
||||
* @brief A template to convert the remote characteristic data to <type\>.
|
||||
* @tparam T The type to convert the data to.
|
||||
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
|
||||
* @param [in] skipSizeCheck If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||
* less than <tt>sizeof(<type\>)</tt>.
|
||||
* @details <b>Use:</b> <tt>getValue<type>(×tamp, skipSizeCheck);</tt>
|
||||
*/
|
||||
template<typename T>
|
||||
T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
|
||||
std::string value = getValue(timestamp);
|
||||
if(!skipSizeCheck && value.size() < sizeof(T)) return T();
|
||||
const char *pData = value.data();
|
||||
return *((T *)pData);
|
||||
}
|
||||
|
||||
bool subscribe(bool notifications = true,
|
||||
notify_callback notifyCallback = nullptr,
|
||||
@@ -82,74 +113,20 @@ public:
|
||||
bool writeValue(const uint8_t* data,
|
||||
size_t length,
|
||||
bool response = false);
|
||||
bool writeValue(const std::vector<uint8_t>& v, bool response = false);
|
||||
bool writeValue(const char* s, bool response = false);
|
||||
|
||||
|
||||
/*********************** Template Functions ************************/
|
||||
|
||||
bool writeValue(const std::string &newValue,
|
||||
bool response = false);
|
||||
/**
|
||||
* @brief Template to set the remote characteristic value to <type\>val.
|
||||
* @brief Convenience template to set the remote characteristic value to <type\>val.
|
||||
* @param [in] s The value to write.
|
||||
* @param [in] response True == request write response.
|
||||
* @details Only used for non-arrays and types without a `c_str()` method.
|
||||
*/
|
||||
template<typename T>
|
||||
#ifdef _DOXYGEN_
|
||||
bool
|
||||
#else
|
||||
typename std::enable_if<!std::is_array<T>::value && !Has_c_str_len<T>::value, bool>::type
|
||||
#endif
|
||||
writeValue(const T& s, bool response = false) {
|
||||
bool writeValue(const T &s, bool response = false) {
|
||||
return writeValue((uint8_t*)&s, sizeof(T), response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to set the remote characteristic value to <type\>val.
|
||||
* @param [in] s The value to write.
|
||||
* @param [in] response True == request write response.
|
||||
* @details Only used if the <type\> has a `c_str()` method.
|
||||
*/
|
||||
template<typename T>
|
||||
#ifdef _DOXYGEN_
|
||||
bool
|
||||
#else
|
||||
typename std::enable_if<Has_c_str_len<T>::value, bool>::type
|
||||
#endif
|
||||
writeValue(const T& s, bool response = false) {
|
||||
return writeValue((uint8_t*)s.c_str(), s.length(), response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to convert the remote characteristic data to <type\>.
|
||||
* @tparam T The type to convert the data to.
|
||||
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
|
||||
* @param [in] skipSizeCheck If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||
* less than <tt>sizeof(<type\>)</tt>.
|
||||
* @details <b>Use:</b> <tt>getValue<type>(×tamp, skipSizeCheck);</tt>
|
||||
*/
|
||||
template<typename T>
|
||||
T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
|
||||
if(!skipSizeCheck && m_value.size() < sizeof(T)) return T();
|
||||
return *((T *)m_value.getValue(timestamp));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to convert the remote characteristic data to <type\>.
|
||||
* @tparam T The type to convert the data to.
|
||||
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
|
||||
* @param [in] skipSizeCheck If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||
* less than <tt>sizeof(<type\>)</tt>.
|
||||
* @details <b>Use:</b> <tt>readValue<type>(×tamp, skipSizeCheck);</tt>
|
||||
*/
|
||||
template<typename T>
|
||||
T readValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
|
||||
NimBLEAttValue value = readValue();
|
||||
if(!skipSizeCheck && value.size() < sizeof(T)) return T();
|
||||
return *((T *)value.getValue(timestamp));
|
||||
}
|
||||
std::string toString();
|
||||
NimBLERemoteService* getRemoteService();
|
||||
|
||||
private:
|
||||
|
||||
@@ -179,8 +156,9 @@ private:
|
||||
uint16_t m_defHandle;
|
||||
uint16_t m_endHandle;
|
||||
NimBLERemoteService* m_pRemoteService;
|
||||
NimBLEAttValue m_value;
|
||||
std::string m_value;
|
||||
notify_callback m_notifyCallback;
|
||||
time_t m_timestamp;
|
||||
|
||||
// We maintain a vector of descriptors owned by this characteristic.
|
||||
std::vector<NimBLERemoteDescriptor*> m_descriptorVector;
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
#include "NimBLERemoteDescriptor.h"
|
||||
#include "NimBLEDevice.h"
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
@@ -87,7 +86,11 @@ NimBLEUUID NimBLERemoteDescriptor::getUUID() {
|
||||
* @deprecated Use readValue<uint8_t>().
|
||||
*/
|
||||
uint8_t NimBLERemoteDescriptor::readUInt8() {
|
||||
return readValue<uint8_t>();
|
||||
std::string value = readValue();
|
||||
if (value.length() >= 1) {
|
||||
return (uint8_t) value[0];
|
||||
}
|
||||
return 0;
|
||||
} // readUInt8
|
||||
|
||||
|
||||
@@ -97,7 +100,11 @@ uint8_t NimBLERemoteDescriptor::readUInt8() {
|
||||
* @deprecated Use readValue<uint16_t>().
|
||||
*/
|
||||
uint16_t NimBLERemoteDescriptor::readUInt16() {
|
||||
return readValue<uint16_t>();
|
||||
std::string value = readValue();
|
||||
if (value.length() >= 2) {
|
||||
return *(uint16_t*) value.data();
|
||||
}
|
||||
return 0;
|
||||
} // readUInt16
|
||||
|
||||
|
||||
@@ -107,7 +114,11 @@ uint16_t NimBLERemoteDescriptor::readUInt16() {
|
||||
* @deprecated Use readValue<uint32_t>().
|
||||
*/
|
||||
uint32_t NimBLERemoteDescriptor::readUInt32() {
|
||||
return readValue<uint32_t>();
|
||||
std::string value = readValue();
|
||||
if (value.length() >= 4) {
|
||||
return *(uint32_t*) value.data();
|
||||
}
|
||||
return 0;
|
||||
} // readUInt32
|
||||
|
||||
|
||||
@@ -115,11 +126,11 @@ uint32_t NimBLERemoteDescriptor::readUInt32() {
|
||||
* @brief Read the value of the remote descriptor.
|
||||
* @return The value of the remote descriptor.
|
||||
*/
|
||||
NimBLEAttValue NimBLERemoteDescriptor::readValue() {
|
||||
std::string NimBLERemoteDescriptor::readValue() {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> Descriptor readValue: %s", toString().c_str());
|
||||
|
||||
NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
|
||||
NimBLEAttValue value;
|
||||
std::string value;
|
||||
|
||||
if (!pClient->isConnected()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Disconnected");
|
||||
@@ -128,10 +139,10 @@ NimBLEAttValue NimBLERemoteDescriptor::readValue() {
|
||||
|
||||
int rc = 0;
|
||||
int retryCount = 1;
|
||||
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||
ble_task_data_t taskData = {this, cur_task, 0, &value};
|
||||
|
||||
do {
|
||||
ble_task_data_t taskData = {this, nullptr, -1, &value};
|
||||
|
||||
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
|
||||
NimBLERemoteDescriptor::onReadCB,
|
||||
&taskData);
|
||||
@@ -141,11 +152,11 @@ NimBLEAttValue NimBLERemoteDescriptor::readValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (!NimBLEDevice::taskWait(&taskData, 10 * 1000)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Read desc value timeout");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
rc = taskData.rc;
|
||||
|
||||
switch(rc){
|
||||
@@ -193,23 +204,25 @@ int NimBLERemoteDescriptor::onReadCB(uint16_t conn_handle,
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
|
||||
|
||||
NimBLEAttValue *valBuf = (NimBLEAttValue*)pTaskData->buf;
|
||||
std::string *strBuf = (std::string*)pTaskData->buf;
|
||||
int rc = error->status;
|
||||
|
||||
if(rc == 0) {
|
||||
if(attr) {
|
||||
uint16_t data_len = OS_MBUF_PKTLEN(attr->om);
|
||||
if((valBuf->size() + data_len) > BLE_ATT_ATTR_MAX_LEN) {
|
||||
if(((*strBuf).length() + data_len) > BLE_ATT_ATTR_MAX_LEN) {
|
||||
rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
} else {
|
||||
NIMBLE_LOGD(LOG_TAG, "Got %u bytes", data_len);
|
||||
valBuf->append(attr->om->om_data, data_len);
|
||||
(*strBuf) += std::string((char*) attr->om->om_data, data_len);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NimBLEDevice::taskComplete(pTaskData, rc);
|
||||
pTaskData->rc = rc;
|
||||
xTaskNotifyGive(pTaskData->task);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -246,40 +259,19 @@ int NimBLERemoteDescriptor::onWriteCB(uint16_t conn_handle,
|
||||
|
||||
NIMBLE_LOGI(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle);
|
||||
|
||||
NimBLEDevice::taskComplete(pTaskData, error->status);
|
||||
pTaskData->rc = error->status;
|
||||
xTaskNotifyGive(pTaskData->task);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write a new value to a remote descriptor from a std::vector<uint8_t>.
|
||||
* @param [in] vec A std::vector<uint8_t> value to write to the remote descriptor.
|
||||
* @param [in] response Whether we require a response from the write.
|
||||
* @return false if not connected or otherwise cannot perform write.
|
||||
*/
|
||||
bool NimBLERemoteDescriptor::writeValue(const std::vector<uint8_t>& vec, bool response) {
|
||||
return writeValue((uint8_t*)&vec[0], vec.size(), response);
|
||||
} // writeValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write a new value to the remote descriptor from a const char*.
|
||||
* @param [in] char_s A character string to write to the remote descriptor.
|
||||
* @param [in] response Whether we require a response from the write.
|
||||
* @return false if not connected or otherwise cannot perform write.
|
||||
*/
|
||||
bool NimBLERemoteDescriptor::writeValue(const char* char_s, bool response) {
|
||||
return writeValue((uint8_t*)char_s, strlen(char_s), response);
|
||||
} // writeValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write a new value to a remote descriptor.
|
||||
* @brief Write data to the BLE Remote Descriptor.
|
||||
* @param [in] data The data to send to the remote descriptor.
|
||||
* @param [in] length The length of the data to send.
|
||||
* @param [in] response True if we expect a write response.
|
||||
* @return false if not connected or otherwise cannot perform write.
|
||||
* @return True if successful
|
||||
*/
|
||||
bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool response) {
|
||||
|
||||
@@ -304,9 +296,10 @@ bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool
|
||||
return (rc == 0);
|
||||
}
|
||||
|
||||
do {
|
||||
ble_task_data_t taskData = {this, nullptr, -1, nullptr};
|
||||
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
|
||||
|
||||
do {
|
||||
if(length > mtu) {
|
||||
NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length);
|
||||
os_mbuf *om = ble_hs_mbuf_from_flat(data, length);
|
||||
@@ -325,11 +318,11 @@ bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!NimBLEDevice::taskWait(&taskData, 10 * 1000)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Desc write value timeout");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
rc = taskData.rc;
|
||||
|
||||
switch(rc) {
|
||||
@@ -359,4 +352,14 @@ bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool
|
||||
} // writeValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write data represented as a string to the BLE Remote Descriptor.
|
||||
* @param [in] newValue The data to send to the remote descriptor.
|
||||
* @param [in] response True if we expect a response.
|
||||
* @return True if successful
|
||||
*/
|
||||
bool NimBLERemoteDescriptor::writeValue(const std::string &newValue, bool response) {
|
||||
return writeValue((uint8_t*) newValue.data(), newValue.length(), response);
|
||||
} // writeValue
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
|
||||
@@ -29,53 +29,10 @@ public:
|
||||
uint16_t getHandle();
|
||||
NimBLERemoteCharacteristic* getRemoteCharacteristic();
|
||||
NimBLEUUID getUUID();
|
||||
NimBLEAttValue readValue();
|
||||
|
||||
uint8_t readUInt8() __attribute__ ((deprecated("Use template readValue<uint8_t>()")));
|
||||
uint16_t readUInt16() __attribute__ ((deprecated("Use template readValue<uint16_t>()")));
|
||||
uint32_t readUInt32() __attribute__ ((deprecated("Use template readValue<uint32_t>()")));
|
||||
std::string toString(void);
|
||||
bool writeValue(const uint8_t* data, size_t length, bool response = false);
|
||||
bool writeValue(const std::vector<uint8_t>& v, bool response = false);
|
||||
bool writeValue(const char* s, bool response = false);
|
||||
|
||||
|
||||
/*********************** Template Functions ************************/
|
||||
std::string readValue();
|
||||
|
||||
/**
|
||||
* @brief Template to set the remote descriptor value to <type\>val.
|
||||
* @param [in] s The value to write.
|
||||
* @param [in] response True == request write response.
|
||||
* @details Only used for non-arrays and types without a `c_str()` method.
|
||||
*/
|
||||
template<typename T>
|
||||
#ifdef _DOXYGEN_
|
||||
bool
|
||||
#else
|
||||
typename std::enable_if<!std::is_array<T>::value && !Has_c_str_len<T>::value, bool>::type
|
||||
#endif
|
||||
writeValue(const T& s, bool response = false) {
|
||||
return writeValue((uint8_t*)&s, sizeof(T), response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to set the remote descriptor value to <type\>val.
|
||||
* @param [in] s The value to write.
|
||||
* @param [in] response True == request write response.
|
||||
* @details Only used if the <type\> has a `c_str()` method.
|
||||
*/
|
||||
template<typename T>
|
||||
#ifdef _DOXYGEN_
|
||||
bool
|
||||
#else
|
||||
typename std::enable_if<Has_c_str_len<T>::value, bool>::type
|
||||
#endif
|
||||
writeValue(const T& s, bool response = false) {
|
||||
return writeValue((uint8_t*)s.c_str(), s.length(), response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to convert the remote descriptor data to <type\>.
|
||||
* @brief A template to convert the remote descriptor data to <type\>.
|
||||
* @tparam T The type to convert the data to.
|
||||
* @param [in] skipSizeCheck If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||
@@ -83,10 +40,28 @@ public:
|
||||
* @details <b>Use:</b> <tt>readValue<type>(skipSizeCheck);</tt>
|
||||
*/
|
||||
template<typename T>
|
||||
T readValue(bool skipSizeCheck = false) {
|
||||
NimBLEAttValue value = readValue();
|
||||
T readValue(bool skipSizeCheck = false) {
|
||||
std::string value = readValue();
|
||||
if(!skipSizeCheck && value.size() < sizeof(T)) return T();
|
||||
return *((T *)value.data());
|
||||
const char *pData = value.data();
|
||||
return *((T *)pData);
|
||||
}
|
||||
|
||||
uint8_t readUInt8() __attribute__ ((deprecated("Use template readValue<uint8_t>()")));
|
||||
uint16_t readUInt16() __attribute__ ((deprecated("Use template readValue<uint16_t>()")));
|
||||
uint32_t readUInt32() __attribute__ ((deprecated("Use template readValue<uint32_t>()")));
|
||||
std::string toString(void);
|
||||
bool writeValue(const uint8_t* data, size_t length, bool response = false);
|
||||
bool writeValue(const std::string &newValue, bool response = false);
|
||||
|
||||
/**
|
||||
* @brief Convenience template to set the remote descriptor value to <type\>val.
|
||||
* @param [in] s The value to write.
|
||||
* @param [in] response True == request write response.
|
||||
*/
|
||||
template<typename T>
|
||||
bool writeValue(const T &s, bool response = false) {
|
||||
return writeValue((uint8_t*)&s, sizeof(T), response);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -199,8 +199,7 @@ int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle,
|
||||
pTaskData->rc = error->status;
|
||||
}
|
||||
|
||||
//xTaskNotifyGive(pTaskData->task);
|
||||
NimBLEDevice::taskComplete(pTaskData, pTaskData->rc);
|
||||
xTaskNotifyGive(pTaskData->task);
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG,"<< Characteristic Discovered");
|
||||
return error->status;
|
||||
@@ -216,8 +215,8 @@ bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID *uuid_filter)
|
||||
NIMBLE_LOGD(LOG_TAG, ">> retrieveCharacteristics() for service: %s", getUUID().toString().c_str());
|
||||
|
||||
int rc = 0;
|
||||
//TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||
ble_task_data_t taskData = {this, nullptr, -1, nullptr};
|
||||
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
|
||||
|
||||
if(uuid_filter == nullptr) {
|
||||
rc = ble_gattc_disc_all_chrs(m_pClient->getConnId(),
|
||||
@@ -239,10 +238,11 @@ bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID *uuid_filter)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!NimBLEDevice::taskWait(&taskData, 10 * 1000)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "disc chars timeout");
|
||||
return false;
|
||||
}
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
if(taskData.rc == 0){
|
||||
if (uuid_filter == nullptr) {
|
||||
@@ -256,9 +256,7 @@ bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID *uuid_filter)
|
||||
}
|
||||
}
|
||||
|
||||
if (m_characteristicVector.size() > 0) {
|
||||
m_characteristicVector.back()->m_endHandle = getEndHandle();
|
||||
}
|
||||
m_characteristicVector.back()->m_endHandle = getEndHandle();
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristics()");
|
||||
|
||||
@@ -56,27 +56,18 @@ NimBLEScan::~NimBLEScan() {
|
||||
* @param [in] param Parameter data for this event.
|
||||
*/
|
||||
/*STATIC*/int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) {
|
||||
(void)arg;
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
|
||||
NimBLEScan* pScan = (NimBLEScan*)arg;
|
||||
|
||||
switch(event->type) {
|
||||
|
||||
case BLE_GAP_EVENT_EXT_DISC:
|
||||
case BLE_GAP_EVENT_DISC: {
|
||||
if(pScan->m_ignoreResults) {
|
||||
NIMBLE_LOGI(LOG_TAG, "Scan op in progress - ignoring results");
|
||||
return 0;
|
||||
}
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
const auto& disc = event->ext_disc;
|
||||
const bool isLegacyAdv = disc.props & BLE_HCI_ADV_LEGACY_MASK;
|
||||
const auto event_type = isLegacyAdv ? disc.legacy_event_type : disc.props;
|
||||
#else
|
||||
const auto& disc = event->disc;
|
||||
const bool isLegacyAdv = true;
|
||||
const auto event_type = disc.event_type;
|
||||
#endif
|
||||
NimBLEAddress advertisedAddress(disc.addr);
|
||||
|
||||
NimBLEAddress advertisedAddress(event->disc.addr);
|
||||
|
||||
// Examine our list of ignored addresses and stop processing if we don't want to see it or are already connected
|
||||
if(NimBLEDevice::isIgnored(advertisedAddress)) {
|
||||
@@ -88,12 +79,7 @@ NimBLEScan::~NimBLEScan() {
|
||||
|
||||
// If we've seen this device before get a pointer to it from the vector
|
||||
for(auto &it: pScan->m_scanResults.m_advertisedDevicesVector) {
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
// Same address but different set ID should create a new advertised device.
|
||||
if (it->getAddress() == advertisedAddress && it->getSetId() == disc.sid) {
|
||||
#else
|
||||
if (it->getAddress() == advertisedAddress) {
|
||||
#endif
|
||||
if(it->getAddress() == advertisedAddress) {
|
||||
advertisedDevice = it;
|
||||
break;
|
||||
}
|
||||
@@ -101,27 +87,20 @@ NimBLEScan::~NimBLEScan() {
|
||||
|
||||
// If we haven't seen this device before; create a new instance and insert it in the vector.
|
||||
// Otherwise just update the relevant parameters of the already known device.
|
||||
if (advertisedDevice == nullptr &&
|
||||
(!isLegacyAdv || event_type != BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP)) {
|
||||
if(advertisedDevice == nullptr && event->disc.event_type != BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP){
|
||||
// Check if we have reach the scan results limit, ignore this one if so.
|
||||
// We still need to store each device when maxResults is 0 to be able to append the scan results
|
||||
if (pScan->m_maxResults > 0 && pScan->m_maxResults < 0xFF &&
|
||||
(pScan->m_scanResults.m_advertisedDevicesVector.size() >= pScan->m_maxResults)) {
|
||||
if(pScan->m_maxResults > 0 && pScan->m_maxResults < 0xFF &&
|
||||
(pScan->m_scanResults.m_advertisedDevicesVector.size() >= pScan->m_maxResults))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
advertisedDevice = new NimBLEAdvertisedDevice();
|
||||
advertisedDevice->setAddress(advertisedAddress);
|
||||
advertisedDevice->setAdvType(event_type, isLegacyAdv);
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
advertisedDevice->setSetId(disc.sid);
|
||||
advertisedDevice->setPrimaryPhy(disc.prim_phy);
|
||||
advertisedDevice->setSecondaryPhy(disc.sec_phy);
|
||||
advertisedDevice->setPeriodicInterval(disc.periodic_adv_itvl);
|
||||
#endif
|
||||
advertisedDevice->setAdvType(event->disc.event_type);
|
||||
pScan->m_scanResults.m_advertisedDevicesVector.push_back(advertisedDevice);
|
||||
NIMBLE_LOGI(LOG_TAG, "New advertiser: %s", advertisedAddress.toString().c_str());
|
||||
} else if (advertisedDevice != nullptr) {
|
||||
} else if(advertisedDevice != nullptr) {
|
||||
NIMBLE_LOGI(LOG_TAG, "Updated advertiser: %s", advertisedAddress.toString().c_str());
|
||||
} else {
|
||||
// Scan response from unknown device
|
||||
@@ -129,14 +108,14 @@ NimBLEScan::~NimBLEScan() {
|
||||
}
|
||||
|
||||
advertisedDevice->m_timestamp = time(nullptr);
|
||||
advertisedDevice->setRSSI(disc.rssi);
|
||||
advertisedDevice->setPayload(disc.data, disc.length_data, (isLegacyAdv &&
|
||||
event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP));
|
||||
advertisedDevice->setRSSI(event->disc.rssi);
|
||||
advertisedDevice->setPayload(event->disc.data, event->disc.length_data,
|
||||
event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP);
|
||||
|
||||
if (pScan->m_pAdvertisedDeviceCallbacks) {
|
||||
// If not active scanning or scan response is not available
|
||||
// or extended advertisement scanning, report the result to the callback now.
|
||||
if(pScan->m_scan_params.passive || !isLegacyAdv ||
|
||||
// report the result to the callback now.
|
||||
if(pScan->m_scan_params.passive ||
|
||||
(advertisedDevice->getAdvType() != BLE_HCI_ADV_TYPE_ADV_IND &&
|
||||
advertisedDevice->getAdvType() != BLE_HCI_ADV_TYPE_ADV_SCAN_IND))
|
||||
{
|
||||
@@ -144,7 +123,7 @@ NimBLEScan::~NimBLEScan() {
|
||||
pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
|
||||
|
||||
// Otherwise, wait for the scan response so we can report the complete data.
|
||||
} else if (isLegacyAdv && event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
|
||||
} else if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
|
||||
advertisedDevice->m_callbackSent = true;
|
||||
pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
|
||||
}
|
||||
@@ -180,7 +159,7 @@ NimBLEScan::~NimBLEScan() {
|
||||
|
||||
if(pScan->m_pTaskData != nullptr) {
|
||||
pScan->m_pTaskData->rc = event->disc_complete.reason;
|
||||
NimBLEDevice::taskComplete(pScan->m_pTaskData , 0);
|
||||
xTaskNotifyGive(pScan->m_pTaskData->task);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -325,28 +304,9 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul
|
||||
m_ignoreResults = true;
|
||||
}
|
||||
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
ble_gap_ext_disc_params scan_params;
|
||||
scan_params.passive = m_scan_params.passive;
|
||||
scan_params.itvl = m_scan_params.itvl;
|
||||
scan_params.window = m_scan_params.window;
|
||||
int rc = ble_gap_ext_disc(NimBLEDevice::m_own_addr_type,
|
||||
duration/10,
|
||||
0,
|
||||
m_scan_params.filter_duplicates,
|
||||
m_scan_params.filter_policy,
|
||||
m_scan_params.limited,
|
||||
&scan_params,
|
||||
&scan_params,
|
||||
NimBLEScan::handleGapEvent,
|
||||
NULL);
|
||||
#else
|
||||
int rc = ble_gap_disc(NimBLEDevice::m_own_addr_type,
|
||||
duration,
|
||||
&m_scan_params,
|
||||
NimBLEScan::handleGapEvent,
|
||||
NULL);
|
||||
#endif
|
||||
int rc = ble_gap_disc(NimBLEDevice::m_own_addr_type, duration, &m_scan_params,
|
||||
NimBLEScan::handleGapEvent, this);
|
||||
|
||||
switch(rc) {
|
||||
case 0:
|
||||
if(!is_continue) {
|
||||
@@ -397,12 +357,16 @@ NimBLEScanResults NimBLEScan::start(uint32_t duration, bool is_continue) {
|
||||
NIMBLE_LOGW(LOG_TAG, "Blocking scan called with duration = forever");
|
||||
}
|
||||
|
||||
//TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||
ble_task_data_t taskData = {nullptr, nullptr, -1, nullptr};
|
||||
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||
ble_task_data_t taskData = {nullptr, cur_task, 0, nullptr};
|
||||
m_pTaskData = &taskData;
|
||||
|
||||
if(start(duration, nullptr, is_continue)) {
|
||||
NimBLEDevice::taskWait(&taskData, 10 * 1000);
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
}
|
||||
|
||||
m_pTaskData = nullptr;
|
||||
@@ -432,7 +396,7 @@ bool NimBLEScan::stop() {
|
||||
}
|
||||
|
||||
if(m_pTaskData != nullptr) {
|
||||
NimBLEDevice::taskComplete(m_pTaskData, 0);
|
||||
xTaskNotifyGive(m_pTaskData->task);
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< stop()");
|
||||
|
||||
@@ -42,9 +42,7 @@ NimBLEServer::NimBLEServer() {
|
||||
// m_svcChgChrHdl = 0xffff; // Future Use
|
||||
m_pServerCallbacks = &defaultCallbacks;
|
||||
m_gattsStarted = false;
|
||||
#if !CONFIG_BT_NIMBLE_EXT_ADV
|
||||
m_advertiseOnDisconnect = true;
|
||||
#endif
|
||||
m_svcChanged = false;
|
||||
m_deleteCallbacks = true;
|
||||
} // NimBLEServer
|
||||
@@ -141,26 +139,15 @@ NimBLEService *NimBLEServer::getServiceByHandle(uint16_t handle) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
/**
|
||||
* @brief Retrieve the advertising object that can be used to advertise the existence of the server.
|
||||
* @return An advertising object.
|
||||
*/
|
||||
NimBLEExtAdvertising* NimBLEServer::getAdvertising() {
|
||||
return NimBLEDevice::getAdvertising();
|
||||
} // getAdvertising
|
||||
#endif
|
||||
|
||||
#if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
|
||||
/**
|
||||
* @brief Retrieve the advertising object that can be used to advertise the existence of the server.
|
||||
*
|
||||
* @return An advertising object.
|
||||
*/
|
||||
NimBLEAdvertising* NimBLEServer::getAdvertising() {
|
||||
return NimBLEDevice::getAdvertising();
|
||||
} // getAdvertising
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sends a service changed notification and resets the GATT server.
|
||||
@@ -253,7 +240,6 @@ int NimBLEServer::disconnect(uint16_t connId, uint8_t reason) {
|
||||
} // disconnect
|
||||
|
||||
|
||||
#if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
|
||||
/**
|
||||
* @brief Set the server to automatically start advertising when a client disconnects.
|
||||
* @param [in] aod true == advertise, false == don't advertise.
|
||||
@@ -261,7 +247,7 @@ int NimBLEServer::disconnect(uint16_t connId, uint8_t reason) {
|
||||
void NimBLEServer::advertiseOnDisconnect(bool aod) {
|
||||
m_advertiseOnDisconnect = aod;
|
||||
} // advertiseOnDisconnect
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the number of connected clients.
|
||||
@@ -339,7 +325,7 @@ NimBLEConnInfo NimBLEServer::getPeerIDInfo(uint16_t id) {
|
||||
*/
|
||||
/*STATIC*/
|
||||
int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||
NimBLEServer* server = NimBLEDevice::getServer();
|
||||
NimBLEServer* server = (NimBLEServer*)arg;
|
||||
NIMBLE_LOGD(LOG_TAG, ">> handleGapEvent: %s",
|
||||
NimBLEUtils::gapEventToString(event->type));
|
||||
int rc = 0;
|
||||
@@ -351,9 +337,7 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||
if (event->connect.status != 0) {
|
||||
/* Connection failed; resume advertising */
|
||||
NIMBLE_LOGE(LOG_TAG, "Connection failed");
|
||||
#if !CONFIG_BT_NIMBLE_EXT_ADV
|
||||
NimBLEDevice::startAdvertising();
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
server->m_connectedPeersVec.push_back(event->connect.conn_handle);
|
||||
@@ -398,11 +382,9 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||
server->m_pServerCallbacks->onDisconnect(server);
|
||||
server->m_pServerCallbacks->onDisconnect(server, &event->disconnect.conn);
|
||||
|
||||
#if !CONFIG_BT_NIMBLE_EXT_ADV
|
||||
if(server->m_advertiseOnDisconnect) {
|
||||
server->startAdvertising();
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
} // BLE_GAP_EVENT_DISCONNECT
|
||||
|
||||
@@ -490,15 +472,11 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||
return 0;
|
||||
} // BLE_GAP_EVENT_NOTIFY_TX
|
||||
|
||||
|
||||
case BLE_GAP_EVENT_ADV_COMPLETE:
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
case BLE_GAP_EVENT_SCAN_REQ_RCVD:
|
||||
return NimBLEExtAdvertising::handleGapEvent(event, arg);
|
||||
#else
|
||||
return NimBLEAdvertising::handleGapEvent(event, arg);
|
||||
#endif
|
||||
// BLE_GAP_EVENT_ADV_COMPLETE | BLE_GAP_EVENT_SCAN_REQ_RCVD
|
||||
case BLE_GAP_EVENT_ADV_COMPLETE: {
|
||||
NIMBLE_LOGD(LOG_TAG, "Advertising Complete");
|
||||
NimBLEDevice::getAdvertising()->advCompleteCB();
|
||||
return 0;
|
||||
}
|
||||
|
||||
case BLE_GAP_EVENT_CONN_UPDATE: {
|
||||
NIMBLE_LOGD(LOG_TAG, "Connection parameters updated.");
|
||||
@@ -675,9 +653,7 @@ void NimBLEServer::removeService(NimBLEService* service, bool deleteSvc) {
|
||||
|
||||
service->m_removed = deleteSvc ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE;
|
||||
serviceChanged();
|
||||
#if !CONFIG_BT_NIMBLE_EXT_ADV
|
||||
NimBLEDevice::getAdvertising()->removeServiceUUID(service->getUUID());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -740,52 +716,22 @@ void NimBLEServer::resetGATT() {
|
||||
}
|
||||
|
||||
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
/**
|
||||
* @brief Start advertising.
|
||||
* @param [in] inst_id The extended advertisement instance ID to start.
|
||||
* @param [in] duration How long to advertise for in milliseconds, 0 = forever (default).
|
||||
* @param [in] max_events Maximum number of advertisement events to send, 0 = no limit (default).
|
||||
* @return True if advertising started successfully.
|
||||
* @details Start the server advertising its existence. This is a convenience function and is equivalent to
|
||||
*
|
||||
* Start the server advertising its existence. This is a convenience function and is equivalent to
|
||||
* retrieving the advertising object and invoking start upon it.
|
||||
*/
|
||||
bool NimBLEServer::startAdvertising(uint8_t inst_id,
|
||||
int duration,
|
||||
int max_events) {
|
||||
return getAdvertising()->start(inst_id, duration, max_events);
|
||||
void NimBLEServer::startAdvertising() {
|
||||
NimBLEDevice::startAdvertising();
|
||||
} // startAdvertising
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convenience function to stop advertising a data set.
|
||||
* @param [in] inst_id The extended advertisement instance ID to stop advertising.
|
||||
* @return True if advertising stopped successfully.
|
||||
*/
|
||||
bool NimBLEServer::stopAdvertising(uint8_t inst_id) {
|
||||
return getAdvertising()->stop(inst_id);
|
||||
} // stopAdvertising
|
||||
#endif
|
||||
|
||||
#if !CONFIG_BT_NIMBLE_EXT_ADV|| defined(_DOXYGEN_)
|
||||
/**
|
||||
* @brief Start advertising.
|
||||
* @return True if advertising started successfully.
|
||||
* @details Start the server advertising its existence. This is a convenience function and is equivalent to
|
||||
* retrieving the advertising object and invoking start upon it.
|
||||
*/
|
||||
bool NimBLEServer::startAdvertising() {
|
||||
return getAdvertising()->start();
|
||||
} // startAdvertising
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Stop advertising.
|
||||
* @return True if advertising stopped successfully.
|
||||
*/
|
||||
bool NimBLEServer::stopAdvertising() {
|
||||
return getAdvertising()->stop();
|
||||
void NimBLEServer::stopAdvertising() {
|
||||
NimBLEDevice::stopAdvertising();
|
||||
} // stopAdvertising
|
||||
|
||||
|
||||
|
||||
@@ -25,11 +25,7 @@
|
||||
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLEAddress.h"
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
#include "NimBLEExtAdvertising.h"
|
||||
#else
|
||||
#include "NimBLEAdvertising.h"
|
||||
#endif
|
||||
#include "NimBLEService.h"
|
||||
#include "NimBLESecurity.h"
|
||||
#include "NimBLEConnInfo.h"
|
||||
@@ -50,19 +46,11 @@ public:
|
||||
NimBLEService* createService(const NimBLEUUID &uuid);
|
||||
void removeService(NimBLEService* service, bool deleteSvc = false);
|
||||
void addService(NimBLEService* service);
|
||||
NimBLEAdvertising* getAdvertising();
|
||||
void setCallbacks(NimBLEServerCallbacks* pCallbacks,
|
||||
bool deleteCallbacks = true);
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
NimBLEExtAdvertising* getAdvertising();
|
||||
bool startAdvertising(uint8_t inst_id,
|
||||
int duration = 0,
|
||||
int max_events = 0);
|
||||
bool stopAdvertising(uint8_t inst_id);
|
||||
#else
|
||||
NimBLEAdvertising* getAdvertising();
|
||||
bool startAdvertising();
|
||||
#endif
|
||||
bool stopAdvertising();
|
||||
void startAdvertising();
|
||||
void stopAdvertising();
|
||||
void start();
|
||||
NimBLEService* getServiceByUUID(const char* uuid, uint16_t instanceId = 0);
|
||||
NimBLEService* getServiceByUUID(const NimBLEUUID &uuid, uint16_t instanceId = 0);
|
||||
@@ -78,9 +66,7 @@ public:
|
||||
NimBLEConnInfo getPeerInfo(size_t index);
|
||||
NimBLEConnInfo getPeerInfo(const NimBLEAddress& address);
|
||||
NimBLEConnInfo getPeerIDInfo(uint16_t id);
|
||||
#if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
|
||||
void advertiseOnDisconnect(bool);
|
||||
#endif
|
||||
|
||||
private:
|
||||
NimBLEServer();
|
||||
@@ -89,15 +75,9 @@ private:
|
||||
friend class NimBLEService;
|
||||
friend class NimBLEDevice;
|
||||
friend class NimBLEAdvertising;
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
friend class NimBLEExtAdvertising;
|
||||
friend class NimBLEExtAdvertisementData;
|
||||
#endif
|
||||
|
||||
bool m_gattsStarted;
|
||||
#if !CONFIG_BT_NIMBLE_EXT_ADV
|
||||
bool m_advertiseOnDisconnect;
|
||||
#endif
|
||||
bool m_svcChanged;
|
||||
NimBLEServerCallbacks* m_pServerCallbacks;
|
||||
bool m_deleteCallbacks;
|
||||
|
||||
@@ -256,11 +256,10 @@ uint16_t NimBLEService::getHandle() {
|
||||
* @brief Create a new BLE Characteristic associated with this service.
|
||||
* @param [in] uuid - The UUID of the characteristic.
|
||||
* @param [in] properties - The properties of the characteristic.
|
||||
* @param [in] max_len - The maximum length in bytes that the characteristic value can hold.
|
||||
* @return The new BLE characteristic.
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEService::createCharacteristic(const char* uuid, uint32_t properties, uint16_t max_len) {
|
||||
return createCharacteristic(NimBLEUUID(uuid), properties, max_len);
|
||||
NimBLECharacteristic* NimBLEService::createCharacteristic(const char* uuid, uint32_t properties) {
|
||||
return createCharacteristic(NimBLEUUID(uuid), properties);
|
||||
}
|
||||
|
||||
|
||||
@@ -268,11 +267,10 @@ NimBLECharacteristic* NimBLEService::createCharacteristic(const char* uuid, uint
|
||||
* @brief Create a new BLE Characteristic associated with this service.
|
||||
* @param [in] uuid - The UUID of the characteristic.
|
||||
* @param [in] properties - The properties of the characteristic.
|
||||
* @param [in] max_len - The maximum length in bytes that the characteristic value can hold.
|
||||
* @return The new BLE characteristic.
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid, uint32_t properties, uint16_t max_len) {
|
||||
NimBLECharacteristic* pCharacteristic = new NimBLECharacteristic(uuid, properties, max_len, this);
|
||||
NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid, uint32_t properties) {
|
||||
NimBLECharacteristic* pCharacteristic = new NimBLECharacteristic(uuid, properties, this);
|
||||
|
||||
if (getCharacteristic(uuid) != nullptr) {
|
||||
NIMBLE_LOGD(LOG_TAG, "<< Adding a duplicate characteristic with UUID: %s",
|
||||
|
||||
@@ -50,14 +50,12 @@ public:
|
||||
NimBLECharacteristic* createCharacteristic(const char* uuid,
|
||||
uint32_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
|
||||
NIMBLE_PROPERTY::WRITE);
|
||||
|
||||
NimBLECharacteristic* createCharacteristic(const NimBLEUUID &uuid,
|
||||
uint32_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
|
||||
NIMBLE_PROPERTY::WRITE);
|
||||
|
||||
void addCharacteristic(NimBLECharacteristic* pCharacteristic);
|
||||
void removeCharacteristic(NimBLECharacteristic* pCharacteristic, bool deleteChr = false);
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
|
||||
typedef struct {
|
||||
void *pATT;
|
||||
void * task;
|
||||
TaskHandle_t task;
|
||||
int rc;
|
||||
void *buf;
|
||||
std::string *buf;
|
||||
} ble_task_data_t;
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "nimconfig_rename.h"
|
||||
@@ -26,13 +25,6 @@
|
||||
#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER
|
||||
#endif
|
||||
|
||||
/* Enables the use of Arduino String class for attribute values */
|
||||
#if defined __has_include
|
||||
# if __has_include (<Arduino.h>)
|
||||
# define NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
|
||||
#ifdef _DOXYGEN_
|
||||
@@ -40,22 +32,6 @@
|
||||
/** @brief Un-comment to change the number of simultaneous connections (esp controller max is 9) */
|
||||
#define CONFIG_BT_NIMBLE_MAX_CONNECTIONS 3
|
||||
|
||||
/** @brief Un-comment to enable storing the timestamp when an attribute value is updated\n
|
||||
* This allows for checking the last update time using getTimeStamp() or getValue(time_t*)\n
|
||||
* If disabled, the timestamp returned from these functions will be 0.\n
|
||||
* Disabling timestamps will reduce the memory used for each value.\n
|
||||
* 1 = Enabled, 0 = Disabled; Default = Disabled
|
||||
*/
|
||||
#define CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED 0
|
||||
|
||||
/** @brief Uncomment to set the default allocation size (bytes) for each attribute if\n
|
||||
* not specified when the constructor is called. This is also the size used when a remote\n
|
||||
* characteristic or descriptor is constructed before a value is read/notifed.\n
|
||||
* Increasing this will reduce reallocations but increase memory footprint.\n
|
||||
* Default value is 20. Range: 1 : 512 (BLE_ATT_ATTR_MAX_LEN)
|
||||
*/
|
||||
#define CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH 20
|
||||
|
||||
/** @brief Un-comment to change the default MTU size */
|
||||
#define CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU 255
|
||||
|
||||
@@ -139,15 +115,3 @@
|
||||
#define CONFIG_BT_NIMBLE_TASK_STACK_SIZE 4096
|
||||
|
||||
#endif // _DOXYGEN_
|
||||
|
||||
#else
|
||||
#include "syscfg/syscfg.h"
|
||||
#define CONFIG_BT_ENABLED
|
||||
#define CONFIG_BT_NIMBLE_ROLE_OBSERVER
|
||||
#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER
|
||||
#define CONFIG_BT_NIMBLE_ROLE_CENTRAL
|
||||
#define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
|
||||
#define CONFIG_NIMBLE_CPP_IDF
|
||||
#define CONFIG_BT_NIMBLE_MAX_CONNECTIONS 3
|
||||
#define CONFIG_NIMBLE_CPP_LOG_LEVEL 0
|
||||
#endif
|
||||
Reference in New Issue
Block a user