From 41c372c143a9585d67110782e735d80813f1889f Mon Sep 17 00:00:00 2001 From: Thomas M Date: Fri, 16 Apr 2021 00:37:33 +0200 Subject: [PATCH] [2.0.0] BtClassic Discovery with info without connect (#4811) Hey guys, so I wanted to do a BtClassic Discovery without the need to call connect and to list all found devices on a display and continue work with that list. I wasn't capable to test the example code with my file structure, but I did use the discovery already in some different situations. However when I noted that the Bluedroid stack won't let me enforce an RfComm SPP connection to a GPS Device (Skytraxx 2 plus, I guess its interface is built so simple that it doesn't advertise its SPP over SDP), I will probably have to switch to BtStack (BlueKitchen) and stop on this side meanwhile --- CMakeLists.txt | 3 + .../bt_classic_device_discovery/.skip.esp32c3 | 0 .../bt_classic_device_discovery/.skip.esp32s2 | 0 .../bt_classic_device_discovery.ino | 52 +++++++ libraries/BluetoothSerial/src/BTAddress.cpp | 96 +++++++++++++ libraries/BluetoothSerial/src/BTAddress.h | 36 +++++ .../BluetoothSerial/src/BTAdvertisedDevice.h | 65 +++++++++ .../src/BTAdvertisedDeviceSet.cpp | 78 ++++++++++ libraries/BluetoothSerial/src/BTScan.h | 42 ++++++ .../BluetoothSerial/src/BTScanResultsSet.cpp | 95 ++++++++++++ .../BluetoothSerial/src/BluetoothSerial.cpp | 135 +++++++++++++++++- .../BluetoothSerial/src/BluetoothSerial.h | 13 ++ 12 files changed, 609 insertions(+), 6 deletions(-) create mode 100644 libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32c3 create mode 100644 libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32s2 create mode 100644 libraries/BluetoothSerial/examples/bt_classic_device_discovery/bt_classic_device_discovery.ino create mode 100644 libraries/BluetoothSerial/src/BTAddress.cpp create mode 100644 libraries/BluetoothSerial/src/BTAddress.h create mode 100644 libraries/BluetoothSerial/src/BTAdvertisedDevice.h create mode 100644 libraries/BluetoothSerial/src/BTAdvertisedDeviceSet.cpp create mode 100644 libraries/BluetoothSerial/src/BTScan.h create mode 100644 libraries/BluetoothSerial/src/BTScanResultsSet.cpp mode change 100755 => 100644 libraries/BluetoothSerial/src/BluetoothSerial.cpp mode change 100755 => 100644 libraries/BluetoothSerial/src/BluetoothSerial.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6570e50c..55941469 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,9 @@ set(LIBRARY_SRCS libraries/ArduinoOTA/src/ArduinoOTA.cpp libraries/AsyncUDP/src/AsyncUDP.cpp libraries/BluetoothSerial/src/BluetoothSerial.cpp + libraries/BluetoothSerial/src/BTAddress.cpp + libraries/BluetoothSerial/src/BTAdvertisedDeviceSet.cpp + libraries/BluetoothSerial/src/BTScanResultsSet.cpp libraries/DNSServer/src/DNSServer.cpp libraries/EEPROM/src/EEPROM.cpp libraries/ESPmDNS/src/ESPmDNS.cpp diff --git a/libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32c3 b/libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32c3 new file mode 100644 index 00000000..e69de29b diff --git a/libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32s2 b/libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32s2 new file mode 100644 index 00000000..e69de29b 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 new file mode 100644 index 00000000..b3ec78cc --- /dev/null +++ b/libraries/BluetoothSerial/examples/bt_classic_device_discovery/bt_classic_device_discovery.ino @@ -0,0 +1,52 @@ +#include + +#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED) +#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it +#endif + +BluetoothSerial SerialBT; + + +#define BT_DISCOVER_TIME 10000 + + +static bool btScanAsync = true; +static bool btScanSync = true; + + +void btAdvertisedDeviceFound(BTAdvertisedDevice* pDevice) { + Serial.printf("Found a device asynchronously: %s\n", pDevice->toString().c_str()); +} + +void setup() { + Serial.begin(115200); + SerialBT.begin("ESP32test"); //Bluetooth device name + Serial.println("The device started, now you can pair it with bluetooth!"); + + + if (btScanAsync) { + Serial.print("Starting discoverAsync..."); + if (SerialBT.discoverAsync(btAdvertisedDeviceFound)) { + Serial.println("Findings will be reported in \"btAdvertisedDeviceFound\""); + delay(10000); + Serial.print("Stopping discoverAsync... "); + SerialBT.discoverAsyncStop(); + Serial.println("stopped"); + } else { + Serial.println("Error on discoverAsync f.e. not workin after a \"connect\""); + } + } + + if (btScanSync) { + Serial.println("Starting discover..."); + BTScanResults *pResults = SerialBT.discover(BT_DISCOVER_TIME); + if (pResults) + pResults->dump(&Serial); + else + Serial.println("Error on BT Scan, no result!"); + } +} + +void loop() { + delay(100); +} diff --git a/libraries/BluetoothSerial/src/BTAddress.cpp b/libraries/BluetoothSerial/src/BTAddress.cpp new file mode 100644 index 00000000..1ed416f2 --- /dev/null +++ b/libraries/BluetoothSerial/src/BTAddress.cpp @@ -0,0 +1,96 @@ +/* + * BTAddress.cpp + * + * Created on: Jul 2, 2017 + * Author: kolban + * Ported on: Feb 5, 2021 + * Author: Thomas M. (ArcticSnowSky) + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) + +#include "BTAddress.h" +#include +#include +#include +#include +#include +#include +#ifdef ARDUINO_ARCH_ESP32 +#include "esp32-hal-log.h" +#endif + + +/** + * @brief Create an address from the native ESP32 representation. + * @param [in] address The native representation. + */ +BTAddress::BTAddress(esp_bd_addr_t address) { + memcpy(m_address, address, ESP_BD_ADDR_LEN); +} // BTAddress + + +/** + * @brief Create an address from a hex string + * + * A hex string is of the format: + * ``` + * 00:00:00:00:00:00 + * ``` + * which is 17 characters in length. + * + * @param [in] stringAddress The hex representation of the address. + */ +BTAddress::BTAddress(std::string stringAddress) { + if (stringAddress.length() != 17) return; + + int data[6]; + sscanf(stringAddress.c_str(), "%x:%x:%x:%x:%x:%x", &data[0], &data[1], &data[2], &data[3], &data[4], &data[5]); + m_address[0] = (uint8_t) data[0]; + m_address[1] = (uint8_t) data[1]; + m_address[2] = (uint8_t) data[2]; + m_address[3] = (uint8_t) data[3]; + m_address[4] = (uint8_t) data[4]; + m_address[5] = (uint8_t) data[5]; +} // BTAddress + + +/** + * @brief Determine if this address equals another. + * @param [in] otherAddress The other address to compare against. + * @return True if the addresses are equal. + */ +bool BTAddress::equals(BTAddress otherAddress) { + return memcmp(otherAddress.getNative(), m_address, 6) == 0; +} // equals + + +/** + * @brief Return the native representation of the address. + * @return The native representation of the address. + */ +esp_bd_addr_t *BTAddress::getNative() { + return &m_address; +} // getNative + + +/** + * @brief Convert a BT address to a string. + * + * A string representation of an address is in the format: + * + * ``` + * xx:xx:xx:xx:xx:xx + * ``` + * + * @return The string representation of the address. + */ +std::string BTAddress::toString() { + auto size = 18; + char *res = (char*)malloc(size); + snprintf(res, size, "%02x:%02x:%02x:%02x:%02x:%02x", m_address[0], m_address[1], m_address[2], m_address[3], m_address[4], m_address[5]); + std::string ret(res); + free(res); + return ret; +} // toString +#endif diff --git a/libraries/BluetoothSerial/src/BTAddress.h b/libraries/BluetoothSerial/src/BTAddress.h new file mode 100644 index 00000000..e23d3459 --- /dev/null +++ b/libraries/BluetoothSerial/src/BTAddress.h @@ -0,0 +1,36 @@ +/* + * BTAddress.h + * + * Created on: Jul 2, 2017 + * Author: kolban + * Ported on: Feb 5, 2021 + * Author: Thomas M. (ArcticSnowSky) + */ + +#ifndef COMPONENTS_CPP_UTILS_BTADDRESS_H_ +#define COMPONENTS_CPP_UTILS_BTADDRESS_H_ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include // ESP32 BT +#include + + +/** + * @brief A %BT device address. + * + * Every %BT device has a unique address which can be used to identify it and form connections. + */ +class BTAddress { +public: + BTAddress(esp_bd_addr_t address); + BTAddress(std::string stringAddress); + bool equals(BTAddress otherAddress); + esp_bd_addr_t* getNative(); + std::string toString(); + +private: + esp_bd_addr_t m_address; +}; + +#endif /* CONFIG_BT_ENABLED */ +#endif /* COMPONENTS_CPP_UTILS_BTADDRESS_H_ */ diff --git a/libraries/BluetoothSerial/src/BTAdvertisedDevice.h b/libraries/BluetoothSerial/src/BTAdvertisedDevice.h new file mode 100644 index 00000000..07e93622 --- /dev/null +++ b/libraries/BluetoothSerial/src/BTAdvertisedDevice.h @@ -0,0 +1,65 @@ +/* + * BTAdvertisedDevice.h + * + * Created on: Feb 5, 2021 + * Author: Thomas M. (ArcticSnowSky) + */ + +#ifndef __BTADVERTISEDDEVICE_H__ +#define __BTADVERTISEDDEVICE_H__ + +#include "BTAddress.h" + + +class BTAdvertisedDevice { +public: + virtual ~BTAdvertisedDevice() = default; + + virtual BTAddress getAddress(); + virtual uint32_t getCOD(); + virtual std::string getName(); + virtual int8_t getRSSI(); + + + virtual bool haveCOD(); + virtual bool haveName(); + virtual bool haveRSSI(); + + virtual std::string toString(); +}; + +class BTAdvertisedDeviceSet : public virtual BTAdvertisedDevice { +public: + BTAdvertisedDeviceSet(); + //~BTAdvertisedDeviceSet() = default; + + + BTAddress getAddress(); + uint32_t getCOD(); + std::string getName(); + int8_t getRSSI(); + + + bool haveCOD(); + bool haveName(); + bool haveRSSI(); + + std::string toString(); + + void setAddress(BTAddress address); + void setCOD(uint32_t cod); + void setName(std::string name); + void setRSSI(int8_t rssi); + + bool m_haveCOD; + bool m_haveName; + bool m_haveRSSI; + + + BTAddress m_address = BTAddress((uint8_t*)"\0\0\0\0\0\0"); + uint32_t m_cod; + std::string m_name; + int8_t m_rssi; +}; + +#endif \ No newline at end of file diff --git a/libraries/BluetoothSerial/src/BTAdvertisedDeviceSet.cpp b/libraries/BluetoothSerial/src/BTAdvertisedDeviceSet.cpp new file mode 100644 index 00000000..ec8a23e8 --- /dev/null +++ b/libraries/BluetoothSerial/src/BTAdvertisedDeviceSet.cpp @@ -0,0 +1,78 @@ +/* + * BTAdvertisedDeviceSet.cpp + * + * Created on: Feb 5, 2021 + * Author: Thomas M. (ArcticSnowSky) + */ + +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) + +//#include + +#include "BTAdvertisedDevice.h" +//#include "BTScan.h" + + +BTAdvertisedDeviceSet::BTAdvertisedDeviceSet() { + m_cod = 0; + m_name = ""; + m_rssi = 0; + + m_haveCOD = false; + m_haveName = false; + m_haveRSSI = false; +} // BTAdvertisedDeviceSet + +BTAddress BTAdvertisedDeviceSet::getAddress() { return m_address; } +uint32_t BTAdvertisedDeviceSet::getCOD() { return m_cod; } +std::string BTAdvertisedDeviceSet::getName() { return m_name; } +int8_t BTAdvertisedDeviceSet::getRSSI() { return m_rssi; } + + +bool BTAdvertisedDeviceSet::haveCOD() { return m_haveCOD; } +bool BTAdvertisedDeviceSet::haveName() { return m_haveName; } +bool BTAdvertisedDeviceSet::haveRSSI() { return m_haveRSSI; } + +/** + * @brief Create a string representation of this device. + * @return A string representation of this device. + */ +std::string BTAdvertisedDeviceSet::toString() { + std::string res = "Name: " + getName() + ", Address: " + getAddress().toString(); + if (haveCOD()) { + char val[6]; + snprintf(val, sizeof(val), "%d", getCOD()); + res += ", cod: "; + res += val; + } + if (haveRSSI()) { + char val[4]; + snprintf(val, sizeof(val), "%d", getRSSI()); + res += ", rssi: "; + res += val; + } + return res; +} // toString + + +void BTAdvertisedDeviceSet::setAddress(BTAddress address) { + m_address = address; +} + +void BTAdvertisedDeviceSet::setCOD(uint32_t cod) { + m_cod = cod; + m_haveCOD = true; +} + +void BTAdvertisedDeviceSet::setName(std::string name) { + m_name = name; + m_haveName = true; +} + +void BTAdvertisedDeviceSet::setRSSI(int8_t rssi) { + m_rssi = rssi; + m_haveRSSI = true; +} + +#endif /* CONFIG_BT_ENABLED */ diff --git a/libraries/BluetoothSerial/src/BTScan.h b/libraries/BluetoothSerial/src/BTScan.h new file mode 100644 index 00000000..3650d416 --- /dev/null +++ b/libraries/BluetoothSerial/src/BTScan.h @@ -0,0 +1,42 @@ +/* + * BTScan.h + * + * Created on: Feb 5, 2021 + * Author: Thomas M. (ArcticSnowSky) + */ + +#ifndef __BTSCAN_H__ +#define __BTSCAN_H__ + +#include +#include +#include +#include "BTAddress.h" +#include "BTAdvertisedDevice.h" + +class BTAdvertisedDevice; +class BTAdvertisedDeviceSet; + + +class BTScanResults { +public: + virtual ~BTScanResults() = default; + + virtual void dump(Print *print = nullptr); + virtual int getCount(); + virtual BTAdvertisedDevice* getDevice(uint32_t i); +}; + +class BTScanResultsSet : public BTScanResults { +public: + void dump(Print *print = nullptr); + int getCount(); + BTAdvertisedDevice* getDevice(uint32_t i); + + bool add(BTAdvertisedDeviceSet advertisedDevice, bool unique = true); + void clear(); + + std::map m_vectorAdvertisedDevices; +}; + +#endif \ No newline at end of file diff --git a/libraries/BluetoothSerial/src/BTScanResultsSet.cpp b/libraries/BluetoothSerial/src/BTScanResultsSet.cpp new file mode 100644 index 00000000..c4d00fa4 --- /dev/null +++ b/libraries/BluetoothSerial/src/BTScanResultsSet.cpp @@ -0,0 +1,95 @@ +/* + * BTScanResultsSet.cpp + * + * Created on: Feb 5, 2021 + * Author: Thomas M. (ArcticSnowSky) + */ + +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) + + +#include + +#include "BTAdvertisedDevice.h" +#include "BTScan.h" +//#include "GeneralUtils.h" +#include "esp32-hal-log.h" + + +class BTAdvertisedDevice; + +/** + * @brief Dump the scan results to the log. + */ +void BTScanResultsSet::dump(Print *print) { + int cnt = getCount(); + if (print == nullptr) { + log_v(">> Dump scan results : %d", cnt); + for (int i=0; i < cnt; i++) { + BTAdvertisedDevice* dev = getDevice(i); + if (dev) + log_d("- %d: %s\n", i+1, dev->toString().c_str()); + else + log_d("- %d is null\n", i+1); + } + log_v("-- dump finished --"); + } else { + print->printf(">> Dump scan results: %d\n", cnt); + for (int i=0; i < cnt; i++) { + BTAdvertisedDevice* dev = getDevice(i); + if (dev) + print->printf("- %d: %s\n", i+1, dev->toString().c_str()); + else + print->printf("- %d is null\n", i+1); + } + print->println("-- Dump finished --"); + } +} // dump + + +/** + * @brief Return the count of devices found in the last scan. + * @return The number of devices found in the last scan. + */ +int BTScanResultsSet::getCount() { + return m_vectorAdvertisedDevices.size(); +} // getCount + + +/** + * @brief Return the specified device at the given index. + * The index should be between 0 and getCount()-1. + * @param [in] i The index of the device. + * @return The device at the specified index. + */ +BTAdvertisedDevice* BTScanResultsSet::getDevice(uint32_t i) { + if (i < 0) + return nullptr; + + uint32_t x = 0; + BTAdvertisedDeviceSet* pDev = &m_vectorAdvertisedDevices.begin()->second; + for (auto it = m_vectorAdvertisedDevices.begin(); it != m_vectorAdvertisedDevices.end(); it++) { + pDev = &it->second; + if (x==i) break; + x++; + } + return x==i ? pDev : nullptr; +} + +void BTScanResultsSet::clear() { + //for(auto _dev : m_vectorAdvertisedDevices) + // delete _dev.second; + m_vectorAdvertisedDevices.clear(); +} + +bool BTScanResultsSet::add(BTAdvertisedDeviceSet advertisedDevice, bool unique) { + std::string key = advertisedDevice.getAddress().toString(); + if (!unique || m_vectorAdvertisedDevices.count(key) == 0) { + m_vectorAdvertisedDevices.insert(std::pair(key, advertisedDevice)); + return true; + } else + return false; +} + +#endif \ No newline at end of file diff --git a/libraries/BluetoothSerial/src/BluetoothSerial.cpp b/libraries/BluetoothSerial/src/BluetoothSerial.cpp old mode 100755 new mode 100644 index ab8ab1fb..b20452c1 --- a/libraries/BluetoothSerial/src/BluetoothSerial.cpp +++ b/libraries/BluetoothSerial/src/BluetoothSerial.cpp @@ -52,6 +52,7 @@ static xQueueHandle _spp_tx_queue = NULL; static SemaphoreHandle_t _spp_tx_done = NULL; static TaskHandle_t _spp_task_handle = NULL; static EventGroupHandle_t _spp_event_group = NULL; +static EventGroupHandle_t _bt_event_group = NULL; static boolean secondConnectionAttempt; static esp_spp_cb_t * custom_spp_callback = NULL; static BluetoothSerialDataCb custom_data_callback = NULL; @@ -72,11 +73,18 @@ static int _pin_len; static bool _isPinSet; static bool _enableSSP; +static BTScanResultsSet scanResults; +static BTAdvertisedDeviceCb advertisedDeviceCb = nullptr; + #define SPP_RUNNING 0x01 #define SPP_CONNECTED 0x02 #define SPP_CONGESTED 0x04 #define SPP_DISCONNECTED 0x08 +#define BT_DISCOVERY_RUNNING 0x01 +#define BT_DISCOVERY_COMPLETED 0x02 + + typedef struct { size_t len; uint8_t data[]; @@ -368,15 +376,16 @@ void BluetoothSerial::onData(BluetoothSerialDataCb 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: { log_i("ESP_BT_GAP_DISC_RES_EVT"); #if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO) char bda_str[18]; log_i("Scanned device: %s", bda2str(param->disc_res.bda, bda_str, 18)); #endif + BTAdvertisedDeviceSet advertisedDevice; + uint8_t peer_bdname_len = 0; + char peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1]; for (int i = 0; i < param->disc_res.num_prop; i++) { - uint8_t peer_bdname_len; - char peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1]; 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)) { @@ -409,10 +418,24 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa case ESP_BT_GAP_DEV_PROP_COD: log_d("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); + } else { + log_d("Value size larger than integer"); + } break; case ESP_BT_GAP_DEV_PROP_RSSI: log_d("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); + advertisedDevice.setRSSI(rssi); + } else { + log_d("Value size larger than integer"); + } break; default: @@ -421,17 +444,33 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa if (_isRemoteAddressSet) break; } - break; + if (peer_bdname_len) + advertisedDevice.setName(peer_bdname); + esp_bd_addr_t addr; + memcpy(addr, param->disc_res.bda, ESP_BD_ADDR_LEN); + advertisedDevice.setAddress(BTAddress(addr)); + if (scanResults.add(advertisedDevice) && advertisedDeviceCb) + advertisedDeviceCb(&advertisedDevice); + } + break; + case ESP_BT_GAP_DISC_STATE_CHANGED_EVT: log_i("ESP_BT_GAP_DISC_STATE_CHANGED_EVT"); + if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STOPPED) { + xEventGroupClearBits(_bt_event_group, BT_DISCOVERY_RUNNING); + xEventGroupSetBits(_bt_event_group, BT_DISCOVERY_COMPLETED); + } else { // ESP_BT_GAP_DISCOVERY_STARTED + xEventGroupClearBits(_bt_event_group, BT_DISCOVERY_COMPLETED); + xEventGroupSetBits(_bt_event_group, BT_DISCOVERY_RUNNING); + } break; case ESP_BT_GAP_RMT_SRVCS_EVT: - log_i( "ESP_BT_GAP_RMT_SRVCS_EVT"); + 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: - log_i("ESP_BT_GAP_RMT_SRVC_REC_EVT"); + log_i("ESP_BT_GAP_RMT_SRVC_REC_EVT: status = %d", param->rmt_srvc_rec.stat); break; case ESP_BT_GAP_AUTH_CMPL_EVT: @@ -490,6 +529,14 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa static bool _init_bt(const char *deviceName) { + if(!_bt_event_group){ + _bt_event_group = xEventGroupCreate(); + if(!_bt_event_group){ + log_e("BT Event Group Create Failed!"); + return false; + } + xEventGroupClearBits(_bt_event_group, 0xFFFFFF); + } if(!_spp_event_group){ _spp_event_group = xEventGroupCreate(); if(!_spp_event_group){ @@ -634,6 +681,10 @@ static bool _stop_bt() vSemaphoreDelete(_spp_tx_done); _spp_tx_done = NULL; } + if (_bt_event_group) { + vEventGroupDelete(_bt_event_group); + _bt_event_group = NULL; + } return true; } @@ -642,6 +693,11 @@ static bool waitForConnect(int timeout) { return (xEventGroupWaitBits(_spp_event_group, SPP_CONNECTED, pdFALSE, pdTRUE, xTicksToWait) & SPP_CONNECTED) != 0; } +static bool waitForDiscovered(int timeout) { + TickType_t xTicksToWait = timeout / portTICK_PERIOD_MS; + return (xEventGroupWaitBits(_spp_event_group, BT_DISCOVERY_COMPLETED, pdFALSE, pdTRUE, xTicksToWait) & BT_DISCOVERY_COMPLETED) != 0; +} + /* * Serial Bluetooth Arduino * @@ -881,6 +937,73 @@ bool BluetoothSerial::isReady(bool checkMaster, int timeout) { return (xEventGroupWaitBits(_spp_event_group, SPP_RUNNING, pdFALSE, pdTRUE, xTicksToWait) & SPP_RUNNING) != 0; } + +/** + * @brief RemoteName or address are not allowed to be set during discovery + * (otherwhise 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) + return nullptr; + int timeout = timeoutMs / INQ_TIME; + log_i("discover::disconnect"); + disconnect(); + log_i("discovering"); + // will resolve name to address first - it may take a while + esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE); + if (esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, timeout, 0) == ESP_OK) { + waitForDiscovered(timeoutMs); + esp_bt_gap_cancel_discovery(); + } + return &scanResults; +} + +/** + * @brief RemoteName or address are not allowed to be set during discovery + * (otherwhise 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 + */ +bool BluetoothSerial::discoverAsync(BTAdvertisedDeviceCb cb, int timeoutMs) { + scanResults.clear(); + if (strlen(_remote_name) || _isRemoteAddressSet) + return false; + int timeout = timeoutMs / INQ_TIME; + disconnect(); + advertisedDeviceCb = cb; + log_i("discovering"); + // will resolve name to address first - it may take a while + esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE); + if (timeout > 0) + return esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, timeout, 0) == ESP_OK; + else return esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, ESP_BT_GAP_MAX_INQ_LEN, 0) == ESP_OK; +} + +/** @brief Stops the asynchronous discovery and clears the callback */ +void BluetoothSerial::discoverAsyncStop() { + esp_bt_gap_cancel_discovery(); + advertisedDeviceCb = nullptr; +} + +/** @brief Clears scanresult entries */ +void BluetoothSerial::discoverClear() { + scanResults.clear(); +} + +/** @brief Can be used while discovering asynchronously + * Will be returned also on synchronous discovery. + * + * @return BTScanResults contains several information of found devices + */ +BTScanResults* BluetoothSerial::getScanResults() { + return &scanResults; +} + BluetoothSerial::operator bool() const { return true; diff --git a/libraries/BluetoothSerial/src/BluetoothSerial.h b/libraries/BluetoothSerial/src/BluetoothSerial.h old mode 100755 new mode 100644 index c6b24fa9..cfb8b823 --- a/libraries/BluetoothSerial/src/BluetoothSerial.h +++ b/libraries/BluetoothSerial/src/BluetoothSerial.h @@ -21,12 +21,15 @@ #include "Arduino.h" #include "Stream.h" +#include #include #include +#include "BTScan.h" typedef std::function BluetoothSerialDataCb; typedef std::function ConfirmRequestCb; typedef std::function AuthCompleteCb; +typedef std::function BTAdvertisedDeviceCb; class BluetoothSerial: public Stream { @@ -63,6 +66,16 @@ class BluetoothSerial: public Stream bool isReady(bool checkMaster=false, int timeout=0); bool disconnect(); bool unpairDevice(uint8_t remoteAddress[]); + + BTScanResults* discover(int timeout=0x30*1280); + bool discoverAsync(BTAdvertisedDeviceCb cb, int timeout=0x30*1280); + void discoverAsyncStop(); + void discoverClear(); + BTScanResults* getScanResults(); + + const int INQ_TIME = 1280; // Inquire Time unit 1280 ms + const int MIN_INQ_TIME = (ESP_BT_GAP_MIN_INQ_LEN * INQ_TIME); + const int MAX_INQ_TIME = (ESP_BT_GAP_MAX_INQ_LEN * INQ_TIME); operator bool() const; private: