diff --git a/libraries/BluetoothSerial/README.md b/libraries/BluetoothSerial/README.md
index 9d25dbca0a9..4989b3a088c 100644
--- a/libraries/BluetoothSerial/README.md
+++ b/libraries/BluetoothSerial/README.md
@@ -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
-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
+#### 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.
\ No newline at end of file
diff --git a/libraries/BluetoothSerial/examples/DiscoverConnect/DiscoverConnect.ino b/libraries/BluetoothSerial/examples/DiscoverConnect/DiscoverConnect.ino
index 168ea9d19c4..4269598b80f 100644
--- a/libraries/BluetoothSerial/examples/DiscoverConnect/DiscoverConnect.ino
+++ b/libraries/BluetoothSerial/examples/DiscoverConnect/DiscoverConnect.ino
@@ -19,19 +19,18 @@
#include
#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 btDeviceList;
diff --git a/libraries/BluetoothSerial/examples/GetLocalMAC/GetLocalMAC.ino b/libraries/BluetoothSerial/examples/GetLocalMAC/GetLocalMAC.ino
index a3ca6b026b6..2930067bf5d 100644
--- a/libraries/BluetoothSerial/examples/GetLocalMAC/GetLocalMAC.ino
+++ b/libraries/BluetoothSerial/examples/GetLocalMAC/GetLocalMAC.ino
@@ -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;
diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino b/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino
index 5027ae6a7e3..c5ac06b992f 100644
--- a/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino
+++ b/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino
@@ -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() {
diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBTM/SerialToSerialBTM.ino b/libraries/BluetoothSerial/examples/SerialToSerialBTM/SerialToSerialBTM.ino
index d71941b002d..a4917bfa141 100644
--- a/libraries/BluetoothSerial/examples/SerialToSerialBTM/SerialToSerialBTM.ino
+++ b/libraries/BluetoothSerial/examples/SerialToSerialBTM/SerialToSerialBTM.ino
@@ -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
diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP_pairing/.skip.esp32c3 b/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/.skip.esp32c3
similarity index 100%
rename from libraries/BluetoothSerial/examples/SerialToSerialBT_SSP_pairing/.skip.esp32c3
rename to libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/.skip.esp32c3
diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP_pairing/.skip.esp32c6 b/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/.skip.esp32c6
similarity index 100%
rename from libraries/BluetoothSerial/examples/SerialToSerialBT_SSP_pairing/.skip.esp32c6
rename to libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/.skip.esp32c6
diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP_pairing/.skip.esp32h2 b/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/.skip.esp32h2
similarity index 100%
rename from libraries/BluetoothSerial/examples/SerialToSerialBT_SSP_pairing/.skip.esp32h2
rename to libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/.skip.esp32h2
diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP_pairing/.skip.esp32s2 b/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/.skip.esp32s2
similarity index 100%
rename from libraries/BluetoothSerial/examples/SerialToSerialBT_SSP_pairing/.skip.esp32s2
rename to libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/.skip.esp32s2
diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP_pairing/.skip.esp32s3 b/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/.skip.esp32s3
similarity index 100%
rename from libraries/BluetoothSerial/examples/SerialToSerialBT_SSP_pairing/.skip.esp32s3
rename to libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/.skip.esp32s3
diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/SerialToSerialBT_Legacy.ino b/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/SerialToSerialBT_Legacy.ino
new file mode 100644
index 00000000000..2343b5ca93d
--- /dev/null
+++ b/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/SerialToSerialBT_Legacy.ino
@@ -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
diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/.skip.esp32c3 b/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/.skip.esp32c3
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/.skip.esp32c6 b/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/.skip.esp32c6
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/.skip.esp32h2 b/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/.skip.esp32h2
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/.skip.esp32s2 b/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/.skip.esp32s2
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/.skip.esp32s3 b/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/.skip.esp32s3
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/SerialToSerialBT_SSP.ino b/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/SerialToSerialBT_SSP.ino
new file mode 100644
index 00000000000..a39dbf1a064
--- /dev/null
+++ b/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/SerialToSerialBT_SSP.ino
@@ -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
+ }
+}
diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP_pairing/SerialToSerialBT_SSP_pairing.ino b/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP_pairing/SerialToSerialBT_SSP_pairing.ino
deleted file mode 100644
index c440545fcf3..00000000000
--- a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP_pairing/SerialToSerialBT_SSP_pairing.ino
+++ /dev/null
@@ -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);
- }
-}
diff --git a/libraries/BluetoothSerial/examples/bt_classic_device_discovery/bt_classic_device_discovery.ino b/libraries/BluetoothSerial/examples/bt_classic_device_discovery/bt_classic_device_discovery.ino
index 8d44f262174..b4ee741924d 100644
--- a/libraries/BluetoothSerial/examples/bt_classic_device_discovery/bt_classic_device_discovery.ino
+++ b/libraries/BluetoothSerial/examples/bt_classic_device_discovery/bt_classic_device_discovery.ino
@@ -1,17 +1,17 @@
#include
#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);
diff --git a/libraries/BluetoothSerial/examples/bt_remove_paired_devices/bt_remove_paired_devices.ino b/libraries/BluetoothSerial/examples/bt_remove_paired_devices/bt_remove_paired_devices.ino
index 0d49fe46414..d6f6786828a 100755
--- a/libraries/BluetoothSerial/examples/bt_remove_paired_devices/bt_remove_paired_devices.ino
+++ b/libraries/BluetoothSerial/examples/bt_remove_paired_devices/bt_remove_paired_devices.ino
@@ -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];
-
-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;
-}
+BluetoothSerial SerialBT;
-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() {}
diff --git a/libraries/BluetoothSerial/src/BTScan.h b/libraries/BluetoothSerial/src/BTScan.h
index 2851fdd3626..2fa1b65c50a 100644
--- a/libraries/BluetoothSerial/src/BTScan.h
+++ b/libraries/BluetoothSerial/src/BTScan.h
@@ -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 m_vectorAdvertisedDevices;
};
diff --git a/libraries/BluetoothSerial/src/BluetoothSerial.cpp b/libraries/BluetoothSerial/src/BluetoothSerial.cpp
index 52254437923..419809d3f25 100644
--- a/libraries/BluetoothSerial/src/BluetoothSerial.cpp
+++ b/libraries/BluetoothSerial/src/BluetoothSerial.cpp
@@ -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);
- }
- 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;
- }
- }
- }
+ case ESP_SPP_UNINIT_EVT: // Enum 1 - When SPP is deinitialized
+ log_i("ESP_SPP_UNINIT_EVT: SPP is deinitialized");
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,21 +438,7 @@ 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:
- 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
- && strncmp(peer_bdname, _remote_name, peer_bdname_len) == 0) {
- log_v("ESP_BT_GAP_DISC_RES_EVT : SPP_START_DISCOVERY_EIR : %s", peer_bdname, peer_bdname_len);
- _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_BDNAME:
+ 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
@@ -456,10 +450,10 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
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:
+ 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);
@@ -470,7 +464,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_DEV_PROP_RSSI:
+ 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);
@@ -480,7 +474,21 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
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
+ && strncmp(peer_bdname, _remote_name, peer_bdname_len) == 0) {
+ log_v("ESP_BT_GAP_DISC_RES_EVT : SPP_START_DISCOVERY_EIR : %s", peer_bdname, peer_bdname_len);
+ _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;
+
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,32 +945,54 @@ 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();
+
+// 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;
}
- return true;
+ _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)
{
@@ -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
#include