BT serial: SSP improvements, added missing events (#8723)
* Renamed SerialToSerialBT_SSP_pairing * Clarified useage of SPP example * Added missing events * Implemented dropCache() method to remove bonded devices * Removed legacy pairing, enhaced SSP * Minor updates to examples * Updated README + asociated comments in source and example * Implemented more methods to manipulate bonded devices + modified example * Added SPP event * Reordered event to match enum declaration; added missing events; added comments * Re-implemented legacy pairing support * Spelling fixes in README * Removed unnecessary test in discover() * Updates --------- Co-authored-by: Tomas Pilny <tomas.pilny@espressif.com> Co-authored-by: Tomáš Pilný <pilnyt@seznam.cz>
This commit is contained in:
parent
6603b6ed2f
commit
02e7fd884a
23 changed files with 773 additions and 409 deletions
|
|
@ -1,19 +1,78 @@
|
|||
### Bluetooth Serial Library
|
||||
## Bluetooth Serial Library
|
||||
|
||||
A simple Serial compatible library using ESP32 classical bluetooth (SPP)
|
||||
A simple Serial compatible library using ESP32 classical Bluetooth Serial Port Profile (SPP)
|
||||
|
||||
Note: Since version 3.0.0 this library does not support legacy pairing (using fixed PIN consisting of 4 digits).
|
||||
|
||||
### How to use it?
|
||||
|
||||
#### How to use it?
|
||||
There are 3 basic use cases: phone, other ESP32 or any MCU with a Bluetooth serial module
|
||||
|
||||
- Download one bluetooth terminal app in your smartphone<br>
|
||||
For Android: https://play.google.com/store/apps/details?id=de.kai_morich.serial_bluetooth_terminal <br>
|
||||
For iOS: https://itunes.apple.com/us/app/hm10-bluetooth-serial-lite/id1030454675
|
||||
#### Phone
|
||||
|
||||
- Download one of the Bluetooth terminal apps to your smartphone
|
||||
|
||||
- For [Android](https://play.google.com/store/apps/details?id=de.kai_morich.serial_bluetooth_terminal)
|
||||
- For [iOS](https://itunes.apple.com/us/app/hm10-bluetooth-serial-lite/id1030454675)
|
||||
|
||||
- Flash an example sketch to your ESP32
|
||||
|
||||
- Scan and pair the device in your smartphone
|
||||
- Scan and pair the device to your smartphone
|
||||
|
||||
- Open the bluetooth terminal app
|
||||
- Open the Bluetooth terminal app and connect
|
||||
|
||||
- Enjoy
|
||||
|
||||
#### ESP32
|
||||
|
||||
You can flash one of the ESP32 with the example [`SerialToSerialBTM`](https://github.com/espressif/arduino-esp32/blob/master/libraries/BluetoothSerial/examples/SerialToSerialBTM/SerialToSerialBTM.ino) (the Master) and another ESP32 with [`SerialToSerialBT`](https://github.com/espressif/arduino-esp32/blob/master/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino) (the Slave).
|
||||
Those examples are preset to work out-of-the-box but they should be scalable to connect multiple Slaves to the Master.
|
||||
|
||||
#### 3rd party Serial Bluetooth module
|
||||
|
||||
Using a 3rd party Serial Bluetooth module will require to study the documentation of the particular module in order to make it work, however, one side can utilize the mentioned [`SerialToSerialBTM`](https://github.com/espressif/arduino-esp32/blob/master/libraries/BluetoothSerial/examples/SerialToSerialBTM/SerialToSerialBTM.ino) (the Master) or [`SerialToSerialBT`](https://github.com/espressif/arduino-esp32/blob/master/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino) (the Slave).
|
||||
|
||||
### Pairing options
|
||||
|
||||
There are two easy options and one difficult.
|
||||
|
||||
The easy options can be used as usual. These offer pairing with and without Secure Simple Pairing (SSP).
|
||||
|
||||
The difficult option offers legacy pairing (using fixed PIN) however this must be compiled with Arduino as an IDF component with disabled sdkconfig option `CONFIG_BT_SSP_ENABLED`.
|
||||
|
||||
#### Without SSP
|
||||
|
||||
This method will authenticate automatically any attempt to pair and should not be used if security is a concern! This option is used for the examples [`SerialToSerialBTM`](https://github.com/espressif/arduino-esp32/blob/master/libraries/BluetoothSerial/examples/SerialToSerialBTM/SerialToSerialBTM.ino) and [`SerialToSerialBT`](https://github.com/espressif/arduino-esp32/blob/master/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino).
|
||||
|
||||
### With SSP
|
||||
|
||||
The usage of SSP provides a secure connection. This option is demonstrated in the example `SerialToSerialBT_SSP``](https://github.com/espressif/arduino-esp32/blob/master/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/SerialToSerialBT_SSP.ino)
|
||||
|
||||
The Secure Simple Pairing is enabled by calling method `enableSSP` which has two variants - one is backward compatible without parameter `enableSSP()` and second with parameters `enableSSP(bool inputCapability, bool outputCapability)`. Similarly, the SSP can be disabled by calling `disableSSP()`.
|
||||
|
||||
Both options must be called before `begin()` or if it is called after `begin()` the driver needs to be restarted (call `end()` followed by `begin()`) in order to take in effect enabling or disabling the SSP.
|
||||
|
||||
#### The parameters define the method of authentication:
|
||||
|
||||
**inputCapability** - Defines if ESP32 device has input method (Serial terminal, keyboard or similar)
|
||||
|
||||
**outputCapability** - Defines if ESP32 device has output method (Serial terminal, display or similar)
|
||||
|
||||
* **inputCapability=true and outputCapability=true**
|
||||
* Both devices display randomly generated code and if they match the user will authenticate pairing on both devices.
|
||||
* This must be implemented by registering a callback via `onConfirmRequest()` and in this callback the user will input the response and call `confirmReply(true)` if the authenticated, otherwise call `confirmReply(false)` to reject the pairing.
|
||||
* **inputCapability=false and outputCapability=false**
|
||||
* Only the other device authenticates pairing without any pin.
|
||||
* **inputCapability=false and outputCapability=true**
|
||||
* Only the other device authenticates pairing without any pin.
|
||||
* **inputCapability=true and outputCapability=false**
|
||||
* The user will be required to input the passkey to the ESP32 device to authenticate.
|
||||
* This must be implemented by registering a callback via `onKeyRequest`()` and in this callback the entered passkey will be responded via `respondPasskey(passkey)`
|
||||
|
||||
### Legacy Pairing (IDF component)
|
||||
|
||||
To use Legacy pairing you will have to use [Arduino as an IDF component](https://espressif-docs.readthedocs-hosted.com/projects/arduino-esp32/en/latest/esp-idf_component.html) and disable option `CONFIG_BT_SSP_ENABLED`.
|
||||
Please refer to the documentation on how to setup Arduino as an IDF component and when you are done, run `idf.py menuconfig` navigate to `Component Config -> Bluetooth -> Bluedroid -> [ ] Secure Simple Pairing` and disable it.
|
||||
While in the menuconfig you will also need to change the partition scheme `Partition Table -> Partition Table -> (X) Single Factory app (large), no OTA`.
|
||||
After these changes save & quit menuconfig and you are ready to go: `idf.py monitor flash`.
|
||||
Please note that to use the PIN in smartphones and computers you need to use characters `SerialBT.setPin("1234", 4);` not a number `SerialBT.setPin(1234, 4);` . Numbers CAN be used if the other side uses them too, but phones and computers use characters.
|
||||
|
|
@ -19,19 +19,18 @@
|
|||
#include <BluetoothSerial.h>
|
||||
|
||||
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
|
||||
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
|
||||
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_BT_SPP_ENABLED)
|
||||
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
|
||||
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
|
||||
#endif
|
||||
|
||||
BluetoothSerial SerialBT;
|
||||
|
||||
|
||||
#define BT_DISCOVER_TIME 10000
|
||||
esp_spp_sec_t sec_mask=ESP_SPP_SEC_NONE; // or ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE to request pincode confirmation
|
||||
esp_spp_role_t role=ESP_SPP_ROLE_SLAVE; // or ESP_SPP_ROLE_MASTER
|
||||
esp_spp_sec_t sec_mask = ESP_SPP_SEC_NONE; // or ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE to request pincode confirmation
|
||||
esp_spp_role_t role = ESP_SPP_ROLE_SLAVE; // or ESP_SPP_ROLE_MASTER
|
||||
|
||||
// std::map<BTAddress, BTAdvertisedDeviceSet> btDeviceList;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@
|
|||
String device_name = "ESP32-example";
|
||||
|
||||
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
|
||||
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
|
||||
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_BT_SPP_ENABLED)
|
||||
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
|
||||
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
|
||||
#endif
|
||||
|
||||
BluetoothSerial SerialBT;
|
||||
|
|
|
|||
|
|
@ -1,22 +1,22 @@
|
|||
//This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
//By Evandro Copercini - 2018
|
||||
// This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
// By Evandro Copercini - 2018
|
||||
//
|
||||
//This example creates a bridge between Serial and Classical Bluetooth (SPP)
|
||||
//and also demonstrate that SerialBT have the same functionalities of a normal Serial
|
||||
// This example creates a bridge between Serial and Classical Bluetooth (SPP)
|
||||
// and also demonstrate that SerialBT have the same functionalities of a normal Serial
|
||||
// Note: Pairing is authenticated automatically by this device
|
||||
|
||||
#include "BluetoothSerial.h"
|
||||
|
||||
//#define USE_PIN // Uncomment this to use PIN during pairing. The pin is specified on the line below
|
||||
const char *pin = "1234"; // Change this to more secure PIN.
|
||||
|
||||
String device_name = "ESP32-BT-Slave";
|
||||
|
||||
// Check if Bluetooth is available
|
||||
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
|
||||
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
|
||||
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
|
||||
#endif
|
||||
|
||||
// Check Serial Port Profile
|
||||
#if !defined(CONFIG_BT_SPP_ENABLED)
|
||||
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
|
||||
#error Serial Port Profile for Bluetooth is not available or not enabled. It is only available for the ESP32 chip.
|
||||
#endif
|
||||
|
||||
BluetoothSerial SerialBT;
|
||||
|
|
@ -24,12 +24,8 @@ BluetoothSerial SerialBT;
|
|||
void setup() {
|
||||
Serial.begin(115200);
|
||||
SerialBT.begin(device_name); //Bluetooth device name
|
||||
//SerialBT.deleteAllBondedDevices(); // Uncomment this to delete paired devices; Must be called after begin
|
||||
Serial.printf("The device with name \"%s\" is started.\nNow you can pair it with Bluetooth!\n", device_name.c_str());
|
||||
//Serial.printf("The device with name \"%s\" and MAC address %s is started.\nNow you can pair it with Bluetooth!\n", device_name.c_str(), SerialBT.getMacString()); // Use this after the MAC method is implemented
|
||||
#ifdef USE_PIN
|
||||
SerialBT.setPin(pin);
|
||||
Serial.println("Using PIN");
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
|
|
|||
|
|
@ -1,27 +1,33 @@
|
|||
// This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
// By Victor Tchistiak - 2019
|
||||
//
|
||||
// This example demonstrates master mode Bluetooth connection to a slave BT device using PIN (password)
|
||||
// defined either by String "slaveName" by default "OBDII" or by MAC address
|
||||
// This example demonstrates master mode Bluetooth connection to a slave BT device
|
||||
// defined either by String "slaveName" by default "ESP32-BT-Slave" or by MAC address
|
||||
//
|
||||
// This example creates a bridge between Serial and Classical Bluetooth (SPP)
|
||||
// This is an extension of the SerialToSerialBT example by Evandro Copercini - 2018
|
||||
//
|
||||
// DO NOT try to connect to phone or laptop - they are master
|
||||
// devices, same as the ESP using this code - it will NOT work!
|
||||
// devices, same as the ESP using this code - you will be able
|
||||
// to pair, but the serial communication will NOT work!
|
||||
//
|
||||
// You can try to flash a second ESP32 with the example SerialToSerialBT - it should
|
||||
// automatically pair with ESP32 running this code
|
||||
// Note: Pairing is authenticated automatically by this device
|
||||
|
||||
#include "BluetoothSerial.h"
|
||||
|
||||
#define USE_NAME // Comment this to use MAC address instead of a slaveName
|
||||
const char *pin = "1234"; // Change this to reflect the pin expected by the real slave BT device
|
||||
|
||||
#if !defined(CONFIG_BT_SPP_ENABLED)
|
||||
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
|
||||
// Check if Bluetooth is available
|
||||
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
|
||||
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
|
||||
#endif
|
||||
|
||||
// Check Serial Port Profile
|
||||
#if !defined(CONFIG_BT_SPP_ENABLED)
|
||||
#error Serial Port Profile for Bluetooth is not available or not enabled. It is only available for the ESP32 chip.
|
||||
#endif
|
||||
BluetoothSerial SerialBT;
|
||||
|
||||
#ifdef USE_NAME
|
||||
|
|
@ -38,6 +44,7 @@ void setup() {
|
|||
Serial.begin(115200);
|
||||
|
||||
SerialBT.begin(myName, true);
|
||||
//SerialBT.deleteAllBondedDevices(); // Uncomment this to delete paired devices; Must be called after begin
|
||||
Serial.printf("The device \"%s\" started in master mode, make sure slave BT device is on!\n", myName.c_str());
|
||||
|
||||
#ifndef USE_NAME
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
// This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
//
|
||||
// This example creates a bridge between Serial and Classical Bluetooth (SPP with authentication)
|
||||
// and also demonstrate that SerialBT have the same functionalities of a normal Serial
|
||||
// Legacy pairing TODO
|
||||
// Must be run as idf component ... todo
|
||||
|
||||
#include "BluetoothSerial.h"
|
||||
|
||||
// Check if Bluetooth is available
|
||||
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
|
||||
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
|
||||
#endif
|
||||
|
||||
// Check Serial Port Profile
|
||||
#if !defined(CONFIG_BT_SPP_ENABLED)
|
||||
#error Serial Port Profile for Bluetooth is not available or not enabled. It is only available for the ESP32 chip.
|
||||
#endif
|
||||
|
||||
// Check Simple Secure Pairing
|
||||
#if defined(CONFIG_BT_SSP_ENABLED)
|
||||
#warning Legacy Pairing is disabled (CONFIG_BT_SSP_ENABLED is enabled. Disable it in menuconfig).
|
||||
void setup(){}
|
||||
void loop(){}
|
||||
#else
|
||||
const char * deviceName = "ESP32_Legacy_example";
|
||||
|
||||
BluetoothSerial SerialBT;
|
||||
bool confirmRequestDone = false;
|
||||
|
||||
void BTAuthCompleteCallback(boolean success){
|
||||
if (success){
|
||||
confirmRequestDone = true;
|
||||
Serial.println("Pairing success!!");
|
||||
} else {
|
||||
Serial.println("Pairing failed, rejected by user!!");
|
||||
}
|
||||
}
|
||||
|
||||
void serial_response(){
|
||||
if (Serial.available()){
|
||||
SerialBT.write(Serial.read());
|
||||
}
|
||||
if (SerialBT.available()){
|
||||
Serial.write(SerialBT.read());
|
||||
}
|
||||
delay(20);
|
||||
}
|
||||
|
||||
void setup(){
|
||||
Serial.begin(115200);
|
||||
SerialBT.onAuthComplete(BTAuthCompleteCallback);
|
||||
SerialBT.begin(deviceName); // Initiate Bluetooth device with name in parameter
|
||||
SerialBT.setPin("1234", 4);
|
||||
Serial.printf("The device started with name \"%s\", now you can pair it with Bluetooth!\n", deviceName);
|
||||
}
|
||||
|
||||
void loop(){
|
||||
if (confirmRequestDone){
|
||||
serial_response();
|
||||
} else {
|
||||
delay(1); // Feed the watchdog
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
// This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
// By Richard Li - 2020
|
||||
//
|
||||
// This example creates a bridge between Serial and Classical Bluetooth (SPP with authentication)
|
||||
// and also demonstrate that SerialBT have the same functionalities of a normal Serial
|
||||
// SSP - Simple Secure Pairing - The device (ESP32) will display random number and the user is responsible of comparing it to the number
|
||||
// displayed on the other device (for example phone).
|
||||
// If the numbers match the user authenticates the pairing on both devices - on phone simply press "Pair" and in terminal for the sketch send 'Y' or 'y' to confirm.
|
||||
// Alternatively uncomment AUTO_PAIR to skip the terminal confirmation.
|
||||
|
||||
#include "BluetoothSerial.h"
|
||||
|
||||
//#define AUTO_PAIR // Uncomment to automatically authenticate ESP32 side
|
||||
|
||||
// Check if Bluetooth is available
|
||||
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
|
||||
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
|
||||
#endif
|
||||
|
||||
// Check Serial Port Profile
|
||||
#if !defined(CONFIG_BT_SPP_ENABLED)
|
||||
#error Serial Port Profile for Bluetooth is not available or not enabled. It is only available for the ESP32 chip.
|
||||
#endif
|
||||
|
||||
// Check Simple Secure Pairing
|
||||
#if !defined(CONFIG_BT_SSP_ENABLED)
|
||||
#error Simple Secure Pairing for Bluetooth is not available or not enabled.
|
||||
#endif
|
||||
|
||||
const char * deviceName = "ESP32_SSP_example";
|
||||
|
||||
// The following lines defines the method of pairing
|
||||
// When both Input and Output are false only the other device authenticates pairing without any pin.
|
||||
// When Output is true and Input is false only the other device authenticates pairing without any pin.
|
||||
// When both Input and Output are true both devices display randomly generated code and if they match authenticate pairing on both devices
|
||||
// - This must be implemented by registering callback via onConfirmRequest() and in this callback request user input and call confirmReply(true); if the authenticated
|
||||
// otherwise call `confirmReply(false)` to reject the pairing.
|
||||
// When Input is true and Output is false User will be required to input the passkey to the ESP32 device to authenticate.
|
||||
// - This must be implemented by registering callback via onKeyRequest() and in this callback the entered passkey will be responded via respondPasskey(passkey);
|
||||
const bool INPUT_CAPABILITY = false; // Defines if ESP32 device has input method (Serial terminal, keyboard or similar)
|
||||
const bool OUTPUT_CAPABILITY = true; // Defines if ESP32 device has output method (Serial terminal, display or similar)
|
||||
|
||||
BluetoothSerial SerialBT;
|
||||
bool confirmRequestDone = false;
|
||||
|
||||
void BTConfirmRequestCallback(uint32_t numVal){
|
||||
confirmRequestDone = false;
|
||||
#ifndef AUTO_PAIR
|
||||
Serial.printf("The PIN is: %06lu. If it matches number displayed on the other device write \'Y\' or \'y\':\n", numVal); // Note the formatting "%06lu" - PIN can start with zero(s) which would be ignored with simple "%lu"
|
||||
while (!Serial.available()) {
|
||||
delay(1); // Feed the watchdog
|
||||
// Wait until data is available on the Serial port.
|
||||
}
|
||||
Serial.printf("Oh you sent %d Bytes, lets see...", Serial.available());
|
||||
int dat = Serial.read();
|
||||
if (dat == 'Y' || dat == 'y'){
|
||||
SerialBT.confirmReply(true);
|
||||
}
|
||||
else{
|
||||
SerialBT.confirmReply(false);
|
||||
}
|
||||
#else
|
||||
SerialBT.confirmReply(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void BTKeyRequestCallback(){
|
||||
Serial.println("BTKeyRequestCallback"); // debug
|
||||
char buffer[7] = {0}; // 6 bytes for number, one for termination '0'
|
||||
while (1) {
|
||||
Serial.print("Enter the passkey displayed on the other device: ");
|
||||
while (!Serial.available()) {
|
||||
delay(1); // Feed the watchdog
|
||||
// Wait until data is available on the Serial port.
|
||||
}
|
||||
size_t len = Serial.readBytesUntil('\n', buffer, sizeof(buffer) - 1);
|
||||
buffer[len] = '\0'; // Null-terminate the string.
|
||||
try {
|
||||
uint32_t passkey = std::stoi(buffer);
|
||||
Serial.printf("Entered PIN: %lu\n", passkey);
|
||||
SerialBT.respondPasskey(passkey);
|
||||
return;
|
||||
} catch (...) {
|
||||
Serial.print("Wrong PIN! Try again.");
|
||||
} // try
|
||||
} // while(1)
|
||||
}
|
||||
|
||||
void BTAuthCompleteCallback(boolean success){
|
||||
if (success){
|
||||
confirmRequestDone = true;
|
||||
Serial.println("Pairing success!!");
|
||||
} else {
|
||||
Serial.println("Pairing failed, rejected by user!!");
|
||||
}
|
||||
}
|
||||
|
||||
void serial_response(){
|
||||
if (Serial.available()){
|
||||
SerialBT.write(Serial.read());
|
||||
}
|
||||
if (SerialBT.available()){
|
||||
Serial.write(SerialBT.read());
|
||||
}
|
||||
delay(20);
|
||||
}
|
||||
|
||||
void setup(){
|
||||
Serial.begin(115200);
|
||||
SerialBT.enableSSP(INPUT_CAPABILITY, OUTPUT_CAPABILITY); // Must be called before begin
|
||||
SerialBT.onConfirmRequest(BTConfirmRequestCallback);
|
||||
SerialBT.onKeyRequest(BTKeyRequestCallback);
|
||||
SerialBT.onAuthComplete(BTAuthCompleteCallback);
|
||||
SerialBT.begin(deviceName); // Initiate Bluetooth device with name in parameter
|
||||
//SerialBT.deleteAllBondedDevices(); // Uncomment this to delete paired devices; Must be called after begin
|
||||
Serial.printf("The device started with name \"%s\", now you can pair it with Bluetooth!\n", deviceName);
|
||||
if(INPUT_CAPABILITY and OUTPUT_CAPABILITY){
|
||||
Serial.println("Both devices will display randomly generated code and if they match authenticate pairing on both devices");
|
||||
}else if(not INPUT_CAPABILITY and not OUTPUT_CAPABILITY){
|
||||
Serial.println("Authenticate pairing on the other device. No PIN is used");
|
||||
}else if(not INPUT_CAPABILITY and OUTPUT_CAPABILITY){
|
||||
Serial.println("Authenticate pairing on the other device. No PIN is used");
|
||||
}else if(INPUT_CAPABILITY and not OUTPUT_CAPABILITY){
|
||||
Serial.println("After pairing is initiated you will be required to enter the passkey to the ESP32 device to authenticate\n > The Passkey will displayed on the other device");
|
||||
}
|
||||
}
|
||||
|
||||
void loop(){
|
||||
if (confirmRequestDone){
|
||||
serial_response();
|
||||
} else {
|
||||
delay(1); // Feed the watchdog
|
||||
}
|
||||
}
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
//This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
//By Richard Li - 2020
|
||||
//
|
||||
//This example creates a bridge between Serial and Classical Bluetooth (SPP with authentication)
|
||||
//and also demonstrate that SerialBT have the same functionalities of a normal Serial
|
||||
|
||||
#include "BluetoothSerial.h"
|
||||
|
||||
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
|
||||
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_BT_SPP_ENABLED)
|
||||
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
|
||||
#endif
|
||||
|
||||
BluetoothSerial SerialBT;
|
||||
boolean confirmRequestPending = true;
|
||||
|
||||
void BTConfirmRequestCallback(uint32_t numVal)
|
||||
{
|
||||
confirmRequestPending = true;
|
||||
Serial.println(numVal);
|
||||
}
|
||||
|
||||
void BTAuthCompleteCallback(boolean success)
|
||||
{
|
||||
confirmRequestPending = false;
|
||||
if (success)
|
||||
{
|
||||
Serial.println("Pairing success!!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Pairing failed, rejected by user!!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
SerialBT.enableSSP();
|
||||
SerialBT.onConfirmRequest(BTConfirmRequestCallback);
|
||||
SerialBT.onAuthComplete(BTAuthCompleteCallback);
|
||||
SerialBT.begin("ESP32test"); //Bluetooth device name
|
||||
Serial.println("The device started, now you can pair it with bluetooth!");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (confirmRequestPending)
|
||||
{
|
||||
if (Serial.available())
|
||||
{
|
||||
int dat = Serial.read();
|
||||
if (dat == 'Y' || dat == 'y')
|
||||
{
|
||||
SerialBT.confirmReply(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
SerialBT.confirmReply(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Serial.available())
|
||||
{
|
||||
SerialBT.write(Serial.read());
|
||||
}
|
||||
if (SerialBT.available())
|
||||
{
|
||||
Serial.write(SerialBT.read());
|
||||
}
|
||||
delay(20);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,17 @@
|
|||
#include <BluetoothSerial.h>
|
||||
|
||||
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
|
||||
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
|
||||
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_BT_SPP_ENABLED)
|
||||
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
|
||||
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
|
||||
#endif
|
||||
|
||||
BluetoothSerial SerialBT;
|
||||
|
||||
|
||||
#define BT_DISCOVER_TIME 10000
|
||||
#define BT_DISCOVER_TIME 10000
|
||||
|
||||
|
||||
static bool btScanAsync = true;
|
||||
|
|
@ -19,7 +19,7 @@ static bool btScanSync = true;
|
|||
|
||||
|
||||
void btAdvertisedDeviceFound(BTAdvertisedDevice* pDevice) {
|
||||
Serial.printf("Found a device asynchronously: %s\n", pDevice->toString().c_str());
|
||||
Serial.printf("Found a device asynchronously: %s\n", pDevice->toString().c_str());
|
||||
}
|
||||
|
||||
void setup() {
|
||||
|
|
@ -29,7 +29,7 @@ void setup() {
|
|||
|
||||
|
||||
if (btScanAsync) {
|
||||
Serial.print("Starting discoverAsync...");
|
||||
Serial.print("Starting asynchronous discovery... ");
|
||||
if (SerialBT.discoverAsync(btAdvertisedDeviceFound)) {
|
||||
Serial.println("Findings will be reported in \"btAdvertisedDeviceFound\"");
|
||||
delay(10000);
|
||||
|
|
@ -37,12 +37,12 @@ void setup() {
|
|||
SerialBT.discoverAsyncStop();
|
||||
Serial.println("stopped");
|
||||
} else {
|
||||
Serial.println("Error on discoverAsync f.e. not workin after a \"connect\"");
|
||||
Serial.println("Error on discoverAsync f.e. not working after a \"connect\"");
|
||||
}
|
||||
}
|
||||
|
||||
if (btScanSync) {
|
||||
Serial.println("Starting discover...");
|
||||
Serial.println("Starting synchronous discovery... ");
|
||||
BTScanResults *pResults = SerialBT.discover(BT_DISCOVER_TIME);
|
||||
if (pResults)
|
||||
pResults->dump(&Serial);
|
||||
|
|
|
|||
|
|
@ -1,91 +1,74 @@
|
|||
//This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
//By Victor Tchistiak - 2019
|
||||
// This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
// Originally by Victor Tchistiak - 2019
|
||||
// Rewritten with new API by Tomas Pilny - 2023
|
||||
//
|
||||
//This example demonstrates reading and removing paired devices stored on the ESP32 flash memory
|
||||
//Sometimes you may find your ESP32 device could not connect to the remote device despite
|
||||
//many successful connections earlier. This is most likely a result of client replacing your paired
|
||||
//device info with new one from other device. The BT clients store connection info for paired devices,
|
||||
//but it is limited to a few devices only. When new device pairs and number of stored devices is exceeded,
|
||||
//one of the previously paired devices would be replaced with new one.
|
||||
//The only remedy is to delete this saved bound device from your device flash memory
|
||||
//and pair with the other device again.
|
||||
//
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_bt_device.h"
|
||||
#include"esp_gap_bt_api.h"
|
||||
#include "esp_err.h"
|
||||
// This example demonstrates reading and removing paired devices stored on the ESP32 flash memory
|
||||
// Sometimes you may find your ESP32 device could not connect to the remote device despite
|
||||
// many successful connections earlier. This is most likely a result of client replacing your paired
|
||||
// device info with new one from other device. The BT clients store connection info for paired devices,
|
||||
// but it is limited to a few devices only. When new device pairs and number of stored devices is exceeded,
|
||||
// one of the previously paired devices would be replaced with new one.
|
||||
// The only remedy is to delete this saved bound device from your device flash memory
|
||||
// and pair with the other device again.
|
||||
|
||||
#include "BluetoothSerial.h"
|
||||
//#include "esp_bt_device.h"
|
||||
|
||||
#if !defined(CONFIG_BT_SPP_ENABLED)
|
||||
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
|
||||
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
|
||||
#endif
|
||||
|
||||
#define REMOVE_BONDED_DEVICES 0 // <- Set to 0 to view all bonded devices addresses, set to 1 to remove
|
||||
|
||||
#define REMOVE_BONDED_DEVICES true // <- Set to `false` to view all bonded devices addresses, set to `true` to remove
|
||||
#define PAIR_MAX_DEVICES 20
|
||||
uint8_t pairedDeviceBtAddr[PAIR_MAX_DEVICES][6];
|
||||
char bda_str[18];
|
||||
BluetoothSerial SerialBT;
|
||||
|
||||
bool initBluetooth()
|
||||
{
|
||||
if(!btStart()) {
|
||||
Serial.println("Failed to initialize controller");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(esp_bluedroid_init() != ESP_OK) {
|
||||
Serial.println("Failed to initialize bluedroid");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(esp_bluedroid_enable() != ESP_OK) {
|
||||
Serial.println("Failed to enable bluedroid");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
char *bda2str(const uint8_t* bda, char *str, size_t size)
|
||||
{
|
||||
if (bda == NULL || str == NULL || size < 18) {
|
||||
char *bda2str(const uint8_t* bda, char *str, size_t size){
|
||||
if (bda == NULL || str == NULL || size < 18){
|
||||
return NULL;
|
||||
}
|
||||
sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
|
||||
return str;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
|
||||
void setup(){
|
||||
char bda_str[18];
|
||||
uint8_t pairedDeviceBtAddr[PAIR_MAX_DEVICES][6];
|
||||
Serial.begin(115200);
|
||||
|
||||
initBluetooth();
|
||||
Serial.print("ESP32 bluetooth address: "); Serial.println(bda2str(esp_bt_dev_get_address(), bda_str, 18));
|
||||
|
||||
SerialBT.begin();
|
||||
Serial.printf("ESP32 bluetooth address: %s\n", SerialBT.getBtAddressString().c_str());
|
||||
// SerialBT.deleteAllBondedDevices(); // If you want just delete all, this is the way
|
||||
// Get the numbers of bonded/paired devices in the BT module
|
||||
int count = esp_bt_gap_get_bond_device_num();
|
||||
if(!count) {
|
||||
Serial.println("No bonded device found.");
|
||||
int count = SerialBT.getNumberOfBondedDevices();
|
||||
if(!count){
|
||||
Serial.println("No bonded devices found.");
|
||||
} else {
|
||||
Serial.print("Bonded device count: "); Serial.println(count);
|
||||
if(PAIR_MAX_DEVICES < count) {
|
||||
count = PAIR_MAX_DEVICES;
|
||||
Serial.print("Reset bonded device count: "); Serial.println(count);
|
||||
Serial.printf("Bonded device count: %d\n", count);
|
||||
if(PAIR_MAX_DEVICES < count){
|
||||
count = PAIR_MAX_DEVICES;
|
||||
Serial.printf("Reset %d bonded devices\n", count);
|
||||
}
|
||||
esp_err_t tError = esp_bt_gap_get_bond_device_list(&count, pairedDeviceBtAddr);
|
||||
if(ESP_OK == tError) {
|
||||
for(int i = 0; i < count; i++) {
|
||||
Serial.print("Found bonded device # "); Serial.print(i); Serial.print(" -> ");
|
||||
Serial.println(bda2str(pairedDeviceBtAddr[i], bda_str, 18));
|
||||
if(REMOVE_BONDED_DEVICES) {
|
||||
esp_err_t tError = esp_bt_gap_remove_bond_device(pairedDeviceBtAddr[i]);
|
||||
if(ESP_OK == tError) {
|
||||
Serial.print("Removed bonded device # ");
|
||||
} else {
|
||||
Serial.print("Failed to remove bonded device # ");
|
||||
}
|
||||
Serial.println(i);
|
||||
count = SerialBT.getBondedDevices(count, pairedDeviceBtAddr);
|
||||
char rmt_name[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
|
||||
if(count > 0){
|
||||
for(int i = 0; i < count; i++){
|
||||
SerialBT.requestRemoteName(pairedDeviceBtAddr[i]);
|
||||
while(!SerialBT.readRemoteName(rmt_name)){
|
||||
delay(1); // Wait for response with the device name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Serial.printf("Found bonded device #%d BDA:%s; Name:\"%s\"\n", i, bda2str(pairedDeviceBtAddr[i], bda_str, 18), rmt_name);
|
||||
SerialBT.invalidateRemoteName(); // Allows waiting for next reading
|
||||
if(REMOVE_BONDED_DEVICES){
|
||||
if(SerialBT.deleteBondedDevice(pairedDeviceBtAddr[i])){
|
||||
Serial.printf("Removed bonded device # %d\n", i);
|
||||
} else {
|
||||
Serial.printf("Failed to remove bonded device # %d", i);
|
||||
} // if(ESP_OK == tError)
|
||||
} // if(REMOVE_BONDED_DEVICES)
|
||||
} // for(int i = 0; i < count; i++)
|
||||
} // if(ESP_OK == tError)
|
||||
} // if(!count)
|
||||
}
|
||||
|
||||
|
||||
void loop() {}
|
||||
|
|
|
|||
|
|
@ -20,21 +20,21 @@ class BTAdvertisedDeviceSet;
|
|||
|
||||
class BTScanResults {
|
||||
public:
|
||||
virtual ~BTScanResults() = default;
|
||||
virtual ~BTScanResults() = default;
|
||||
|
||||
virtual void dump(Print *print = nullptr);
|
||||
virtual int getCount();
|
||||
virtual void dump(Print *print = nullptr);
|
||||
virtual int getCount();
|
||||
virtual BTAdvertisedDevice* getDevice(int i);
|
||||
};
|
||||
|
||||
class BTScanResultsSet : public BTScanResults {
|
||||
public:
|
||||
void dump(Print *print = nullptr);
|
||||
int getCount();
|
||||
BTAdvertisedDevice* getDevice(int i);
|
||||
void dump(Print *print = nullptr);
|
||||
int getCount();
|
||||
BTAdvertisedDevice* getDevice(int i);
|
||||
|
||||
bool add(BTAdvertisedDeviceSet advertisedDevice, bool unique = true);
|
||||
void clear();
|
||||
bool add(BTAdvertisedDeviceSet advertisedDevice, bool unique = true);
|
||||
void clear();
|
||||
|
||||
std::map<std::string, BTAdvertisedDeviceSet> m_vectorAdvertisedDevices;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,10 +24,11 @@
|
|||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BLUEDROID_ENABLED)
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "esp32-hal-log.h"
|
||||
#include "esp32-hal-log.h"
|
||||
#endif
|
||||
|
||||
#include "BluetoothSerial.h"
|
||||
#include "BTAdvertisedDevice.h"
|
||||
|
||||
#include "esp_bt.h"
|
||||
#include "esp_bt_main.h"
|
||||
|
|
@ -58,7 +59,10 @@ static esp_spp_cb_t * custom_spp_callback = NULL;
|
|||
static BluetoothSerialDataCb custom_data_callback = NULL;
|
||||
static esp_bd_addr_t current_bd_addr;
|
||||
static ConfirmRequestCb confirm_request_callback = NULL;
|
||||
static KeyRequestCb key_request_callback = NULL;
|
||||
static AuthCompleteCb auth_complete_callback = NULL;
|
||||
static bool _rmt_name_valid = false;
|
||||
static uint8_t _rmt_name[ESP_BT_GAP_MAX_BDNAME_LEN + 1] = {0};
|
||||
|
||||
#define INQ_LEN 0x10
|
||||
#define INQ_NUM_RSPS 20
|
||||
|
|
@ -68,10 +72,13 @@ static esp_bd_addr_t _peer_bd_addr;
|
|||
static char _remote_name[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
|
||||
static bool _isRemoteAddressSet;
|
||||
static bool _isMaster;
|
||||
static esp_bt_pin_code_t _pin_code;
|
||||
static int _pin_len;
|
||||
static bool _isPinSet;
|
||||
static bool _enableSSP;
|
||||
#ifdef CONFIG_BT_SSP_ENABLED
|
||||
static bool _enableSSP;
|
||||
static bool _IO_CAP_INPUT;
|
||||
static bool _IO_CAP_OUTPUT;
|
||||
#endif
|
||||
esp_bt_pin_code_t _pin_code = {0};
|
||||
uint8_t _pin_code_len = 0; // Number of valid Bytes in the esp_bt_pin_code_t array
|
||||
static esp_spp_sec_t _sec_mask;
|
||||
static esp_spp_role_t _role;
|
||||
// start connect on ESP_SPP_DISCOVERY_COMP_EVT or save entry for getChannels
|
||||
|
|
@ -139,22 +146,6 @@ static bool get_name_from_eir(uint8_t *eir, char *bdname, uint8_t *bdname_len)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool btSetPin() {
|
||||
esp_bt_pin_type_t pin_type;
|
||||
if (_isPinSet) {
|
||||
if (_pin_len) {
|
||||
log_i("pin set");
|
||||
pin_type = ESP_BT_PIN_TYPE_FIXED;
|
||||
} else {
|
||||
_isPinSet = false;
|
||||
log_i("pin reset");
|
||||
pin_type = ESP_BT_PIN_TYPE_VARIABLE; // pin_code would be ignored (default)
|
||||
}
|
||||
return (esp_bt_gap_set_pin(pin_type, _pin_len, _pin_code) == ESP_OK);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static esp_err_t _spp_queue_packet(uint8_t *data, size_t len){
|
||||
if(!data || !len){
|
||||
log_w("No data provided");
|
||||
|
|
@ -259,7 +250,7 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
|
|||
{
|
||||
switch (event)
|
||||
{
|
||||
case ESP_SPP_INIT_EVT:
|
||||
case ESP_SPP_INIT_EVT: // Enum 0 - When SPP is initialized
|
||||
log_i("ESP_SPP_INIT_EVT");
|
||||
#ifdef ESP_IDF_VERSION_MAJOR
|
||||
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
|
||||
|
|
@ -273,80 +264,11 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
|
|||
xEventGroupSetBits(_spp_event_group, SPP_RUNNING);
|
||||
break;
|
||||
|
||||
case ESP_SPP_SRV_OPEN_EVT://Server connection open
|
||||
if (param->srv_open.status == ESP_SPP_SUCCESS) {
|
||||
log_i("ESP_SPP_SRV_OPEN_EVT: %u", _spp_client);
|
||||
if (!_spp_client){
|
||||
_spp_client = param->srv_open.handle;
|
||||
_spp_tx_buffer_len = 0;
|
||||
} else {
|
||||
secondConnectionAttempt = true;
|
||||
esp_spp_disconnect(param->srv_open.handle);
|
||||
}
|
||||
xEventGroupClearBits(_spp_event_group, SPP_DISCONNECTED);
|
||||
xEventGroupSetBits(_spp_event_group, SPP_CONNECTED);
|
||||
} else {
|
||||
log_e("ESP_SPP_SRV_OPEN_EVT Failed!, status:%d", param->srv_open.status);
|
||||
}
|
||||
case ESP_SPP_UNINIT_EVT: // Enum 1 - When SPP is deinitialized
|
||||
log_i("ESP_SPP_UNINIT_EVT: SPP is deinitialized");
|
||||
break;
|
||||
|
||||
case ESP_SPP_CLOSE_EVT://Client connection closed
|
||||
if ((param->close.async == false && param->close.status == ESP_SPP_SUCCESS) || param->close.async) {
|
||||
log_i("ESP_SPP_CLOSE_EVT status:%d handle:%d close_by_remote:%d attempt %u", param->close.status,
|
||||
param->close.handle, param->close.async, secondConnectionAttempt);
|
||||
if(secondConnectionAttempt) {
|
||||
secondConnectionAttempt = false;
|
||||
} else {
|
||||
_spp_client = 0;
|
||||
xEventGroupSetBits(_spp_event_group, SPP_DISCONNECTED);
|
||||
xEventGroupSetBits(_spp_event_group, SPP_CONGESTED);
|
||||
xEventGroupSetBits(_spp_event_group, SPP_CLOSED);
|
||||
xEventGroupClearBits(_spp_event_group, SPP_CONNECTED);
|
||||
}
|
||||
} else {
|
||||
log_e("ESP_SPP_CLOSE_EVT failed!, status:%d", param->close.status);
|
||||
}
|
||||
break;
|
||||
|
||||
case ESP_SPP_CONG_EVT://connection congestion status changed
|
||||
if(param->cong.cong){
|
||||
xEventGroupClearBits(_spp_event_group, SPP_CONGESTED);
|
||||
} else {
|
||||
xEventGroupSetBits(_spp_event_group, SPP_CONGESTED);
|
||||
}
|
||||
log_v("ESP_SPP_CONG_EVT: %s", param->cong.cong?"CONGESTED":"FREE");
|
||||
break;
|
||||
|
||||
case ESP_SPP_WRITE_EVT://write operation completed
|
||||
if (param->write.status == ESP_SPP_SUCCESS) {
|
||||
if(param->write.cong){
|
||||
xEventGroupClearBits(_spp_event_group, SPP_CONGESTED);
|
||||
}
|
||||
log_v("ESP_SPP_WRITE_EVT: %u %s", param->write.len, param->write.cong?"CONGESTED":"");
|
||||
} else {
|
||||
log_e("ESP_SPP_WRITE_EVT failed!, status:%d", param->write.status);
|
||||
}
|
||||
xSemaphoreGive(_spp_tx_done);//we can try to send another packet
|
||||
break;
|
||||
|
||||
case ESP_SPP_DATA_IND_EVT://connection received data
|
||||
log_v("ESP_SPP_DATA_IND_EVT len=%d handle=%d", param->data_ind.len, param->data_ind.handle);
|
||||
//esp_log_buffer_hex("",param->data_ind.data,param->data_ind.len); //for low level debug
|
||||
//ets_printf("r:%u\n", param->data_ind.len);
|
||||
|
||||
if(custom_data_callback){
|
||||
custom_data_callback(param->data_ind.data, param->data_ind.len);
|
||||
} else if (_spp_rx_queue != NULL){
|
||||
for (int i = 0; i < param->data_ind.len; i++){
|
||||
if(xQueueSend(_spp_rx_queue, param->data_ind.data + i, (TickType_t)0) != pdTRUE){
|
||||
log_e("RX Full! Discarding %u bytes", param->data_ind.len - i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ESP_SPP_DISCOVERY_COMP_EVT://discovery complete
|
||||
case ESP_SPP_DISCOVERY_COMP_EVT: // Enum 8 - When SDP discovery complete
|
||||
log_i("ESP_SPP_DISCOVERY_COMP_EVT num=%d", param->disc_comp.scn_num);
|
||||
if (param->disc_comp.status == ESP_SPP_SUCCESS) {
|
||||
for(int i=0; i < param->disc_comp.scn_num; i++) {
|
||||
|
|
@ -380,7 +302,7 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
|
|||
xEventGroupSetBits(_bt_event_group, BT_SDP_COMPLETED);
|
||||
break;
|
||||
|
||||
case ESP_SPP_OPEN_EVT://Client connection open
|
||||
case ESP_SPP_OPEN_EVT: // Enum 26 - When SPP Client connection open
|
||||
log_i("ESP_SPP_OPEN_EVT");
|
||||
if (!_spp_client){
|
||||
_spp_client = param->open.handle;
|
||||
|
|
@ -393,11 +315,29 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
|
|||
xEventGroupSetBits(_spp_event_group, SPP_CONGESTED);
|
||||
break;
|
||||
|
||||
case ESP_SPP_START_EVT://server started
|
||||
case ESP_SPP_CLOSE_EVT: // Enum 27 - When SPP connection closed
|
||||
if ((param->close.async == false && param->close.status == ESP_SPP_SUCCESS) || param->close.async) {
|
||||
log_i("ESP_SPP_CLOSE_EVT status:%d handle:%d close_by_remote:%d attempt %u", param->close.status,
|
||||
param->close.handle, param->close.async, secondConnectionAttempt);
|
||||
if(secondConnectionAttempt) {
|
||||
secondConnectionAttempt = false;
|
||||
} else {
|
||||
_spp_client = 0;
|
||||
xEventGroupSetBits(_spp_event_group, SPP_DISCONNECTED);
|
||||
xEventGroupSetBits(_spp_event_group, SPP_CONGESTED);
|
||||
xEventGroupSetBits(_spp_event_group, SPP_CLOSED);
|
||||
xEventGroupClearBits(_spp_event_group, SPP_CONNECTED);
|
||||
}
|
||||
} else {
|
||||
log_e("ESP_SPP_CLOSE_EVT failed!, status:%d", param->close.status);
|
||||
}
|
||||
break;
|
||||
|
||||
case ESP_SPP_START_EVT: // Enum 28 - When SPP server started
|
||||
log_i("ESP_SPP_START_EVT");
|
||||
break;
|
||||
|
||||
case ESP_SPP_CL_INIT_EVT://client initiated a connection
|
||||
case ESP_SPP_CL_INIT_EVT: // Enum 29 - When SPP client initiated a connection
|
||||
if (param->cl_init.status == ESP_SPP_SUCCESS) {
|
||||
log_i("ESP_SPP_CL_INIT_EVT handle:%d sec_id:%d", param->cl_init.handle, param->cl_init.sec_id);
|
||||
} else {
|
||||
|
|
@ -405,8 +345,75 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
|
|||
}
|
||||
break;
|
||||
|
||||
case ESP_SPP_DATA_IND_EVT: // Enum 30 - When SPP connection received data, only for ESP_SPP_MODE_CB
|
||||
log_v("ESP_SPP_DATA_IND_EVT len=%d handle=%d", param->data_ind.len, param->data_ind.handle);
|
||||
//esp_log_buffer_hex("",param->data_ind.data,param->data_ind.len); //for low level debug
|
||||
//ets_printf("r:%u\n", param->data_ind.len);
|
||||
|
||||
if(custom_data_callback){
|
||||
custom_data_callback(param->data_ind.data, param->data_ind.len);
|
||||
} else if (_spp_rx_queue != NULL){
|
||||
for (int i = 0; i < param->data_ind.len; i++){
|
||||
if(xQueueSend(_spp_rx_queue, param->data_ind.data + i, (TickType_t)0) != pdTRUE){
|
||||
log_e("RX Full! Discarding %u bytes", param->data_ind.len - i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ESP_SPP_CONG_EVT: // Enum 31 - When SPP connection congestion status changed, only for ESP_SPP_MODE_CB
|
||||
if(param->cong.cong){
|
||||
xEventGroupClearBits(_spp_event_group, SPP_CONGESTED);
|
||||
} else {
|
||||
xEventGroupSetBits(_spp_event_group, SPP_CONGESTED);
|
||||
}
|
||||
log_v("ESP_SPP_CONG_EVT: %s", param->cong.cong?"CONGESTED":"FREE");
|
||||
break;
|
||||
|
||||
case ESP_SPP_WRITE_EVT: // Enum 33 - When SPP write operation completes, only for ESP_SPP_MODE_CB
|
||||
if (param->write.status == ESP_SPP_SUCCESS) {
|
||||
if(param->write.cong){
|
||||
xEventGroupClearBits(_spp_event_group, SPP_CONGESTED);
|
||||
}
|
||||
log_v("ESP_SPP_WRITE_EVT: %u %s", param->write.len, param->write.cong?"CONGESTED":"");
|
||||
} else {
|
||||
log_e("ESP_SPP_WRITE_EVT failed!, status:%d", param->write.status);
|
||||
}
|
||||
xSemaphoreGive(_spp_tx_done);//we can try to send another packet
|
||||
break;
|
||||
|
||||
case ESP_SPP_SRV_OPEN_EVT: // Enum 34 - When SPP Server connection open
|
||||
if (param->srv_open.status == ESP_SPP_SUCCESS) {
|
||||
log_i("ESP_SPP_SRV_OPEN_EVT: %u", _spp_client);
|
||||
if (!_spp_client){
|
||||
_spp_client = param->srv_open.handle;
|
||||
_spp_tx_buffer_len = 0;
|
||||
} else {
|
||||
secondConnectionAttempt = true;
|
||||
esp_spp_disconnect(param->srv_open.handle);
|
||||
}
|
||||
xEventGroupClearBits(_spp_event_group, SPP_DISCONNECTED);
|
||||
xEventGroupSetBits(_spp_event_group, SPP_CONNECTED);
|
||||
} else {
|
||||
log_e("ESP_SPP_SRV_OPEN_EVT Failed!, status:%d", param->srv_open.status);
|
||||
}
|
||||
break;
|
||||
|
||||
case ESP_SPP_SRV_STOP_EVT: // Enum 35 - When SPP server stopped
|
||||
log_i("ESP_SPP_SRV_STOP_EVT");
|
||||
break;
|
||||
|
||||
case ESP_SPP_VFS_REGISTER_EVT: // Enum 36 - When SPP VFS register
|
||||
log_i("ESP_SPP_VFS_REGISTER_EVT");
|
||||
break;
|
||||
|
||||
case ESP_SPP_VFS_UNREGISTER_EVT: // Enum 37 - When SPP VFS unregister
|
||||
log_i("ESP_SPP_VFS_UNREGISTER_EVT");
|
||||
break;
|
||||
|
||||
default:
|
||||
log_i("ESP_SPP_* event unhandled %d", event);
|
||||
log_i("ESP_SPP_* event #%d unhandled", event);
|
||||
break;
|
||||
}
|
||||
if(custom_spp_callback)(*custom_spp_callback)(event, param);
|
||||
|
|
@ -416,10 +423,11 @@ void BluetoothSerial::onData(BluetoothSerialDataCb cb){
|
|||
custom_data_callback = cb;
|
||||
}
|
||||
|
||||
|
||||
static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
|
||||
{
|
||||
switch(event){
|
||||
case ESP_BT_GAP_DISC_RES_EVT: {
|
||||
case ESP_BT_GAP_DISC_RES_EVT: { // Enum 0 - Device discovery result event
|
||||
log_i("ESP_BT_GAP_DISC_RES_EVT properties=%d", param->disc_res.num_prop);
|
||||
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)
|
||||
char bda_str[18];
|
||||
|
|
@ -430,7 +438,44 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
|
|||
char peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
|
||||
for (int i = 0; i < param->disc_res.num_prop; i++) {
|
||||
switch(param->disc_res.prop[i].type) {
|
||||
case ESP_BT_GAP_DEV_PROP_EIR:
|
||||
case ESP_BT_GAP_DEV_PROP_BDNAME: // Enum 1 - Bluetooth device name, value type is int8_t []
|
||||
peer_bdname_len = param->disc_res.prop[i].len;
|
||||
memcpy(peer_bdname, param->disc_res.prop[i].val, peer_bdname_len);
|
||||
peer_bdname_len--; // len includes 0 terminator
|
||||
log_v("ESP_BT_GAP_DISC_RES_EVT : BDNAME : %s : %d", peer_bdname, peer_bdname_len);
|
||||
if (strlen(_remote_name) == peer_bdname_len
|
||||
&& strncmp(peer_bdname, _remote_name, peer_bdname_len) == 0) {
|
||||
log_i("ESP_BT_GAP_DISC_RES_EVT : SPP_START_DISCOVERY_BDNAME : %s", peer_bdname);
|
||||
_isRemoteAddressSet = true;
|
||||
memcpy(_peer_bd_addr, param->disc_res.bda, ESP_BD_ADDR_LEN);
|
||||
esp_bt_gap_cancel_discovery();
|
||||
esp_spp_start_discovery(_peer_bd_addr);
|
||||
}
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_DEV_PROP_COD: // Enum 2 - Class of Device, value type is uint32_t
|
||||
if (param->disc_res.prop[i].len <= sizeof(int)) {
|
||||
uint32_t cod = 0;
|
||||
memcpy(&cod, param->disc_res.prop[i].val, param->disc_res.prop[i].len);
|
||||
advertisedDevice.setCOD(cod);
|
||||
log_d("ESP_BT_GAP_DEV_PROP_COD 0x%x", cod);
|
||||
} else {
|
||||
log_d("ESP_BT_GAP_DEV_PROP_COD invalid COD: Value size larger than integer");
|
||||
}
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_DEV_PROP_RSSI: // Enum 3 - Received Signal strength Indication, value type is int8_t, ranging from -128 to 127
|
||||
if (param->disc_res.prop[i].len <= sizeof(int)) {
|
||||
uint8_t rssi = 0;
|
||||
memcpy(&rssi, param->disc_res.prop[i].val, param->disc_res.prop[i].len);
|
||||
log_d("ESP_BT_GAP_DEV_PROP_RSSI %d", rssi);
|
||||
advertisedDevice.setRSSI(rssi);
|
||||
} else {
|
||||
log_d("ESP_BT_GAP_DEV_PROP_RSSI invalid RSSI: Value size larger than integer");
|
||||
}
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_DEV_PROP_EIR: // Enum 4 - Extended Inquiry Response, value type is uint8_t []
|
||||
if (get_name_from_eir((uint8_t*)param->disc_res.prop[i].val, peer_bdname, &peer_bdname_len)) {
|
||||
log_i("ESP_BT_GAP_DISC_RES_EVT : EIR : %s : %d", peer_bdname, peer_bdname_len);
|
||||
if (strlen(_remote_name) == peer_bdname_len
|
||||
|
|
@ -444,43 +489,6 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
|
|||
}
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_DEV_PROP_BDNAME:
|
||||
peer_bdname_len = param->disc_res.prop[i].len;
|
||||
memcpy(peer_bdname, param->disc_res.prop[i].val, peer_bdname_len);
|
||||
peer_bdname_len--; // len includes 0 terminator
|
||||
log_v("ESP_BT_GAP_DISC_RES_EVT : BDNAME : %s : %d", peer_bdname, peer_bdname_len);
|
||||
if (strlen(_remote_name) == peer_bdname_len
|
||||
&& strncmp(peer_bdname, _remote_name, peer_bdname_len) == 0) {
|
||||
log_i("ESP_BT_GAP_DISC_RES_EVT : SPP_START_DISCOVERY_BDNAME : %s", peer_bdname);
|
||||
_isRemoteAddressSet = true;
|
||||
memcpy(_peer_bd_addr, param->disc_res.bda, ESP_BD_ADDR_LEN);
|
||||
esp_bt_gap_cancel_discovery();
|
||||
esp_spp_start_discovery(_peer_bd_addr);
|
||||
}
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_DEV_PROP_COD:
|
||||
if (param->disc_res.prop[i].len <= sizeof(int)) {
|
||||
uint32_t cod = 0;
|
||||
memcpy(&cod, param->disc_res.prop[i].val, param->disc_res.prop[i].len);
|
||||
advertisedDevice.setCOD(cod);
|
||||
log_d("ESP_BT_GAP_DEV_PROP_COD 0x%x", cod);
|
||||
} else {
|
||||
log_d("ESP_BT_GAP_DEV_PROP_COD invalid COD: Value size larger than integer");
|
||||
}
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_DEV_PROP_RSSI:
|
||||
if (param->disc_res.prop[i].len <= sizeof(int)) {
|
||||
uint8_t rssi = 0;
|
||||
memcpy(&rssi, param->disc_res.prop[i].val, param->disc_res.prop[i].len);
|
||||
log_d("ESP_BT_GAP_DEV_PROP_RSSI %d", rssi);
|
||||
advertisedDevice.setRSSI(rssi);
|
||||
} else {
|
||||
log_d("ESP_BT_GAP_DEV_PROP_RSSI invalid RSSI: Value size larger than integer");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
log_i("ESP_BT_GAP_DISC_RES_EVT unknown property [%d]:type:%d", i, param->disc_res.prop[i].type);
|
||||
break;
|
||||
|
|
@ -498,7 +506,7 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
|
|||
}
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_DISC_STATE_CHANGED_EVT:
|
||||
case ESP_BT_GAP_DISC_STATE_CHANGED_EVT: // Enum 1 - Discovery state changed event
|
||||
if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STOPPED) {
|
||||
log_i("ESP_BT_GAP_DISC_STATE_CHANGED_EVT stopped");
|
||||
xEventGroupClearBits(_bt_event_group, BT_DISCOVERY_RUNNING);
|
||||
|
|
@ -510,15 +518,15 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
|
|||
}
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_RMT_SRVCS_EVT:
|
||||
case ESP_BT_GAP_RMT_SRVCS_EVT: // Enum 2 - Get remote services event
|
||||
log_i( "ESP_BT_GAP_RMT_SRVCS_EVT: status = %d, num_uuids = %d", param->rmt_srvcs.stat, param->rmt_srvcs.num_uuids);
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_RMT_SRVC_REC_EVT:
|
||||
case ESP_BT_GAP_RMT_SRVC_REC_EVT: // Enum 3 - Get remote service record event
|
||||
log_i("ESP_BT_GAP_RMT_SRVC_REC_EVT: status = %d", param->rmt_srvc_rec.stat);
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_AUTH_CMPL_EVT:
|
||||
case ESP_BT_GAP_AUTH_CMPL_EVT: // Enum 4 - Authentication complete event
|
||||
if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
|
||||
log_v("authentication success: %s", param->auth_cmpl.device_name);
|
||||
if (auth_complete_callback) {
|
||||
|
|
@ -531,58 +539,89 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_PIN_REQ_EVT:
|
||||
// default pairing pins
|
||||
log_i("ESP_BT_GAP_PIN_REQ_EVT min_16_digit:%d", param->pin_req.min_16_digit);
|
||||
if (param->pin_req.min_16_digit) {
|
||||
log_i("Input pin code: 0000 0000 0000 0000");
|
||||
esp_bt_pin_code_t pin_code;
|
||||
memset(pin_code, '0', ESP_BT_PIN_CODE_LEN);
|
||||
esp_bt_gap_pin_reply(param->pin_req.bda, true, 16, pin_code);
|
||||
case ESP_BT_GAP_PIN_REQ_EVT: // Enum 5 - Legacy Pairing Pin code request
|
||||
log_i("ESP_BT_GAP_PIN_REQ_EVT (min_16_digit=%d)", param->pin_req.min_16_digit);
|
||||
if (param->pin_req.min_16_digit && _pin_code_len < 16) {
|
||||
esp_bt_gap_pin_reply(param->pin_req.bda, false, 0, NULL);
|
||||
} else {
|
||||
log_i("Input pin code: 1234");
|
||||
esp_bt_pin_code_t pin_code;
|
||||
memcpy(pin_code, "1234", 4);
|
||||
esp_bt_gap_pin_reply(param->pin_req.bda, true, 4, pin_code);
|
||||
//log_i("Input pin code: \"%s\"=0x%x", _pin_code);
|
||||
log_i("Input pin code: \"%.*s\"=0x%x", _pin_code_len, _pin_code, *(int*)_pin_code);
|
||||
esp_bt_gap_pin_reply(param->pin_req.bda, true, _pin_code_len, _pin_code);
|
||||
}
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_CFM_REQ_EVT:
|
||||
#ifdef CONFIG_BT_SSP_ENABLED
|
||||
case ESP_BT_GAP_CFM_REQ_EVT: // Enum 6 - Security Simple Pairing User Confirmation request.
|
||||
log_i("ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %d", param->cfm_req.num_val);
|
||||
if (confirm_request_callback) {
|
||||
memcpy(current_bd_addr, param->cfm_req.bda, sizeof(esp_bd_addr_t));
|
||||
confirm_request_callback(param->cfm_req.num_val);
|
||||
}
|
||||
else {
|
||||
esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
|
||||
log_w("ESP_BT_GAP_CFM_REQ_EVT: confirm_request_callback does not exist - refusing pairing");
|
||||
esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, false);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case ESP_BT_GAP_KEY_NOTIF_EVT:
|
||||
case ESP_BT_GAP_KEY_NOTIF_EVT: // Enum 7 - Security Simple Pairing Passkey Notification
|
||||
log_i("ESP_BT_GAP_KEY_NOTIF_EVT passkey:%d", param->key_notif.passkey);
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_KEY_REQ_EVT:
|
||||
#ifdef CONFIG_BT_SSP_ENABLED
|
||||
case ESP_BT_GAP_KEY_REQ_EVT: // Enum 8 - Security Simple Pairing Passkey request
|
||||
log_i("ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
|
||||
if (key_request_callback) {
|
||||
memcpy(current_bd_addr, param->cfm_req.bda, sizeof(esp_bd_addr_t));
|
||||
key_request_callback();
|
||||
} else {
|
||||
log_w("ESP_BT_GAP_KEY_REQ_EVT: key_request_callback does not exist - refuseing pairing");
|
||||
esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, false);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case ESP_BT_GAP_CONFIG_EIR_DATA_EVT:
|
||||
case ESP_BT_GAP_READ_RSSI_DELTA_EVT: // Enum 9 - Read rssi event
|
||||
log_i("ESP_BT_GAP_READ_RSSI_DELTA_EVT Read rssi event");
|
||||
break;
|
||||
case ESP_BT_GAP_CONFIG_EIR_DATA_EVT: // Enum 10 - Config EIR data event
|
||||
log_i("ESP_BT_GAP_CONFIG_EIR_DATA_EVT: stat:%d num:%d", param->config_eir_data.stat, param->config_eir_data.eir_type_num);
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_READ_REMOTE_NAME_EVT:
|
||||
case ESP_BT_GAP_SET_AFH_CHANNELS_EVT: // Enum 11 - Set AFH channels event
|
||||
log_i("ESP_BT_GAP_SET_AFH_CHANNELS_EVT Set AFH channels event");
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_READ_REMOTE_NAME_EVT: // Enum 12 - Read Remote Name event
|
||||
if (param->read_rmt_name.stat == ESP_BT_STATUS_SUCCESS ) {
|
||||
log_i("ESP_BT_GAP_READ_REMOTE_NAME_EVT: %s", param->read_rmt_name.rmt_name);
|
||||
memcpy(_rmt_name, param->read_rmt_name.rmt_name, ESP_BT_GAP_MAX_BDNAME_LEN + 1);
|
||||
_rmt_name_valid = true;
|
||||
} else {
|
||||
log_i("ESP_BT_GAP_READ_REMOTE_NAME_EVT: no success stat:%d", param->read_rmt_name.stat);
|
||||
}
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_MODE_CHG_EVT:
|
||||
|
||||
case ESP_BT_GAP_MODE_CHG_EVT: // Enum 13
|
||||
log_i("ESP_BT_GAP_MODE_CHG_EVT: mode: %d", param->mode_chg.mode);
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_REMOVE_BOND_DEV_COMPLETE_EVT: // Enum - 14 remove bond device complete event
|
||||
log_i("ESP_BT_GAP_REMOVE_BOND_DEV_COMPLETE_EVT remove bond device complete event");
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_QOS_CMPL_EVT: // Enum 15 - QOS complete event
|
||||
log_i("ESP_BT_GAP_QOS_CMPL_EVT QOS complete event");
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_ACL_CONN_CMPL_STAT_EVT: // Enum 16 - ACL connection complete status event
|
||||
log_i("ESP_BT_GAP_ACL_CONN_CMPL_STAT_EVT ACL connection complete status event");
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_ACL_DISCONN_CMPL_STAT_EVT: // Enum 17 - ACL disconnection complete status event
|
||||
log_i("ESP_BT_GAP_ACL_DISCONN_CMPL_STAT_EVT ACL disconnection complete status event: reason %d, handle %d", param->acl_disconn_cmpl_stat.reason, param->acl_disconn_cmpl_stat.handle);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_i("ESP-BT_GAP_* unknown message: %d", event);
|
||||
break;
|
||||
|
|
@ -678,24 +717,26 @@ static bool _init_bt(const char *deviceName)
|
|||
return false;
|
||||
}
|
||||
|
||||
// if (esp_bt_sleep_disable() != ESP_OK){
|
||||
// log_e("esp_bt_sleep_disable failed");
|
||||
// }
|
||||
|
||||
log_i("device name set");
|
||||
esp_bt_dev_set_device_name(deviceName);
|
||||
|
||||
if (_isPinSet) {
|
||||
log_i("pin set");
|
||||
btSetPin();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BT_SSP_ENABLED
|
||||
if (_enableSSP) {
|
||||
log_i("Simple Secure Pairing");
|
||||
esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
|
||||
esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
|
||||
esp_bt_io_cap_t iocap;
|
||||
if(_IO_CAP_INPUT && _IO_CAP_OUTPUT){
|
||||
iocap = ESP_BT_IO_CAP_IO; // Display with prompt
|
||||
}else if(!_IO_CAP_INPUT && _IO_CAP_OUTPUT){
|
||||
iocap = ESP_BT_IO_CAP_OUT; // DisplayOnly
|
||||
}else if(_IO_CAP_INPUT && !_IO_CAP_OUTPUT){
|
||||
iocap = ESP_BT_IO_CAP_IN; // Input only
|
||||
}else if(!_IO_CAP_INPUT && !_IO_CAP_OUTPUT){
|
||||
iocap = ESP_BT_IO_CAP_NONE; // No input/output
|
||||
}
|
||||
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
|
||||
}
|
||||
#endif
|
||||
|
||||
// the default BTA_DM_COD_LOUDSPEAKER does not work with the macOS BT stack
|
||||
esp_bt_cod_t cod;
|
||||
|
|
@ -871,11 +912,22 @@ void BluetoothSerial::end()
|
|||
_stop_bt();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BT_SSP_ENABLED
|
||||
void BluetoothSerial::onConfirmRequest(ConfirmRequestCb cb)
|
||||
{
|
||||
confirm_request_callback = cb;
|
||||
}
|
||||
|
||||
void BluetoothSerial::onKeyRequest(KeyRequestCb cb)
|
||||
{
|
||||
key_request_callback = cb;
|
||||
}
|
||||
|
||||
void BluetoothSerial::respondPasskey(uint32_t passkey){
|
||||
esp_bt_gap_ssp_passkey_reply(current_bd_addr, true, passkey);
|
||||
}
|
||||
#endif
|
||||
|
||||
void BluetoothSerial::onAuthComplete(AuthCompleteCb cb)
|
||||
{
|
||||
auth_complete_callback = cb;
|
||||
|
|
@ -883,7 +935,7 @@ void BluetoothSerial::onAuthComplete(AuthCompleteCb cb)
|
|||
|
||||
void BluetoothSerial::confirmReply(boolean confirm)
|
||||
{
|
||||
esp_bt_gap_ssp_confirm_reply(current_bd_addr, confirm);
|
||||
esp_bt_gap_ssp_confirm_reply(current_bd_addr, confirm);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -893,33 +945,55 @@ esp_err_t BluetoothSerial::register_callback(esp_spp_cb_t * callback)
|
|||
return ESP_OK;
|
||||
}
|
||||
|
||||
//Simple Secure Pairing
|
||||
#ifdef CONFIG_BT_SSP_ENABLED
|
||||
// Enable Simple Secure Pairing (using generated PIN)
|
||||
// This must be called before calling begin, otherwise has no effect!
|
||||
void BluetoothSerial::enableSSP() {
|
||||
if(isReady(false, READY_TIMEOUT)){
|
||||
log_i("Attempted to enable SSP for already initialized driver. Restart to take effect with end() followed by begin()");
|
||||
return;
|
||||
}
|
||||
_enableSSP = true;
|
||||
_IO_CAP_INPUT = true;
|
||||
_IO_CAP_OUTPUT = true;
|
||||
}
|
||||
/*
|
||||
* Set default parameters for Legacy Pairing
|
||||
* Use fixed pin code
|
||||
*/
|
||||
bool BluetoothSerial::setPin(const char *pin) {
|
||||
log_i("pin: %s", pin);
|
||||
bool isEmpty = !(pin && *pin);
|
||||
if (isEmpty && !_isPinSet) {
|
||||
return true; // nothing to do
|
||||
} else if (!isEmpty){
|
||||
_pin_len = strlen(pin);
|
||||
memcpy(_pin_code, pin, _pin_len);
|
||||
} else {
|
||||
_pin_len = 0; // resetting pin to none (default)
|
||||
}
|
||||
_pin_code[_pin_len] = 0;
|
||||
_isPinSet = true;
|
||||
if (isReady(false, READY_TIMEOUT)) {
|
||||
btSetPin();
|
||||
}
|
||||
return true;
|
||||
|
||||
// Enable Simple Secure Pairing (using generated PIN)
|
||||
// This must be called before calling begin, otherwise has no effect!
|
||||
// Behavior description:
|
||||
// When both Input and Output are false only the other device authenticates pairing without any pin.
|
||||
// When Output is true and Input is false only the other device authenticates pairing without any pin.
|
||||
// When both Input and Output are true both devices display randomly generated code and if they match authenticate pairing on both devices
|
||||
// - This must be implemented by registering callback via onConfirmRequest() and in this callback request user input and call confirmReply(true); if the authenticated
|
||||
// otherwise call `confirmReply(false)` to reject the pairing.
|
||||
// When Input is true and Output is false User will be required to input the passkey to the ESP32 device to authenticate.
|
||||
// - This must be implemented by registering callback via onKeyRequest() and in this callback the entered passkey will be responded via respondPasskey(passkey);
|
||||
void BluetoothSerial::enableSSP(bool inputCpability, bool outputCapability) {
|
||||
log_i("Enabling SSP: input capability=%d; output capability=%d", inputCpability, outputCapability);
|
||||
_enableSSP = true;
|
||||
_IO_CAP_INPUT = inputCpability;
|
||||
_IO_CAP_OUTPUT = outputCapability;
|
||||
}
|
||||
|
||||
// Disable Simple Secure Pairing (using generated PIN)
|
||||
// This must be called before calling begin, otherwise has no effect!
|
||||
void BluetoothSerial::disableSSP() {
|
||||
_enableSSP = false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool BluetoothSerial::setPin(const char *pin, uint8_t pin_code_len){
|
||||
if(pin_code_len == 0 || pin_code_len > 16){
|
||||
log_e("PIN code must be 1-16 Bytes long! Called with length %d", pin_code_len);
|
||||
return false;
|
||||
}
|
||||
_pin_code_len = pin_code_len;
|
||||
memcpy(_pin_code, pin, pin_code_len);
|
||||
return (esp_bt_gap_set_pin(ESP_BT_PIN_TYPE_FIXED, _pin_code_len, _pin_code) == ESP_OK);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool BluetoothSerial::connect(String remoteName)
|
||||
{
|
||||
bool retval = false;
|
||||
|
|
@ -931,9 +1005,9 @@ bool BluetoothSerial::connect(String remoteName)
|
|||
}
|
||||
disconnect();
|
||||
_doConnect = true;
|
||||
_isRemoteAddressSet = false;
|
||||
_sec_mask = ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE;
|
||||
_role = ESP_SPP_ROLE_MASTER;
|
||||
_isRemoteAddressSet = true;
|
||||
_sec_mask = ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE;
|
||||
_role = ESP_SPP_ROLE_MASTER;
|
||||
strncpy(_remote_name, remoteName.c_str(), ESP_BT_GAP_MAX_BDNAME_LEN);
|
||||
_remote_name[ESP_BT_GAP_MAX_BDNAME_LEN] = 0;
|
||||
log_i("master : remoteName");
|
||||
|
|
@ -974,8 +1048,8 @@ bool BluetoothSerial::connect(uint8_t remoteAddress[], int channel, esp_spp_sec_
|
|||
_doConnect = true;
|
||||
_remote_name[0] = 0;
|
||||
_isRemoteAddressSet = true;
|
||||
_sec_mask = sec_mask;
|
||||
_role = role;
|
||||
_sec_mask = sec_mask;
|
||||
_role = role;
|
||||
memcpy(_peer_bd_addr, remoteAddress, ESP_BD_ADDR_LEN);
|
||||
log_i("master : remoteAddress");
|
||||
xEventGroupClearBits(_spp_event_group, SPP_CLOSED);
|
||||
|
|
@ -987,7 +1061,7 @@ bool BluetoothSerial::connect(uint8_t remoteAddress[], int channel, esp_spp_sec_
|
|||
channel);
|
||||
#endif
|
||||
if(esp_spp_connect(sec_mask, role, channel, _peer_bd_addr) != ESP_OK ) {
|
||||
log_e("spp connect failed");
|
||||
log_e("spp connect failed");
|
||||
retval = false;
|
||||
} else {
|
||||
retval = waitForConnect(READY_TIMEOUT);
|
||||
|
|
@ -1088,14 +1162,16 @@ bool BluetoothSerial::isReady(bool checkMaster, int timeout) {
|
|||
|
||||
/**
|
||||
* @brief RemoteName or address are not allowed to be set during discovery
|
||||
* (otherwhise it might connect automatically and stop discovery)
|
||||
* (otherwise it might connect automatically and stop discovery)
|
||||
* @param[in] timeoutMs can range from MIN_INQ_TIME to MAX_INQ_TIME
|
||||
* @return in case of Error immediately Empty ScanResults.
|
||||
*/
|
||||
BTScanResults* BluetoothSerial::discover(int timeoutMs) {
|
||||
scanResults.clear();
|
||||
if (timeoutMs < MIN_INQ_TIME || timeoutMs > MAX_INQ_TIME || strlen(_remote_name) || _isRemoteAddressSet)
|
||||
if (timeoutMs < MIN_INQ_TIME || timeoutMs > MAX_INQ_TIME){
|
||||
log_e("Timeout out of bounds: MIN=%d; MAX=%d; requested=%d", MIN_INQ_TIME, MAX_INQ_TIME, timeoutMs);
|
||||
return nullptr;
|
||||
}
|
||||
int timeout = timeoutMs / INQ_TIME;
|
||||
log_i("discover::disconnect");
|
||||
disconnect();
|
||||
|
|
@ -1112,11 +1188,11 @@ BTScanResults* BluetoothSerial::discover(int timeoutMs) {
|
|||
|
||||
/**
|
||||
* @brief RemoteName or address are not allowed to be set during discovery
|
||||
* (otherwhise it might connect automatically and stop discovery)
|
||||
* (otherwise it might connect automatically and stop discovery)
|
||||
* @param[in] cb called when a [b]new[/b] device has been discovered
|
||||
* @param[in] timeoutMs can be 0 or range from MIN_INQ_TIME to MAX_INQ_TIME
|
||||
*
|
||||
* @return Wheter start was successfull or problems with params
|
||||
* @return Whether start was successful or problems with params
|
||||
*/
|
||||
bool BluetoothSerial::discoverAsync(BTAdvertisedDeviceCb cb, int timeoutMs) {
|
||||
scanResults.clear();
|
||||
|
|
@ -1139,7 +1215,7 @@ void BluetoothSerial::discoverAsyncStop() {
|
|||
advertisedDeviceCb = nullptr;
|
||||
}
|
||||
|
||||
/** @brief Clears scanresult entries */
|
||||
/** @brief Clears scanResult entries */
|
||||
void BluetoothSerial::discoverClear() {
|
||||
scanResults.clear();
|
||||
}
|
||||
|
|
@ -1211,4 +1287,108 @@ BTAddress BluetoothSerial::getBtAddressObject() {
|
|||
String BluetoothSerial::getBtAddressString() {
|
||||
return getBtAddressObject().toString(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Send a request to the remote device defined by the remoteAddress to send back its name.
|
||||
// The name will be read by background task and stored. It can be later read with radRemoteName()
|
||||
void BluetoothSerial::requestRemoteName(uint8_t remoteAddress[]){
|
||||
if(isReady(false, READY_TIMEOUT)){
|
||||
esp_bt_gap_read_remote_name(remoteAddress);
|
||||
}
|
||||
}
|
||||
|
||||
// If remote name is valid (was already received) this function will copy the name to the aprameter rmt_name
|
||||
// The buffer must have size at least ESP_BT_GAP_MAX_BDNAME_LEN + 1
|
||||
// If the name is valid the function will return true
|
||||
// If the name is not valid (was not read yet) returns false
|
||||
bool BluetoothSerial::readRemoteName(char rmt_name[ESP_BT_GAP_MAX_BDNAME_LEN + 1]){
|
||||
if(_rmt_name_valid){
|
||||
memcpy(rmt_name, _rmt_name, ESP_BT_GAP_MAX_BDNAME_LEN + 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set validity of remote name before reading name from different device
|
||||
void BluetoothSerial::invalidateRemoteName(){
|
||||
_rmt_name_valid = false;
|
||||
}
|
||||
|
||||
int BluetoothSerial::getNumberOfBondedDevices(){
|
||||
return esp_bt_gap_get_bond_device_num();
|
||||
}
|
||||
|
||||
// Accepts the maximum number of devices that can fit in given array dev_list.
|
||||
// Create you list this way: esp_bd_addr_t dev_list[dev_num];
|
||||
// Returns number of retrieved devices (on error returns 0)
|
||||
int BluetoothSerial::getBondedDevices(uint dev_num, esp_bd_addr_t *dev_list){
|
||||
// typedef uint8_t esp_bd_addr_t[ESP_BD_ADDR_LEN]
|
||||
if(dev_list == NULL){
|
||||
log_e("Device list is NULL");
|
||||
return 0;
|
||||
}
|
||||
if(dev_num == 0){
|
||||
log_e("Device number must be larger than 0!");
|
||||
return 0;
|
||||
}
|
||||
int _dev_num = dev_num;
|
||||
esp_bt_gap_get_bond_device_list(&_dev_num, dev_list);
|
||||
return _dev_num;
|
||||
}
|
||||
|
||||
bool BluetoothSerial::deleteBondedDevice(uint8_t *remoteAddress){
|
||||
esp_err_t ret = esp_bt_gap_remove_bond_device(remoteAddress);
|
||||
if(ret == ESP_OK){
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void BluetoothSerial::deleteAllBondedDevices(){
|
||||
if(!isReady(false, READY_TIMEOUT)){
|
||||
log_w("Attempted to drop cache for uninitialized driver. First call begin()");
|
||||
return;
|
||||
}
|
||||
|
||||
int expected_dev_num = esp_bt_gap_get_bond_device_num();
|
||||
if(expected_dev_num == 0){
|
||||
log_i("No devices in cache.");
|
||||
return;
|
||||
} else {
|
||||
log_d("Found %d bonded devices", expected_dev_num);
|
||||
}
|
||||
esp_err_t ret;
|
||||
|
||||
// typedef uint8_t esp_bd_addr_t[ESP_BD_ADDR_LEN] // ESP_BD_ADDR_LEN = 6
|
||||
esp_bd_addr_t *dev_list = NULL;
|
||||
log_d("Allocate buffer: sizeof(esp_bd_addr_t)=%d * expected_dev_num=%d", sizeof(esp_bd_addr_t), expected_dev_num);
|
||||
dev_list = (esp_bd_addr_t*) malloc(sizeof(esp_bd_addr_t) * expected_dev_num);
|
||||
if(dev_list == NULL){
|
||||
log_e("Could not allocated BT device buffer!");
|
||||
return;
|
||||
}
|
||||
//uint8_t dev_list [20][6];
|
||||
|
||||
int dev_num;
|
||||
ret = esp_bt_gap_get_bond_device_list(&dev_num, dev_list);
|
||||
log_d("esp_bt_gap_get_bond_device_list ret = %d", ret);
|
||||
if(ret == ESP_OK){
|
||||
if(dev_num != expected_dev_num){
|
||||
log_w("Inconsistent number of bonded devices. Expected %d; returned %d",expected_dev_num, dev_num);
|
||||
}
|
||||
for(int i=0; i<dev_num; ++i){
|
||||
ret = esp_bt_gap_remove_bond_device(dev_list[i]);
|
||||
log_d("esp_bt_gap_remove_bond_device ret = %d", ret);
|
||||
if(ret == ESP_OK){
|
||||
log_d("Removed bonded device #%d", i);
|
||||
} else {
|
||||
log_w("Failed to removed bonded device #%d", i);
|
||||
}
|
||||
//btc_storage_remove_bonded_device(dev_list[i]);
|
||||
}
|
||||
log_d("device num after delete = %d", esp_bt_gap_get_bond_device_num());
|
||||
}else{
|
||||
log_w("Function esp_bt_gap_get_bond_device_list() returned code %d", ret);
|
||||
}
|
||||
}
|
||||
#endif // defined(CONFIG_BT_ENABLED) && defined(CONFIG_BLUEDROID_ENABLED)
|
||||
|
|
|
|||
|
|
@ -26,9 +26,12 @@
|
|||
#include <functional>
|
||||
#include <map>
|
||||
#include "BTScan.h"
|
||||
#include "BTAdvertisedDevice.h"
|
||||
|
||||
|
||||
typedef std::function<void(const uint8_t *buffer, size_t size)> BluetoothSerialDataCb;
|
||||
typedef std::function<void(uint32_t num_val)> ConfirmRequestCb;
|
||||
typedef std::function<void()> KeyRequestCb;
|
||||
typedef std::function<void(boolean success)> AuthCompleteCb;
|
||||
typedef std::function<void(BTAdvertisedDevice* pAdvertisedDevice)> BTAdvertisedDeviceCb;
|
||||
|
||||
|
|
@ -55,16 +58,25 @@ class BluetoothSerial: public Stream
|
|||
void onData(BluetoothSerialDataCb cb);
|
||||
esp_err_t register_callback(esp_spp_cb_t * callback);
|
||||
|
||||
#ifdef CONFIG_BT_SSP_ENABLED
|
||||
void onConfirmRequest(ConfirmRequestCb cb);
|
||||
void onKeyRequest(KeyRequestCb cb);
|
||||
void respondPasskey(uint32_t passkey);
|
||||
#endif
|
||||
void onAuthComplete(AuthCompleteCb cb);
|
||||
void confirmReply(boolean confirm);
|
||||
|
||||
#ifdef CONFIG_BT_SSP_ENABLED
|
||||
void enableSSP();
|
||||
bool setPin(const char *pin);
|
||||
void enableSSP(bool inputCapability, bool outputCapability);
|
||||
void disableSSP();
|
||||
#else
|
||||
bool setPin(const char *pin, uint8_t pin_code_len);
|
||||
#endif
|
||||
bool connect(String remoteName);
|
||||
bool connect(uint8_t remoteAddress[], int channel=0, esp_spp_sec_t sec_mask=(ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE), esp_spp_role_t role=ESP_SPP_ROLE_MASTER);
|
||||
bool connect(const BTAddress &remoteAddress, int channel=0, esp_spp_sec_t sec_mask=(ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE), esp_spp_role_t role=ESP_SPP_ROLE_MASTER) {
|
||||
return connect(*remoteAddress.getNative(), channel, sec_mask); };
|
||||
return connect(*remoteAddress.getNative(), channel, sec_mask); };
|
||||
bool connect();
|
||||
bool connected(int timeout=0);
|
||||
bool isClosed();
|
||||
|
|
@ -88,6 +100,14 @@ class BluetoothSerial: public Stream
|
|||
void getBtAddress(uint8_t *mac);
|
||||
BTAddress getBtAddressObject();
|
||||
String getBtAddressString();
|
||||
//void dropCache(); // To be replaced
|
||||
void requestRemoteName(uint8_t *remoteAddress);
|
||||
bool readRemoteName(char rmt_name[ESP_BT_GAP_MAX_BDNAME_LEN + 1]);
|
||||
void invalidateRemoteName();
|
||||
int getNumberOfBondedDevices();
|
||||
int getBondedDevices(uint dev_num, esp_bd_addr_t *dev_list);
|
||||
bool deleteBondedDevice(uint8_t *remoteAddress);
|
||||
void deleteAllBondedDevices();
|
||||
private:
|
||||
String local_name;
|
||||
int timeoutTicks=0;
|
||||
|
|
|
|||
Loading…
Reference in a new issue