Update documentation.

This commit is contained in:
h2zero 2020-08-20 16:07:07 -06:00
parent 88562bb310
commit 3b81d93d31
6 changed files with 396 additions and 281 deletions

View file

@ -42,7 +42,9 @@ Call `NimBLEDevice::init("");` in `app_main`.
# Using # Using
This library is intended to be compatible with the original ESP32 BLE functions and types with minor changes. This library is intended to be compatible with the original ESP32 BLE functions and types with minor changes.
See: [The migration guide](docs/Migration_guide.md) for details. If you have not used the original Bluedroid library please refer to the [New user guide](docs/New_user_guide.md).
If you are familiar with the original library, see: [The migration guide](docs/Migration_guide.md) for details about breaking changes and migration.
Also see [Improvements_and_updates](docs/Improvements_and_updates.md) for information about non-breaking changes. Also see [Improvements_and_updates](docs/Improvements_and_updates.md) for information about non-breaking changes.
@ -57,8 +59,5 @@ Also see [Improvements_and_updates](docs/Improvements_and_updates.md) for inform
# Todo # Todo
1. Implement random addresses. 1. Implement random addresses.
2. Implement NimBLEServer::removeService 2. Add BLE Mesh code.
3. Implement extra fields in NimBLEAdvertisedDevice.
4. Document nimconfig.
5. Add BLE Mesh code.
<br/> <br/>

View file

@ -1,238 +0,0 @@
# Breaking API Changes vs Original
<br/>
# Server API differnces
### Characteristics
When creating a characteristic the properties are now set with `NIMBLE_PROPERTY::XXXX` instead of `BLECharacteristic::XXXX`.
#### Originally
> BLECharacteristic::PROPERTY_READ |
> BLECharacteristic::PROPERTY_WRITE
#### Is Now
> NIMBLE_PROPERTY::READ |
> NIMBLE_PROPERTY::WRITE
<br/>
#### The full list of properties
> NIMBLE_PROPERTY::READ
> NIMBLE_PROPERTY::READ_ENC
> NIMBLE_PROPERTY::READ_AUTHEN
> NIMBLE_PROPERTY::READ_AUTHOR
> NIMBLE_PROPERTY::WRITE
> NIMBLE_PROPERTY::WRITE_NR
> NIMBLE_PROPERTY::WRITE_ENC
> NIMBLE_PROPERTY::WRITE_AUTHEN
> NIMBLE_PROPERTY::WRITE_AUTHOR
> NIMBLE_PROPERTY::BROADCAST
> NIMBLE_PROPERTY::NOTIFY
> NIMBLE_PROPERTY::INDICATE
<br/>
### Descriptors
Descriptors are now created using the `NimBLECharacteristic::createDescriptor()` method.
The previous method `BLECharacteristic::addDescriptor()` has been removed.
0x2902 Descriptor class: formerly known as BLE2902 or NimBLE2902 has been removed.
It was no longer useful as a new callback `NimBLECharacteristicCallbacks::onSubscribe` was added
to handle callback functionality and the client subscription status is handled internally.
NimBLE automatically creates the 0x2902 descriptor if a characteristic has a notification or indication property assigned to it.
**Note** Attempting to create a 0x2902 descriptor will trigger an assert to notify the error,
allowing the creation of it would cause a fault in the NimBLE stack.
All other descriptors are now created just as characteristics are by using the `NimBLECharacteristic::createDescriptor` methods (except 0x2904, see below).
Which are defined as:
```
NimBLEDescriptor* createDescriptor(const char* uuid,
uint32_t properties =
NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE,
uint16_t max_len = 100);
NimBLEDescriptor* createDescriptor(NimBLEUUID uuid,
uint32_t properties =
NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE,
uint16_t max_len = 100);
```
##### Example
```
pDescriptor = pCharacteristic->createDescriptor("ABCD",
NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE |
NIMBLE_PROPERTY::WRITE_ENC,
25);
```
Would create a descriptor with the UUID 0xABCD, publicly readable but only writable if paired/bonded (encrypted) and has a max value length of 25 bytes.
<br/>
For the 0x2904, there is a special class that is created when you call `createDescriptor("2904").
The pointer returned is of the base class `NimBLEDescriptor` but the call will create the derived class of `NimBLE2904` so you must cast the returned pointer to
`NimBLE2904` to access the specific class methods.
##### Example
```
p2904 = (NimBLE2904*)pCharacteristic->createDescriptor("2904");
```
<br/>
### Server Security
Security is set on the characteristic or descriptor properties by applying one of the following:
> NIMBLE_PROPERTY::READ_ENC
> NIMBLE_PROPERTY::READ_AUTHEN
> NIMBLE_PROPERTY::READ_AUTHOR
> NIMBLE_PROPERTY::WRITE_ENC
> NIMBLE_PROPERTY::WRITE_AUTHEN
> NIMBLE_PROPERTY::WRITE_AUTHOR
When a peer wants to read or write a characteristic or descriptor with any of these properties applied
it will trigger the pairing process. By default the "just-works" pairing will be performed automatically.
This can be changed to use passkey authentication or numeric comparison. See [Security Differences](#security-differences) for details.
<br/>
# Client API Differences
The `NimBLEAdvertisedDeviceCallbacks::onResult()` method now receives a pointer to the
`NimBLEAdvertisedDevice` object instead of a copy.
`NimBLEClient::connect()` Has had it's parameters altered.
Defined as:
> NimBLEClient::connect(bool refreshServices = true);
> NimBLEClient::connect(NimBLEAdvertisedDevice\* device, bool refreshServices = true);
> NimBLEClient::connect(NimBLEAddress address, bool refreshServices = true);
<br/>
The type parameter has been removed and a new bool parameter has been added to indicate if the client should
delete the attribute database previously retrieved (if applicable) for the peripheral, default value is true.
If set to false the client will use the attribute database it retrieved from the peripheral when previously connected.
This allows for faster connections and power saving if the devices dropped connection and are reconnecting.
<br/>
> NimBLERemoteCharacteristic::writeValue();
> NimBLERemoteCharacteristic::registerForNotify();
Now return true or false to indicate success or failure so you can choose to disconnect or try again.
<br/>
> NimBLERemoteCharacteristic::registerForNotify();
Is now **deprecated**.
> NimBLERemoteCharacteristic::subscribe()
> NimBLERemoteCharacteristic::unsubscribe()
Are the new methods added to replace it.
<br/>
> NimBLERemoteCharacteristic::readUInt8()
> NimBLERemoteCharacteristic::readUInt16()
> NimBLERemoteCharacteristic::readUInt32()
> NimBLERemoteCharacteristic::readFloat()
Are **deprecated** and NimBLERemoteCharacteristic::readValue<type\>(time_t\*, bool) template added to replace them.
<br/>
> NimBLERemoteService::getCharacteristicsByHandle()
Has been removed from the API as it is no longer maintained in the library.
<br/>
> NimBLERemoteCharacteristic::readRawData()
Has been removed from the API as it stored an unnecessary copy of the data.
The user application should use NimBLERemoteCharacteristic::readValue or NimBLERemoteCharacteristic::getValue.
Then cast the returned std::string to the type they wish such as:
```
uint8_t *val = (uint8_t*)pChr->readValue().data();
```
<br/>
> NimBLEClient::getServices(bool refresh = false)
> NimBLERemoteCharacteristic::getDescriptors(bool refresh = false)
> NimBLERemoteService::getCharacteristics(bool refresh = false)
These methods now take an optional (bool) parameter and return a pointer to `std::vector` instead of `std::map`.
If passed true it will clear the respective vector and retrieve **all** the respective attributes from the peripheral.
If false(default) it will return the respective vector with the currently stored attributes.
<br/>
**Removed:** the automatic discovery of all peripheral attributes as they consumed time and resources for data
the user may not be interested in.
**Added:** NimBLEClient::discoverAttributes() for the user to discover all the peripheral attributes
to replace the the removed functionality.
<br/>
> NimBLEClient::getService()
> NimBLERemoteService::getCharacteristic()
> NimBLERemoteCharacteristic::getDescriptor()
These methods will now check the respective vectors for the attribute object and, if not found, will retrieve (only)
the specified attribute from the peripheral.
These changes allow more control for the user to manage the resources used for the attributes.
<br/>
### Client Security
The client will automatically initiate security when the peripheral responds that it's required.
The default configuration will use "just-works" pairing with no bonding, if you wish to enable bonding see below.
<br/>
# General Differences
`NimBLEAddress()` When constructing an address the constructor now takes an optional `uint8_t type` paramameter
to specify the address type. Default is (0) Public static address.
Defined as:
> NimBLEAddress(ble_addr_t address);
> NimBLEAddress(uint8_t address[6], uint8_t type = BLE_ADDR_PUBLIC);
> NimBLEAddress(const std::string &stringAddress, uint8_t type = BLE_ADDR_PUBLIC);
> NimBLEAddress(const uint64_t &address, uint8_t type = BLE_ADDR_PUBLIC);
<br/>
# Security Differences
Security callback functions are now incorporated in the NimBLEServerCallbacks / NimBLEClientCallbacks classes.
However backward compatibility with the original `BLESecurity` class is retained to minimize app code changes.
The callback methods are:
> bool onConfirmPIN(uint32_t pin);
Receives the pin when using numeric comparison authentication, `return true;` to accept.
<br/>
> uint32_t onPassKeyRequest();
For server callback; return the passkey expected from the client.
For client callback; return the passkey to send to the server.
<br/>
> void onAuthenticationComplete(ble_gap_conn_desc\* desc);
Authentication complete, success or failed information is in `desc`.
<br/>
Security settings and IO capabilities are now set by the following methods of NimBLEDevice.
> NimBLEDevice::setSecurityAuth(bool bonding, bool mitm, bool sc)
> NimBLEDevice::setSecurityAuth(uint8_t auth_req)
Sets the authorization mode for this device.
<br/>
> NimBLEDevice::setSecurityIOCap(uint8_t iocap)
Sets the Input/Output capabilities of this device.
<br/>
> NimBLEDevice::setSecurityInitKey(uint8_t init_key)
If we are the initiator of the security procedure this sets the keys we will distribute.
<br/>
> NimBLEDevice::setSecurityRespKey(uint8_t resp_key)
Sets the keys we are willing to accept from the peer during pairing.
<br/>

View file

@ -2,8 +2,8 @@
# Server # Server
NimBLECharacteristic::setValue(const T &s) `NimBLECharacteristic::setValue(const T &s)`
NimBLEDescriptor::setValue(const T &s) `NimBLEDescriptor::setValue(const T &s)`
Now use a template to accomodate standard and custom types/values. Now use a template to accomodate standard and custom types/values.
@ -27,7 +27,7 @@ struct my_struct{
``` ```
This will send the struct to the recieving client when read or a notification sent. This will send the struct to the recieving client when read or a notification sent.
NimBLECharacteristic::getValue now takes an optional timestamp parameter which will update it's value with `NimBLECharacteristic::getValue` now takes an optional timestamp parameter which will update it's value with
the time the last value was recieved. In addition an overloaded template has been added to retrieve the value the time the last value was recieved. In addition an overloaded template has been added to retrieve the value
as a type specified by the user. as a type specified by the user.
@ -53,8 +53,8 @@ using `NimBLEServer::addService`.
# Client # Client
NimBLERemoteCharacteristic::readValue(time_t\*, bool) `NimBLERemoteCharacteristic::readValue(time_t\*, bool)`
NimBLERemoteDescriptor::readValue(bool) `NimBLERemoteDescriptor::readValue(bool)`
Have been added as templates to allow reading the values as any specified type. Have been added as templates to allow reading the values as any specified type.
@ -73,14 +73,14 @@ struct my_struct{
``` ```
<br/> <br/>
NimBLERemoteCharacteristic::registerForNotify `NimBLERemoteCharacteristic::registerForNotify`
Has been **deprecated** as now the internally stored characteristic value is updated when notification/indication is recieved. Has been **deprecated** as now the internally stored characteristic value is updated when notification/indication is recieved.
NimBLERemoteCharacteristic::subscribe and NimBLERemoteCharacteristic::unsubscribe have been implemented to replace it. `NimBLERemoteCharacteristic::subscribe` and `NimBLERemoteCharacteristic::unsubscribe` have been implemented to replace it.
A callback is no longer requred to get the most recent value unless timing is important. Instead, the application can call NimBLERemoteCharacteristic::getValue to A callback is no longer requred to get the most recent value unless timing is important. Instead, the application can call `NimBLERemoteCharacteristic::getValue` to
get the last updated value any time. get the last updated value any time.
In addition NimBLERemoteCharacteristic::readValue and NimBLERemoteCharacteristic::getValue take an optional timestamp parameter which will update it's value with In addition `NimBLERemoteCharacteristic::readValue` and `NimBLERemoteCharacteristic::getValue` take an optional timestamp parameter which will update it's value with
the time the last value was recieved. the time the last value was recieved.
> NimBLEClient::getService > NimBLEClient::getService
@ -93,19 +93,19 @@ the specified attribute from the peripheral.
These changes allow more control for the user to manage the resources used for the attributes. These changes allow more control for the user to manage the resources used for the attributes.
<br/> <br/>
NimBLEClient::connect() can now be called without an address or advertised device parameter. This will connect to the `NimBLEClient::connect()` can now be called without an address or advertised device parameter. This will connect to the
device with the address previously set when last connected or set with NimBLEDevice::setPeerAddress(). device with the address previously set when last connected or set with `NimBLEDevice::setPeerAddress()`.
# General # General
To reduce resource use all instances of std::map have been replaced with std::vector. To reduce resource use all instances of std::map have been replaced with std::vector.
Use of FreeRTOS::Semaphore has been removed as it was consuming too much ram, the related files have been left in place to accomodate application use. Use of `FreeRTOS::Semaphore` has been removed as it was consuming too much ram, the related files have been left in place to accomodate application use.
Operators `==`, `!=` and `std::string` have been added to NimBLEAddress and NimBLEUUID for easier comparison and logging. Operators `==`, `!=` and `std::string` have been added to `NimBLEAddress` and `NimBLEUUID` for easier comparison and logging.
New constructor for NimBLEUUID(uint32_t, uint16_t, uint16_t, uint64_t) added to lower memory use vs string construction. See: [#21](https://github.com/h2zero/NimBLE-Arduino/pull/21). New constructor for `NimBLEUUID(uint32_t, uint16_t, uint16_t, uint64_t)` added to lower memory use vs string construction. See: [#21](https://github.com/h2zero/NimBLE-Arduino/pull/21).
Security/pairing operations are now handled in the respective NimBLEClientCallbacks and NimBLEServerCallbacks classes, NimBLESecurity(deprecated) remains for backward compatibility. Security/pairing operations are now handled in the respective `NimBLEClientCallbacks` and `NimBLEServerCallbacks` classes, `NimBLESecurity`(deprecated) remains for backward compatibility.
Configuration options have been added to add or remove debugging information, when disabled (default) significatly reduces binary size. Configuration options have been added to add or remove debugging information, when disabled (default) significatly reduces binary size.
In ESP-IDF the options are in menuconfig: `Main menu -> ESP-NimBLE-cpp configuration`. In ESP-IDF the options are in menuconfig: `Main menu -> ESP-NimBLE-cpp configuration`.

View file

@ -2,17 +2,27 @@
This guide describes the required changes to existing projects migrating from the original bluedroid API to NimBLE. This guide describes the required changes to existing projects migrating from the original bluedroid API to NimBLE.
The changes listed here are only some of the many that have been made, this is a short overview for migrating existing applications. The changes listed here are only the **required changes that must be made** and a short overview of options for migrating existing applications.
For more information on the improvements and additions please refer to the [class documentation](https://h2zero.github.io/esp-nimble-cpp/annotated.html) and [Improvements and updates](docs/Improvements_and_updates.md) For more information on the improvements and additions please refer to the [class documentation](https://h2zero.github.io/esp-nimble-cpp/annotated.html) and [Improvements and updates](Improvements_and_updates.md)
* [General Changes](#general-information)
* [Server](#server-api)
* [Services](#services)
* [characteristics](#characteristics)
* [descriptors](#descriptors)
* [Client](#client-api)
* [Remote Services](#remote-services)
* [Remote characteristics](#remote-characteristics)
* [Security](#security-api)
<br/> <br/>
# General Information # General Information {#general-information}
### Header Files ### Header Files
All classes are accessible by including `NimBLEDevice.h` in your application, no further headers need to be included. All classes are accessible by including `NimBLEDevice.h` in your application, no further headers need to be included.
You may choose to include `NimBLELog.h` in your appplication if you want to use the `NIMBLE_LOGx` macros for debugging. (Mainly for Arduino) You may choose to include `NimBLELog.h` in your appplication if you want to use the `NIMBLE_LOGx` macros for debugging.
These macros are used the same way as the `ESP_LOGx` macros. These macros are used the same way as the `ESP_LOGx` macros.
<br/> <br/>
@ -25,7 +35,7 @@ this means **no class names need to be changed in existing code** and makes migr
<br/> <br/>
### BLE Addresses ### BLE Addresses
`BLEAddress` (`NimBLEAddress`) When constructing an address the constructor now takes an *optional* `uint8_t type` paramameter `BLEAddress` (`NimBLEAddress`) When constructing an address the constructor now takes an *(optional)* `uint8_t type` paramameter
to specify the address type. Default is (0) Public static address. to specify the address type. Default is (0) Public static address.
For example `BLEAddress addr(11:22:33:44:55:66, 1)` will create the address object with an address type of: 1 (Random). For example `BLEAddress addr(11:22:33:44:55:66, 1)` will create the address object with an address type of: 1 (Random).
@ -33,7 +43,7 @@ For example `BLEAddress addr(11:22:33:44:55:66, 1)` will create the address obje
As this paramameter is optional no changes to existing code are needed, it is mentioned here for information. As this paramameter is optional no changes to existing code are needed, it is mentioned here for information.
<br/> <br/>
# Server API ## Server API {#server-api}
Creating a `BLEServer` instance is the same as original, no changes required. Creating a `BLEServer` instance is the same as original, no changes required.
For example `BLEDevice::createServer()` will work just as it did before. For example `BLEDevice::createServer()` will work just as it did before.
@ -41,11 +51,11 @@ For example `BLEDevice::createServer()` will work just as it did before.
**Note:** All callback methods have default implementations which allows the application to implement only the methods applicable. **Note:** All callback methods have default implementations which allows the application to implement only the methods applicable.
<br/> <br/>
### Services ### Services {#services}
Creating a `BLEService` (`NimBLEService`) instance is the same as original, no changes required. Creating a `BLEService` (`NimBLEService`) instance is the same as original, no changes required.
For example `BLEServer::createService(SERVICE_UUID)` will work just as it did before. For example `BLEServer::createService(SERVICE_UUID)` will work just as it did before.
### Characteristics ### Characteristics {#characteristics}
`BLEService::createCharacteristic` (`NimBLEService::createCharacteristic`) is used the same way as originally except the properties parameter has changed. `BLEService::createCharacteristic` (`NimBLEService::createCharacteristic`) is used the same way as originally except the properties parameter has changed.
When creating a characteristic the properties are now set with `NIMBLE_PROPERTY::XXXX` instead of `BLECharacteristic::XXXX`. When creating a characteristic the properties are now set with `NIMBLE_PROPERTY::XXXX` instead of `BLECharacteristic::XXXX`.
@ -97,7 +107,7 @@ BLECharacteristic *pCharacteristic = pService->createCharacteristic(
**Note:** All callback methods have default implementations which allows the application to implement only the methods applicable. **Note:** All callback methods have default implementations which allows the application to implement only the methods applicable.
<br/> <br/>
### Descriptors ### Descriptors {descriptors}
The previous method `BLECharacteristic::addDescriptor()` has been removed. The previous method `BLECharacteristic::addDescriptor()` has been removed.
Descriptors are now created using the `NimBLECharacteristic::createDescriptor` method. Descriptors are now created using the `NimBLECharacteristic::createDescriptor` method.
@ -159,10 +169,10 @@ Security is set on the characteristic or descriptor properties by applying one o
When a peer wants to read or write a characteristic or descriptor with any of these properties applied When a peer wants to read or write a characteristic or descriptor with any of these properties applied
it will trigger the pairing process. By default the "just-works" pairing will be performed automatically. it will trigger the pairing process. By default the "just-works" pairing will be performed automatically.
This can be changed to use passkey authentication or numeric comparison. See [Security Differences](#security-differences) for details. This can be changed to use passkey authentication or numeric comparison. See [Security API](#security-api) for details.
<br/> <br/>
# Client API ## Client API {#client-api}
Client instances are created just as before with `BLEDevice::createClient` (`NimBLEDevice::createClient`). Client instances are created just as before with `BLEDevice::createClient` (`NimBLEDevice::createClient`).
@ -195,19 +205,22 @@ the user may not be interested in.
to replace the the removed automatic functionality. to replace the the removed automatic functionality.
<br/> <br/>
### Remote Services ### Remote Services {#remote-services}
`BLERemoteService` (`NimBLERemoteService`) Methods remain mostly unchanged with the exceptions of: `BLERemoteService` (`NimBLERemoteService`) Methods remain mostly unchanged with the exceptions of:
> BLERemoteService::getCharacteristicsByHandle > BLERemoteService::getCharacteristicsByHandle
This method has been removed. This method has been removed.
<br/> <br/>
> `BLERemoteService::getCharacteristics` (`NimBLERemoteService::getCharacteristics`) > `BLERemoteService::getCharacteristics` (`NimBLERemoteService::getCharacteristics`)
This method now takes an optional (bool) parameter to indicate if the characteristics should be retrieved from the server (true) or This method now takes an optional (bool) parameter to indicate if the characteristics should be retrieved from the server (true) or
the currently known database returned (false : default). the currently known database returned (false : default).
Also now returns a pointer to `std::vector` instead of `std::map`. Also now returns a pointer to `std::vector` instead of `std::map`.
<br/> <br/>
### Remote Characteristics ### Remote Characteristics{#remote-characteristics}
`BLERemoteCharacteristic` (`NimBLERemoteCharacteristic`) There have been a few changes to the methods in this class: `BLERemoteCharacteristic` (`NimBLERemoteCharacteristic`) There have been a few changes to the methods in this class:
> `BLERemoteCharacteristic::writeValue` (`NimBLERemoteCharacteristic::writeValue`) > `BLERemoteCharacteristic::writeValue` (`NimBLERemoteCharacteristic::writeValue`)
@ -241,6 +254,10 @@ Then cast the returned std::string to the type they wish such as:
``` ```
uint8_t *val = (uint8_t*)pChr->readValue().data(); uint8_t *val = (uint8_t*)pChr->readValue().data();
``` ```
Alternatively use the `readValue` template:
```
my_struct_t myStruct = pChr->readValue<my_struct_t>();
```
<br/> <br/>
> `BLERemoteCharacteristic::getDescriptors` (`NimBLERemoteCharacteristic::getDescriptors`) > `BLERemoteCharacteristic::getDescriptors` (`NimBLERemoteCharacteristic::getDescriptors`)
@ -250,16 +267,16 @@ the currently known database returned (false : default).
Also now returns a pointer to `std::vector` instead of `std::map`. Also now returns a pointer to `std::vector` instead of `std::map`.
<br/> <br/>
### Client Security ### Client Security {#client-security}
The client will automatically initiate security when the peripheral responds that it's required. The client will automatically initiate security when the peripheral responds that it's required.
The default configuration will use "just-works" pairing with no bonding, if you wish to enable bonding see below. The default configuration will use "just-works" pairing with no bonding, if you wish to enable bonding see below.
<br/> <br/>
# Security API ## Security API {#security-api}
Security operations have been moved to `BLEDevice` (`NimBLEDevice`). Security operations have been moved to `BLEDevice` (`NimBLEDevice`).
Also security callback methods are now incorporated in the NimBLEServerCallbacks / NimBLEClientCallbacks classes. Also security callback methods are now incorporated in the NimBLEServerCallbacks / NimBLEClientCallbacks classes.
However backward compatibility with the original `BLESecurity` (`NimBLESecurity`) class is retained to minimize app code changes. However backward compatibility with the original `BLESecurity` (`NimBLESecurity`) class is retained to minimize application code changes.
The callback methods are: The callback methods are:

337
docs/New_user_guide.md Normal file
View file

@ -0,0 +1,337 @@
# New User Guide
**Note:** If you are migrating an existing project from the original Bluedroid library please see the [Migration Guide.](Migration_guide.md)
If you are a new user this will guide you through a simple server and client application.
* [Creating a Server](#creating-a-server)
* [Creating a Client](#creating-a-client)
<br/>
## Include Files
At the top of your application file add `#include NimBLEDevice.h`, this is the only header required and provides access to all classes.
<br/>
## Using the Library
In order to perform any BLE tasks you must first initialize the library, this prepares the NimBLE stack to be ready for commands.
To do this you must call `NimBLEDevice::init("your device name here")`, the parameter passed is a character string containing the name you want to advertise.
If you're not creating a server or do not want to advertise a name, simply pass an empty string for the parameter.
This can be called any time you wish to use BLE functions and does not need to be called from app_main(IDF) or setup(Arduino) but usually is.
<br/>
## Creating a Server {#creating-a-server}
BLE servers perform 2 tasks, they advertise their existance for clients to find them and they provide services which contain information for the connecting client.
After initializing the NimBLE stack we create a server by calling `NimBLEDevice::createServer()`, this will create a server instance and return a pointer to it.
Once we have created the server we need to tell it the services it hosts.
To do this we call `NimBLEServer::createService(const char* uuid)`. Which returns a pointer to an instance of `NimBLEService`.
The `uuid` parameter is a hexadecimal string with the uuid we want to give the service, it can be 16, 32, or 128 bits.
For this example we will keep it simple and use a 16 bit value: ABCD.
<br/>
**Example code:**
```
#include "NimBLEDevice.h"
// void setup() in Arduino
void app_main(void)
{
NimBLEDevice::init("NimBLE");
NimBLEServer *pServer = NimBLEDevice::createServer();
NimBLEService *pService = pServer->createService("ABCD");
}
```
Now we have NimBLE initialized, a server created and a service assigned to it.
We can't do much with this yet so now we should add a characteristic to the service to provide some data.
Next we call `NimBLEService::createCharacteristic` which returns a pointer to an instance of `NimBLECharacteristic`, and takes two parameters:
A `uuid` to specify the UUID of the characteristic and a bitmask of the properties we want applied to it.
Just as with the service UUID we will use a simple 16 bit value: 1234.
The properties bitmask is a little more involved. It is a combination of NIMBLE_PROPERTY:: values.
Here is the list of options:
> NIMBLE_PROPERTY\::READ
> NIMBLE_PROPERTY\::READ_ENC
> NIMBLE_PROPERTY\::READ_AUTHEN
> NIMBLE_PROPERTY\::READ_AUTHOR
> NIMBLE_PROPERTY\::WRITE
> NIMBLE_PROPERTY\::WRITE_NR
> NIMBLE_PROPERTY\::WRITE_ENC
> NIMBLE_PROPERTY\::WRITE_AUTHEN
> NIMBLE_PROPERTY\::WRITE_AUTHOR
> NIMBLE_PROPERTY\::BROADCAST
> NIMBLE_PROPERTY\::NOTIFY
> NIMBLE_PROPERTY\::INDICATE
For this example we won't need to specify these as the default value is `NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE`
which will allow reading and writing values to the characteristic without encryption or security.
The function call will simply be `pService->createCharacteristic("1234");`
<br/>
**Our example code now is:**
```
#include "NimBLEDevice.h"
// void setup() in Arduino
void app_main(void)
{
NimBLEDevice::init("NimBLE");
NimBLEServer *pServer = NimBLEDevice::createServer();
NimBLEService *pService = pServer->createService("ABCD");
NimBLECharacteristic *pCharacteristic = pService->createCharacteristic("1234");
}
```
All that's left to do now is start the sevice, give the characteristic a value and start advertising for clients.
Fist we start the service by calling `NimBLEService::start()`.
Next we need to call `NimBLECharacteristic::setValue` to set the characteristic value that the client will read.
There are many different types you can send as parameters for the value but for this example we will use a simple string.
`pCharacteristic->setValue("Hello BLE");`
Next we need to advertise for connections.
To do this we create an instance of `NimBLEAdvertising` add our service to it (optional) and start advertisng.
**The code for this will be:**
```
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising(); // create advertising instance
pAdvertising->addServiceUUID("ABCD"); // tell advertising the UUID of our service
pAdvertising->start(); // start advertising
```
That's it, this will be enough to create a BLE server with a service and a characteristic and advertise for client connections.
**The full example code:**
```
#include "NimBLEDevice.h"
// void setup() in Arduino
void app_main(void)
{
NimBLEDevice::init("NimBLE");
NimBLEServer *pServer = NimBLEDevice::createServer();
NimBLEService *pService = pServer->createService("ABCD");
NimBLECharacteristic *pCharacteristic = pService->createCharacteristic("1234");
pService->start();
pCharacteristic->setValue("Hello BLE");
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
pAdvertising->addServiceUUID("ABCD");
pAdvertising->start();
}
```
Now if you scan with your phone using nRFConnect or any other BLE app you should see a device named "NimBLE" with a service of "ABCD".
For more advanced features and options please see the server examples in the examples folder.
<br/>
## Creating a Client {#creating-a-client}
BLE clients perform 2 tasks, they scan for advertising servers and form connections to them to read and write to their characteristics/descriptors.
After initializing the NimBLE stack we create a scan instance by calling `NimBLEDevice::getScan()`, this will create a `NimBLEScan` instance and return a pointer to it.
Once we have created the scan we can start looking for advertising servers.
To do this we call `NimBLEScan::start(duration)`, the duration parameter is a uint32_t that specifies the number of seconds to scan for,
passing 0 will scan forever.
In this example we will scan for 10 seconds. This is a blocking function (a non blocking overload is also available).
This call returns an instance of `NimBLEScanResults` when the scan completes which can be parsed for advertisers we are interested in.
**Example Code:**
```
#include "NimBLEDevice.h"
// void setup() in Arduino
void app_main(void)
{
NimBLEDevice::init("");
NimBLEScan *pScan = NimBLEDevice::getScan();
NimBLEScanResults results = pScan->start(10);
}
```
<br/>
Now that we have scanned we need to check the results for any advertisers we are interested in connecting to.
To do this we iterate through the results and check if any of the devices found are advertising the service we want `ABCD`.
Each result in `NimBLEScanResults` is a `NimBLEAdvertisedDevice` instance that we can access data from.
We will check each device found for the `ABCD` service by calling `NimBLEAdvertisedDevice::isAdvertisingService`.
This takes an instance of `NimBLEUUID` as a parameter so we will need to create one.
**The code for this looks like:**
```
NimBLEUUID serviceUuid("ABCD");
for(int i = 0; i < results.getCount(); i++) {
NimBLEAdvertisedDevice device = results.getDevice(i);
if (device.isAdvertisingService(serviceUuid)) {
// create a client and connect
}
}
```
<br/>
Now that we can scan and parse advertisers we need to be able to create a `NimBLEClient` instance and use it to connect.
To do this we call `NimBLEDevice::createClient` which creates the `NimBLEClient` instance and returns a pointer to it.
After this we call `NimBLEClient::connect` to connect to the advertiser.
This takes a pointer to the `NimBLEAdvertisedDevice` and returns `true` if successful.
**Lets do that now:**
```
NimBLEUUID serviceUuid("ABCD");
for(int i = 0; i < results.getCount(); i++) {
NimBLEAdvertisedDevice device = results.getDevice(i);
if (device.isAdvertisingService(serviceUuid)) {
NimBLEClient *pClient = NimBLEDevice::createClient();
if(pClient->connect(&device)) {
//success
} else {
// failed to connect
}
}
}
```
As shown, the call to `NimBLEClient::connect` should have it's eturn value tested to make sure it succeeded before proceeding to get data.
<br/>
Next we need to access the servers data by asking it for the service and the characteristic we are interested in, then read the characteristic value.
To do this we call `NimBLEClient::getService`, which takes as a parameter the UUID of the service and returns
a pointer an instance to `NimBLERemoteService` or `nullptr` if the service was not found.
Next we will call `NimBLERemoteService::getCharateristic` which takes as a parameter the UUID of the service and returns
a pointer to an instance of `NimBLERemoteCharacteristic` or `nullptr` if not found.
Finally we will read the characteristic value with `NimBLERemoteCharacteristic::readValue()`.
**Here is what that looks like:**
```
NimBLEUUID serviceUuid("ABCD");
for(int i = 0; i < results.getCount(); i++) {
NimBLEAdvertisedDevice device = results.getDevice(i);
if (device.isAdvertisingService(serviceUuid)) {
NimBLEClient *pClient = NimBLEDevice::createClient();
if (pClient->connect(&device)) {
NimBLERemoteService *pService = pClient->getService(serviceUuid);
if (pService != nullptr) {
NimBLERemoteCharacteristic *pCharacteristic = pService->getCharacteristic("1234");
if (pCharacteristic != nullptr) {
std::string value = pCharacteristic->readValue();
// print or do whatever you need with the value
}
}
} else {
// failed to connect
}
}
}
```
<br/>
The last thing we should do is clean up once we are done with the connection.
Because multiple clients are supported and can be created we should delete them when finished with them to conserve resources.
This is done by calling `NimBLEDevice::deleteClient`.
**Lets add that now:**
```
NimBLEUUID serviceUuid("ABCD");
for(int i = 0; i < results.getCount(); i++) {
NimBLEAdvertisedDevice device = results.getDevice(i);
if (device.isAdvertisingService(serviceUuid)) {
NimBLEClient *pClient = NimBLEDevice::createClient();
if (pClient->connect(&device)) {
NimBLERemoteService *pService = pClient->getService(serviceUuid);
if (pService != nullptr) {
NimBLERemoteCharacteristic *pCharacteristic = pService->getCharacteristic("1234");
if (pCharacteristic != nullptr) {
std::string value = pCharacteristic->readValue();
// print or do whatever you need with the value
}
}
} else {
// failed to connect
}
NimBLEDevice::deleteClient(pClient);
}
}
```
Note that there is no need to disconnect as that will be done when deleting the client instance.
<br/>
**Here is the full example code:**
```
#include "NimBLEDevice.h"
// void setup() in Arduino
void app_main(void)
{
NimBLEDevice::init("");
NimBLEScan *pScan = NimBLEDevice::getScan();
NimBLEScanResults results = pScan->start(10);
NimBLEUUID serviceUuid("ABCD");
for(int i = 0; i < results.getCount(); i++) {
NimBLEAdvertisedDevice device = results.getDevice(i);
if (device.isAdvertisingService(serviceUuid)) {
NimBLEClient *pClient = NimBLEDevice::createClient();
if (pClient->connect(&device)) {
NimBLERemoteService *pService = pClient->getService(serviceUuid);
if (pService != nullptr) {
NimBLERemoteCharacteristic *pCharacteristic = pService->getCharacteristic("1234");
if (pCharacteristic != nullptr) {
std::string value = pCharacteristic->readValue();
// print or do whatever you need with the value
}
}
} else {
// failed to connect
}
NimBLEDevice::deleteClient(pClient);
}
}
}
```
<br/>
For more advanced features and options please see the client examples in the examples folder.
<br/>

View file

@ -44,9 +44,9 @@ Call `NimBLEDevice::init("");` in `app_main`.
# Using # Using
This library is intended to be compatible with the original ESP32 BLE functions and types with minor changes. This library is intended to be compatible with the original ESP32 BLE functions and types with minor changes.
See: [The migration guide](docs/Migration_guide.md) for details. See: [The migration guide](Migration_guide.md) for details.
Also see [Improvements_and_updates](docs/Improvements_and_updates.md) for information about non-breaking changes. Also see [Improvements_and_updates](Improvements_and_updates.md) for information about non-breaking changes.
### Arduino specific: ### Arduino specific:
See the Refactored_original_examples in the examples folder for highlights of the differences with the original library. See the Refactored_original_examples in the examples folder for highlights of the differences with the original library.