Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 41c372c

Browse files
authoredApr 15, 2021
[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
1 parent 223acb3 commit 41c372c

File tree

12 files changed

+609
-6
lines changed

12 files changed

+609
-6
lines changed
 

‎CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ set(LIBRARY_SRCS
4545
libraries/ArduinoOTA/src/ArduinoOTA.cpp
4646
libraries/AsyncUDP/src/AsyncUDP.cpp
4747
libraries/BluetoothSerial/src/BluetoothSerial.cpp
48+
libraries/BluetoothSerial/src/BTAddress.cpp
49+
libraries/BluetoothSerial/src/BTAdvertisedDeviceSet.cpp
50+
libraries/BluetoothSerial/src/BTScanResultsSet.cpp
4851
libraries/DNSServer/src/DNSServer.cpp
4952
libraries/EEPROM/src/EEPROM.cpp
5053
libraries/ESPmDNS/src/ESPmDNS.cpp

‎libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32c3

Whitespace-only changes.

‎libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32s2

Whitespace-only changes.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#include <BluetoothSerial.h>
2+
3+
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
4+
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
5+
#endif
6+
7+
BluetoothSerial SerialBT;
8+
9+
10+
#define BT_DISCOVER_TIME 10000
11+
12+
13+
static bool btScanAsync = true;
14+
static bool btScanSync = true;
15+
16+
17+
void btAdvertisedDeviceFound(BTAdvertisedDevice* pDevice) {
18+
Serial.printf("Found a device asynchronously: %s\n", pDevice->toString().c_str());
19+
}
20+
21+
void setup() {
22+
Serial.begin(115200);
23+
SerialBT.begin("ESP32test"); //Bluetooth device name
24+
Serial.println("The device started, now you can pair it with bluetooth!");
25+
26+
27+
if (btScanAsync) {
28+
Serial.print("Starting discoverAsync...");
29+
if (SerialBT.discoverAsync(btAdvertisedDeviceFound)) {
30+
Serial.println("Findings will be reported in \"btAdvertisedDeviceFound\"");
31+
delay(10000);
32+
Serial.print("Stopping discoverAsync... ");
33+
SerialBT.discoverAsyncStop();
34+
Serial.println("stopped");
35+
} else {
36+
Serial.println("Error on discoverAsync f.e. not workin after a \"connect\"");
37+
}
38+
}
39+
40+
if (btScanSync) {
41+
Serial.println("Starting discover...");
42+
BTScanResults *pResults = SerialBT.discover(BT_DISCOVER_TIME);
43+
if (pResults)
44+
pResults->dump(&Serial);
45+
else
46+
Serial.println("Error on BT Scan, no result!");
47+
}
48+
}
49+
50+
void loop() {
51+
delay(100);
52+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* BTAddress.cpp
3+
*
4+
* Created on: Jul 2, 2017
5+
* Author: kolban
6+
* Ported on: Feb 5, 2021
7+
* Author: Thomas M. (ArcticSnowSky)
8+
*/
9+
#include "sdkconfig.h"
10+
#if defined(CONFIG_BT_ENABLED)
11+
12+
#include "BTAddress.h"
13+
#include <string>
14+
#include <sstream>
15+
#include <iomanip>
16+
#include <string.h>
17+
#include <stdio.h>
18+
#include <malloc.h>
19+
#ifdef ARDUINO_ARCH_ESP32
20+
#include "esp32-hal-log.h"
21+
#endif
22+
23+
24+
/**
25+
* @brief Create an address from the native ESP32 representation.
26+
* @param [in] address The native representation.
27+
*/
28+
BTAddress::BTAddress(esp_bd_addr_t address) {
29+
memcpy(m_address, address, ESP_BD_ADDR_LEN);
30+
} // BTAddress
31+
32+
33+
/**
34+
* @brief Create an address from a hex string
35+
*
36+
* A hex string is of the format:
37+
* ```
38+
* 00:00:00:00:00:00
39+
* ```
40+
* which is 17 characters in length.
41+
*
42+
* @param [in] stringAddress The hex representation of the address.
43+
*/
44+
BTAddress::BTAddress(std::string stringAddress) {
45+
if (stringAddress.length() != 17) return;
46+
47+
int data[6];
48+
sscanf(stringAddress.c_str(), "%x:%x:%x:%x:%x:%x", &data[0], &data[1], &data[2], &data[3], &data[4], &data[5]);
49+
m_address[0] = (uint8_t) data[0];
50+
m_address[1] = (uint8_t) data[1];
51+
m_address[2] = (uint8_t) data[2];
52+
m_address[3] = (uint8_t) data[3];
53+
m_address[4] = (uint8_t) data[4];
54+
m_address[5] = (uint8_t) data[5];
55+
} // BTAddress
56+
57+
58+
/**
59+
* @brief Determine if this address equals another.
60+
* @param [in] otherAddress The other address to compare against.
61+
* @return True if the addresses are equal.
62+
*/
63+
bool BTAddress::equals(BTAddress otherAddress) {
64+
return memcmp(otherAddress.getNative(), m_address, 6) == 0;
65+
} // equals
66+
67+
68+
/**
69+
* @brief Return the native representation of the address.
70+
* @return The native representation of the address.
71+
*/
72+
esp_bd_addr_t *BTAddress::getNative() {
73+
return &m_address;
74+
} // getNative
75+
76+
77+
/**
78+
* @brief Convert a BT address to a string.
79+
*
80+
* A string representation of an address is in the format:
81+
*
82+
* ```
83+
* xx:xx:xx:xx:xx:xx
84+
* ```
85+
*
86+
* @return The string representation of the address.
87+
*/
88+
std::string BTAddress::toString() {
89+
auto size = 18;
90+
char *res = (char*)malloc(size);
91+
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]);
92+
std::string ret(res);
93+
free(res);
94+
return ret;
95+
} // toString
96+
#endif
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* BTAddress.h
3+
*
4+
* Created on: Jul 2, 2017
5+
* Author: kolban
6+
* Ported on: Feb 5, 2021
7+
* Author: Thomas M. (ArcticSnowSky)
8+
*/
9+
10+
#ifndef COMPONENTS_CPP_UTILS_BTADDRESS_H_
11+
#define COMPONENTS_CPP_UTILS_BTADDRESS_H_
12+
#include "sdkconfig.h"
13+
#if defined(CONFIG_BT_ENABLED)
14+
#include <esp_gap_bt_api.h> // ESP32 BT
15+
#include <string>
16+
17+
18+
/**
19+
* @brief A %BT device address.
20+
*
21+
* Every %BT device has a unique address which can be used to identify it and form connections.
22+
*/
23+
class BTAddress {
24+
public:
25+
BTAddress(esp_bd_addr_t address);
26+
BTAddress(std::string stringAddress);
27+
bool equals(BTAddress otherAddress);
28+
esp_bd_addr_t* getNative();
29+
std::string toString();
30+
31+
private:
32+
esp_bd_addr_t m_address;
33+
};
34+
35+
#endif /* CONFIG_BT_ENABLED */
36+
#endif /* COMPONENTS_CPP_UTILS_BTADDRESS_H_ */
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* BTAdvertisedDevice.h
3+
*
4+
* Created on: Feb 5, 2021
5+
* Author: Thomas M. (ArcticSnowSky)
6+
*/
7+
8+
#ifndef __BTADVERTISEDDEVICE_H__
9+
#define __BTADVERTISEDDEVICE_H__
10+
11+
#include "BTAddress.h"
12+
13+
14+
class BTAdvertisedDevice {
15+
public:
16+
virtual ~BTAdvertisedDevice() = default;
17+
18+
virtual BTAddress getAddress();
19+
virtual uint32_t getCOD();
20+
virtual std::string getName();
21+
virtual int8_t getRSSI();
22+
23+
24+
virtual bool haveCOD();
25+
virtual bool haveName();
26+
virtual bool haveRSSI();
27+
28+
virtual std::string toString();
29+
};
30+
31+
class BTAdvertisedDeviceSet : public virtual BTAdvertisedDevice {
32+
public:
33+
BTAdvertisedDeviceSet();
34+
//~BTAdvertisedDeviceSet() = default;
35+
36+
37+
BTAddress getAddress();
38+
uint32_t getCOD();
39+
std::string getName();
40+
int8_t getRSSI();
41+
42+
43+
bool haveCOD();
44+
bool haveName();
45+
bool haveRSSI();
46+
47+
std::string toString();
48+
49+
void setAddress(BTAddress address);
50+
void setCOD(uint32_t cod);
51+
void setName(std::string name);
52+
void setRSSI(int8_t rssi);
53+
54+
bool m_haveCOD;
55+
bool m_haveName;
56+
bool m_haveRSSI;
57+
58+
59+
BTAddress m_address = BTAddress((uint8_t*)"\0\0\0\0\0\0");
60+
uint32_t m_cod;
61+
std::string m_name;
62+
int8_t m_rssi;
63+
};
64+
65+
#endif
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* BTAdvertisedDeviceSet.cpp
3+
*
4+
* Created on: Feb 5, 2021
5+
* Author: Thomas M. (ArcticSnowSky)
6+
*/
7+
8+
#include "sdkconfig.h"
9+
#if defined(CONFIG_BT_ENABLED)
10+
11+
//#include <map>
12+
13+
#include "BTAdvertisedDevice.h"
14+
//#include "BTScan.h"
15+
16+
17+
BTAdvertisedDeviceSet::BTAdvertisedDeviceSet() {
18+
m_cod = 0;
19+
m_name = "";
20+
m_rssi = 0;
21+
22+
m_haveCOD = false;
23+
m_haveName = false;
24+
m_haveRSSI = false;
25+
} // BTAdvertisedDeviceSet
26+
27+
BTAddress BTAdvertisedDeviceSet::getAddress() { return m_address; }
28+
uint32_t BTAdvertisedDeviceSet::getCOD() { return m_cod; }
29+
std::string BTAdvertisedDeviceSet::getName() { return m_name; }
30+
int8_t BTAdvertisedDeviceSet::getRSSI() { return m_rssi; }
31+
32+
33+
bool BTAdvertisedDeviceSet::haveCOD() { return m_haveCOD; }
34+
bool BTAdvertisedDeviceSet::haveName() { return m_haveName; }
35+
bool BTAdvertisedDeviceSet::haveRSSI() { return m_haveRSSI; }
36+
37+
/**
38+
* @brief Create a string representation of this device.
39+
* @return A string representation of this device.
40+
*/
41+
std::string BTAdvertisedDeviceSet::toString() {
42+
std::string res = "Name: " + getName() + ", Address: " + getAddress().toString();
43+
if (haveCOD()) {
44+
char val[6];
45+
snprintf(val, sizeof(val), "%d", getCOD());
46+
res += ", cod: ";
47+
res += val;
48+
}
49+
if (haveRSSI()) {
50+
char val[4];
51+
snprintf(val, sizeof(val), "%d", getRSSI());
52+
res += ", rssi: ";
53+
res += val;
54+
}
55+
return res;
56+
} // toString
57+
58+
59+
void BTAdvertisedDeviceSet::setAddress(BTAddress address) {
60+
m_address = address;
61+
}
62+
63+
void BTAdvertisedDeviceSet::setCOD(uint32_t cod) {
64+
m_cod = cod;
65+
m_haveCOD = true;
66+
}
67+
68+
void BTAdvertisedDeviceSet::setName(std::string name) {
69+
m_name = name;
70+
m_haveName = true;
71+
}
72+
73+
void BTAdvertisedDeviceSet::setRSSI(int8_t rssi) {
74+
m_rssi = rssi;
75+
m_haveRSSI = true;
76+
}
77+
78+
#endif /* CONFIG_BT_ENABLED */
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* BTScan.h
3+
*
4+
* Created on: Feb 5, 2021
5+
* Author: Thomas M. (ArcticSnowSky)
6+
*/
7+
8+
#ifndef __BTSCAN_H__
9+
#define __BTSCAN_H__
10+
11+
#include <map>
12+
#include <string>
13+
#include <Print.h>
14+
#include "BTAddress.h"
15+
#include "BTAdvertisedDevice.h"
16+
17+
class BTAdvertisedDevice;
18+
class BTAdvertisedDeviceSet;
19+
20+
21+
class BTScanResults {
22+
public:
23+
virtual ~BTScanResults() = default;
24+
25+
virtual void dump(Print *print = nullptr);
26+
virtual int getCount();
27+
virtual BTAdvertisedDevice* getDevice(uint32_t i);
28+
};
29+
30+
class BTScanResultsSet : public BTScanResults {
31+
public:
32+
void dump(Print *print = nullptr);
33+
int getCount();
34+
BTAdvertisedDevice* getDevice(uint32_t i);
35+
36+
bool add(BTAdvertisedDeviceSet advertisedDevice, bool unique = true);
37+
void clear();
38+
39+
std::map<std::string, BTAdvertisedDeviceSet> m_vectorAdvertisedDevices;
40+
};
41+
42+
#endif
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* BTScanResultsSet.cpp
3+
*
4+
* Created on: Feb 5, 2021
5+
* Author: Thomas M. (ArcticSnowSky)
6+
*/
7+
8+
#include "sdkconfig.h"
9+
#if defined(CONFIG_BT_ENABLED)
10+
11+
12+
#include <esp_err.h>
13+
14+
#include "BTAdvertisedDevice.h"
15+
#include "BTScan.h"
16+
//#include "GeneralUtils.h"
17+
#include "esp32-hal-log.h"
18+
19+
20+
class BTAdvertisedDevice;
21+
22+
/**
23+
* @brief Dump the scan results to the log.
24+
*/
25+
void BTScanResultsSet::dump(Print *print) {
26+
int cnt = getCount();
27+
if (print == nullptr) {
28+
log_v(">> Dump scan results : %d", cnt);
29+
for (int i=0; i < cnt; i++) {
30+
BTAdvertisedDevice* dev = getDevice(i);
31+
if (dev)
32+
log_d("- %d: %s\n", i+1, dev->toString().c_str());
33+
else
34+
log_d("- %d is null\n", i+1);
35+
}
36+
log_v("-- dump finished --");
37+
} else {
38+
print->printf(">> Dump scan results: %d\n", cnt);
39+
for (int i=0; i < cnt; i++) {
40+
BTAdvertisedDevice* dev = getDevice(i);
41+
if (dev)
42+
print->printf("- %d: %s\n", i+1, dev->toString().c_str());
43+
else
44+
print->printf("- %d is null\n", i+1);
45+
}
46+
print->println("-- Dump finished --");
47+
}
48+
} // dump
49+
50+
51+
/**
52+
* @brief Return the count of devices found in the last scan.
53+
* @return The number of devices found in the last scan.
54+
*/
55+
int BTScanResultsSet::getCount() {
56+
return m_vectorAdvertisedDevices.size();
57+
} // getCount
58+
59+
60+
/**
61+
* @brief Return the specified device at the given index.
62+
* The index should be between 0 and getCount()-1.
63+
* @param [in] i The index of the device.
64+
* @return The device at the specified index.
65+
*/
66+
BTAdvertisedDevice* BTScanResultsSet::getDevice(uint32_t i) {
67+
if (i < 0)
68+
return nullptr;
69+
70+
uint32_t x = 0;
71+
BTAdvertisedDeviceSet* pDev = &m_vectorAdvertisedDevices.begin()->second;
72+
for (auto it = m_vectorAdvertisedDevices.begin(); it != m_vectorAdvertisedDevices.end(); it++) {
73+
pDev = &it->second;
74+
if (x==i) break;
75+
x++;
76+
}
77+
return x==i ? pDev : nullptr;
78+
}
79+
80+
void BTScanResultsSet::clear() {
81+
//for(auto _dev : m_vectorAdvertisedDevices)
82+
// delete _dev.second;
83+
m_vectorAdvertisedDevices.clear();
84+
}
85+
86+
bool BTScanResultsSet::add(BTAdvertisedDeviceSet advertisedDevice, bool unique) {
87+
std::string key = advertisedDevice.getAddress().toString();
88+
if (!unique || m_vectorAdvertisedDevices.count(key) == 0) {
89+
m_vectorAdvertisedDevices.insert(std::pair<std::string, BTAdvertisedDeviceSet>(key, advertisedDevice));
90+
return true;
91+
} else
92+
return false;
93+
}
94+
95+
#endif

‎libraries/BluetoothSerial/src/BluetoothSerial.cpp

100755100644
Lines changed: 129 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ static xQueueHandle _spp_tx_queue = NULL;
5252
static SemaphoreHandle_t _spp_tx_done = NULL;
5353
static TaskHandle_t _spp_task_handle = NULL;
5454
static EventGroupHandle_t _spp_event_group = NULL;
55+
static EventGroupHandle_t _bt_event_group = NULL;
5556
static boolean secondConnectionAttempt;
5657
static esp_spp_cb_t * custom_spp_callback = NULL;
5758
static BluetoothSerialDataCb custom_data_callback = NULL;
@@ -72,11 +73,18 @@ static int _pin_len;
7273
static bool _isPinSet;
7374
static bool _enableSSP;
7475

76+
static BTScanResultsSet scanResults;
77+
static BTAdvertisedDeviceCb advertisedDeviceCb = nullptr;
78+
7579
#define SPP_RUNNING 0x01
7680
#define SPP_CONNECTED 0x02
7781
#define SPP_CONGESTED 0x04
7882
#define SPP_DISCONNECTED 0x08
7983

84+
#define BT_DISCOVERY_RUNNING 0x01
85+
#define BT_DISCOVERY_COMPLETED 0x02
86+
87+
8088
typedef struct {
8189
size_t len;
8290
uint8_t data[];
@@ -368,15 +376,16 @@ void BluetoothSerial::onData(BluetoothSerialDataCb cb){
368376
static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
369377
{
370378
switch(event){
371-
case ESP_BT_GAP_DISC_RES_EVT:
379+
case ESP_BT_GAP_DISC_RES_EVT: {
372380
log_i("ESP_BT_GAP_DISC_RES_EVT");
373381
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)
374382
char bda_str[18];
375383
log_i("Scanned device: %s", bda2str(param->disc_res.bda, bda_str, 18));
376384
#endif
385+
BTAdvertisedDeviceSet advertisedDevice;
386+
uint8_t peer_bdname_len = 0;
387+
char peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
377388
for (int i = 0; i < param->disc_res.num_prop; i++) {
378-
uint8_t peer_bdname_len;
379-
char peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
380389
switch(param->disc_res.prop[i].type) {
381390
case ESP_BT_GAP_DEV_PROP_EIR:
382391
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
409418

410419
case ESP_BT_GAP_DEV_PROP_COD:
411420
log_d("ESP_BT_GAP_DEV_PROP_COD");
421+
if (param->disc_res.prop[i].len <= sizeof(int)) {
422+
uint32_t cod = 0;
423+
memcpy(&cod, param->disc_res.prop[i].val, param->disc_res.prop[i].len);
424+
advertisedDevice.setCOD(cod);
425+
} else {
426+
log_d("Value size larger than integer");
427+
}
412428
break;
413429

414430
case ESP_BT_GAP_DEV_PROP_RSSI:
415431
log_d("ESP_BT_GAP_DEV_PROP_RSSI");
432+
if (param->disc_res.prop[i].len <= sizeof(int)) {
433+
uint8_t rssi = 0;
434+
memcpy(&rssi, param->disc_res.prop[i].val, param->disc_res.prop[i].len);
435+
advertisedDevice.setRSSI(rssi);
436+
} else {
437+
log_d("Value size larger than integer");
438+
}
416439
break;
417440

418441
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
421444
if (_isRemoteAddressSet)
422445
break;
423446
}
424-
break;
447+
if (peer_bdname_len)
448+
advertisedDevice.setName(peer_bdname);
449+
esp_bd_addr_t addr;
450+
memcpy(addr, param->disc_res.bda, ESP_BD_ADDR_LEN);
451+
advertisedDevice.setAddress(BTAddress(addr));
452+
if (scanResults.add(advertisedDevice) && advertisedDeviceCb)
453+
advertisedDeviceCb(&advertisedDevice);
454+
}
455+
break;
456+
425457
case ESP_BT_GAP_DISC_STATE_CHANGED_EVT:
426458
log_i("ESP_BT_GAP_DISC_STATE_CHANGED_EVT");
459+
if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STOPPED) {
460+
xEventGroupClearBits(_bt_event_group, BT_DISCOVERY_RUNNING);
461+
xEventGroupSetBits(_bt_event_group, BT_DISCOVERY_COMPLETED);
462+
} else { // ESP_BT_GAP_DISCOVERY_STARTED
463+
xEventGroupClearBits(_bt_event_group, BT_DISCOVERY_COMPLETED);
464+
xEventGroupSetBits(_bt_event_group, BT_DISCOVERY_RUNNING);
465+
}
427466
break;
428467

429468
case ESP_BT_GAP_RMT_SRVCS_EVT:
430-
log_i( "ESP_BT_GAP_RMT_SRVCS_EVT");
469+
log_i( "ESP_BT_GAP_RMT_SRVCS_EVT: status = %d, num_uuids = %d", param->rmt_srvcs.stat, param->rmt_srvcs.num_uuids);
431470
break;
432471

433472
case ESP_BT_GAP_RMT_SRVC_REC_EVT:
434-
log_i("ESP_BT_GAP_RMT_SRVC_REC_EVT");
473+
log_i("ESP_BT_GAP_RMT_SRVC_REC_EVT: status = %d", param->rmt_srvc_rec.stat);
435474
break;
436475

437476
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
490529

491530
static bool _init_bt(const char *deviceName)
492531
{
532+
if(!_bt_event_group){
533+
_bt_event_group = xEventGroupCreate();
534+
if(!_bt_event_group){
535+
log_e("BT Event Group Create Failed!");
536+
return false;
537+
}
538+
xEventGroupClearBits(_bt_event_group, 0xFFFFFF);
539+
}
493540
if(!_spp_event_group){
494541
_spp_event_group = xEventGroupCreate();
495542
if(!_spp_event_group){
@@ -634,6 +681,10 @@ static bool _stop_bt()
634681
vSemaphoreDelete(_spp_tx_done);
635682
_spp_tx_done = NULL;
636683
}
684+
if (_bt_event_group) {
685+
vEventGroupDelete(_bt_event_group);
686+
_bt_event_group = NULL;
687+
}
637688
return true;
638689
}
639690

@@ -642,6 +693,11 @@ static bool waitForConnect(int timeout) {
642693
return (xEventGroupWaitBits(_spp_event_group, SPP_CONNECTED, pdFALSE, pdTRUE, xTicksToWait) & SPP_CONNECTED) != 0;
643694
}
644695

696+
static bool waitForDiscovered(int timeout) {
697+
TickType_t xTicksToWait = timeout / portTICK_PERIOD_MS;
698+
return (xEventGroupWaitBits(_spp_event_group, BT_DISCOVERY_COMPLETED, pdFALSE, pdTRUE, xTicksToWait) & BT_DISCOVERY_COMPLETED) != 0;
699+
}
700+
645701
/*
646702
* Serial Bluetooth Arduino
647703
*
@@ -881,6 +937,73 @@ bool BluetoothSerial::isReady(bool checkMaster, int timeout) {
881937
return (xEventGroupWaitBits(_spp_event_group, SPP_RUNNING, pdFALSE, pdTRUE, xTicksToWait) & SPP_RUNNING) != 0;
882938
}
883939

940+
941+
/**
942+
* @brief RemoteName or address are not allowed to be set during discovery
943+
* (otherwhise it might connect automatically and stop discovery)
944+
* @param[in] timeoutMs can range from MIN_INQ_TIME to MAX_INQ_TIME
945+
* @return in case of Error immediately Empty ScanResults.
946+
*/
947+
BTScanResults* BluetoothSerial::discover(int timeoutMs) {
948+
scanResults.clear();
949+
if (timeoutMs < MIN_INQ_TIME || timeoutMs > MAX_INQ_TIME || strlen(_remote_name) || _isRemoteAddressSet)
950+
return nullptr;
951+
int timeout = timeoutMs / INQ_TIME;
952+
log_i("discover::disconnect");
953+
disconnect();
954+
log_i("discovering");
955+
// will resolve name to address first - it may take a while
956+
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
957+
if (esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, timeout, 0) == ESP_OK) {
958+
waitForDiscovered(timeoutMs);
959+
esp_bt_gap_cancel_discovery();
960+
}
961+
return &scanResults;
962+
}
963+
964+
/**
965+
* @brief RemoteName or address are not allowed to be set during discovery
966+
* (otherwhise it might connect automatically and stop discovery)
967+
* @param[in] cb called when a [b]new[/b] device has been discovered
968+
* @param[in] timeoutMs can be 0 or range from MIN_INQ_TIME to MAX_INQ_TIME
969+
*
970+
* @return Wheter start was successfull or problems with params
971+
*/
972+
bool BluetoothSerial::discoverAsync(BTAdvertisedDeviceCb cb, int timeoutMs) {
973+
scanResults.clear();
974+
if (strlen(_remote_name) || _isRemoteAddressSet)
975+
return false;
976+
int timeout = timeoutMs / INQ_TIME;
977+
disconnect();
978+
advertisedDeviceCb = cb;
979+
log_i("discovering");
980+
// will resolve name to address first - it may take a while
981+
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
982+
if (timeout > 0)
983+
return esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, timeout, 0) == ESP_OK;
984+
else return esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, ESP_BT_GAP_MAX_INQ_LEN, 0) == ESP_OK;
985+
}
986+
987+
/** @brief Stops the asynchronous discovery and clears the callback */
988+
void BluetoothSerial::discoverAsyncStop() {
989+
esp_bt_gap_cancel_discovery();
990+
advertisedDeviceCb = nullptr;
991+
}
992+
993+
/** @brief Clears scanresult entries */
994+
void BluetoothSerial::discoverClear() {
995+
scanResults.clear();
996+
}
997+
998+
/** @brief Can be used while discovering asynchronously
999+
* Will be returned also on synchronous discovery.
1000+
*
1001+
* @return BTScanResults contains several information of found devices
1002+
*/
1003+
BTScanResults* BluetoothSerial::getScanResults() {
1004+
return &scanResults;
1005+
}
1006+
8841007
BluetoothSerial::operator bool() const
8851008
{
8861009
return true;

‎libraries/BluetoothSerial/src/BluetoothSerial.h

100755100644
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,15 @@
2121

2222
#include "Arduino.h"
2323
#include "Stream.h"
24+
#include <esp_gap_bt_api.h>
2425
#include <esp_spp_api.h>
2526
#include <functional>
27+
#include "BTScan.h"
2628

2729
typedef std::function<void(const uint8_t *buffer, size_t size)> BluetoothSerialDataCb;
2830
typedef std::function<void(uint32_t num_val)> ConfirmRequestCb;
2931
typedef std::function<void(boolean success)> AuthCompleteCb;
32+
typedef std::function<void(BTAdvertisedDevice* pAdvertisedDevice)> BTAdvertisedDeviceCb;
3033

3134
class BluetoothSerial: public Stream
3235
{
@@ -63,6 +66,16 @@ class BluetoothSerial: public Stream
6366
bool isReady(bool checkMaster=false, int timeout=0);
6467
bool disconnect();
6568
bool unpairDevice(uint8_t remoteAddress[]);
69+
70+
BTScanResults* discover(int timeout=0x30*1280);
71+
bool discoverAsync(BTAdvertisedDeviceCb cb, int timeout=0x30*1280);
72+
void discoverAsyncStop();
73+
void discoverClear();
74+
BTScanResults* getScanResults();
75+
76+
const int INQ_TIME = 1280; // Inquire Time unit 1280 ms
77+
const int MIN_INQ_TIME = (ESP_BT_GAP_MIN_INQ_LEN * INQ_TIME);
78+
const int MAX_INQ_TIME = (ESP_BT_GAP_MAX_INQ_LEN * INQ_TIME);
6679

6780
operator bool() const;
6881
private:

0 commit comments

Comments
 (0)
Please sign in to comment.