[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
This commit is contained in:
parent
223acb3511
commit
41c372c143
@ -45,6 +45,9 @@ set(LIBRARY_SRCS
|
|||||||
libraries/ArduinoOTA/src/ArduinoOTA.cpp
|
libraries/ArduinoOTA/src/ArduinoOTA.cpp
|
||||||
libraries/AsyncUDP/src/AsyncUDP.cpp
|
libraries/AsyncUDP/src/AsyncUDP.cpp
|
||||||
libraries/BluetoothSerial/src/BluetoothSerial.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/DNSServer/src/DNSServer.cpp
|
||||||
libraries/EEPROM/src/EEPROM.cpp
|
libraries/EEPROM/src/EEPROM.cpp
|
||||||
libraries/ESPmDNS/src/ESPmDNS.cpp
|
libraries/ESPmDNS/src/ESPmDNS.cpp
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
#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
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
96
libraries/BluetoothSerial/src/BTAddress.cpp
Normal file
96
libraries/BluetoothSerial/src/BTAddress.cpp
Normal file
@ -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 <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#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
|
36
libraries/BluetoothSerial/src/BTAddress.h
Normal file
36
libraries/BluetoothSerial/src/BTAddress.h
Normal file
@ -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 <esp_gap_bt_api.h> // ESP32 BT
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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_ */
|
65
libraries/BluetoothSerial/src/BTAdvertisedDevice.h
Normal file
65
libraries/BluetoothSerial/src/BTAdvertisedDevice.h
Normal file
@ -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
|
78
libraries/BluetoothSerial/src/BTAdvertisedDeviceSet.cpp
Normal file
78
libraries/BluetoothSerial/src/BTAdvertisedDeviceSet.cpp
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* BTAdvertisedDeviceSet.cpp
|
||||||
|
*
|
||||||
|
* Created on: Feb 5, 2021
|
||||||
|
* Author: Thomas M. (ArcticSnowSky)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#if defined(CONFIG_BT_ENABLED)
|
||||||
|
|
||||||
|
//#include <map>
|
||||||
|
|
||||||
|
#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 */
|
42
libraries/BluetoothSerial/src/BTScan.h
Normal file
42
libraries/BluetoothSerial/src/BTScan.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* BTScan.h
|
||||||
|
*
|
||||||
|
* Created on: Feb 5, 2021
|
||||||
|
* Author: Thomas M. (ArcticSnowSky)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BTSCAN_H__
|
||||||
|
#define __BTSCAN_H__
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <Print.h>
|
||||||
|
#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<std::string, BTAdvertisedDeviceSet> m_vectorAdvertisedDevices;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
95
libraries/BluetoothSerial/src/BTScanResultsSet.cpp
Normal file
95
libraries/BluetoothSerial/src/BTScanResultsSet.cpp
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* BTScanResultsSet.cpp
|
||||||
|
*
|
||||||
|
* Created on: Feb 5, 2021
|
||||||
|
* Author: Thomas M. (ArcticSnowSky)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#if defined(CONFIG_BT_ENABLED)
|
||||||
|
|
||||||
|
|
||||||
|
#include <esp_err.h>
|
||||||
|
|
||||||
|
#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<std::string, BTAdvertisedDeviceSet>(key, advertisedDevice));
|
||||||
|
return true;
|
||||||
|
} else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
133
libraries/BluetoothSerial/src/BluetoothSerial.cpp
Executable file → Normal file
133
libraries/BluetoothSerial/src/BluetoothSerial.cpp
Executable file → Normal file
@ -52,6 +52,7 @@ static xQueueHandle _spp_tx_queue = NULL;
|
|||||||
static SemaphoreHandle_t _spp_tx_done = NULL;
|
static SemaphoreHandle_t _spp_tx_done = NULL;
|
||||||
static TaskHandle_t _spp_task_handle = NULL;
|
static TaskHandle_t _spp_task_handle = NULL;
|
||||||
static EventGroupHandle_t _spp_event_group = NULL;
|
static EventGroupHandle_t _spp_event_group = NULL;
|
||||||
|
static EventGroupHandle_t _bt_event_group = NULL;
|
||||||
static boolean secondConnectionAttempt;
|
static boolean secondConnectionAttempt;
|
||||||
static esp_spp_cb_t * custom_spp_callback = NULL;
|
static esp_spp_cb_t * custom_spp_callback = NULL;
|
||||||
static BluetoothSerialDataCb custom_data_callback = NULL;
|
static BluetoothSerialDataCb custom_data_callback = NULL;
|
||||||
@ -72,11 +73,18 @@ static int _pin_len;
|
|||||||
static bool _isPinSet;
|
static bool _isPinSet;
|
||||||
static bool _enableSSP;
|
static bool _enableSSP;
|
||||||
|
|
||||||
|
static BTScanResultsSet scanResults;
|
||||||
|
static BTAdvertisedDeviceCb advertisedDeviceCb = nullptr;
|
||||||
|
|
||||||
#define SPP_RUNNING 0x01
|
#define SPP_RUNNING 0x01
|
||||||
#define SPP_CONNECTED 0x02
|
#define SPP_CONNECTED 0x02
|
||||||
#define SPP_CONGESTED 0x04
|
#define SPP_CONGESTED 0x04
|
||||||
#define SPP_DISCONNECTED 0x08
|
#define SPP_DISCONNECTED 0x08
|
||||||
|
|
||||||
|
#define BT_DISCOVERY_RUNNING 0x01
|
||||||
|
#define BT_DISCOVERY_COMPLETED 0x02
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t len;
|
size_t len;
|
||||||
uint8_t data[];
|
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)
|
static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
|
||||||
{
|
{
|
||||||
switch(event){
|
switch(event){
|
||||||
case ESP_BT_GAP_DISC_RES_EVT:
|
case ESP_BT_GAP_DISC_RES_EVT: {
|
||||||
log_i("ESP_BT_GAP_DISC_RES_EVT");
|
log_i("ESP_BT_GAP_DISC_RES_EVT");
|
||||||
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)
|
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)
|
||||||
char bda_str[18];
|
char bda_str[18];
|
||||||
log_i("Scanned device: %s", bda2str(param->disc_res.bda, bda_str, 18));
|
log_i("Scanned device: %s", bda2str(param->disc_res.bda, bda_str, 18));
|
||||||
#endif
|
#endif
|
||||||
for (int i = 0; i < param->disc_res.num_prop; i++) {
|
BTAdvertisedDeviceSet advertisedDevice;
|
||||||
uint8_t peer_bdname_len;
|
uint8_t peer_bdname_len = 0;
|
||||||
char peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
|
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) {
|
switch(param->disc_res.prop[i].type) {
|
||||||
case ESP_BT_GAP_DEV_PROP_EIR:
|
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)) {
|
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:
|
case ESP_BT_GAP_DEV_PROP_COD:
|
||||||
log_d("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;
|
break;
|
||||||
|
|
||||||
case ESP_BT_GAP_DEV_PROP_RSSI:
|
case ESP_BT_GAP_DEV_PROP_RSSI:
|
||||||
log_d("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;
|
break;
|
||||||
|
|
||||||
default:
|
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)
|
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;
|
break;
|
||||||
|
|
||||||
case ESP_BT_GAP_DISC_STATE_CHANGED_EVT:
|
case ESP_BT_GAP_DISC_STATE_CHANGED_EVT:
|
||||||
log_i("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;
|
break;
|
||||||
|
|
||||||
case ESP_BT_GAP_RMT_SRVCS_EVT:
|
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;
|
break;
|
||||||
|
|
||||||
case ESP_BT_GAP_RMT_SRVC_REC_EVT:
|
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;
|
break;
|
||||||
|
|
||||||
case ESP_BT_GAP_AUTH_CMPL_EVT:
|
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)
|
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){
|
if(!_spp_event_group){
|
||||||
_spp_event_group = xEventGroupCreate();
|
_spp_event_group = xEventGroupCreate();
|
||||||
if(!_spp_event_group){
|
if(!_spp_event_group){
|
||||||
@ -634,6 +681,10 @@ static bool _stop_bt()
|
|||||||
vSemaphoreDelete(_spp_tx_done);
|
vSemaphoreDelete(_spp_tx_done);
|
||||||
_spp_tx_done = NULL;
|
_spp_tx_done = NULL;
|
||||||
}
|
}
|
||||||
|
if (_bt_event_group) {
|
||||||
|
vEventGroupDelete(_bt_event_group);
|
||||||
|
_bt_event_group = NULL;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -642,6 +693,11 @@ static bool waitForConnect(int timeout) {
|
|||||||
return (xEventGroupWaitBits(_spp_event_group, SPP_CONNECTED, pdFALSE, pdTRUE, xTicksToWait) & SPP_CONNECTED) != 0;
|
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
|
* 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;
|
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
|
BluetoothSerial::operator bool() const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
13
libraries/BluetoothSerial/src/BluetoothSerial.h
Executable file → Normal file
13
libraries/BluetoothSerial/src/BluetoothSerial.h
Executable file → Normal file
@ -21,12 +21,15 @@
|
|||||||
|
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#include "Stream.h"
|
#include "Stream.h"
|
||||||
|
#include <esp_gap_bt_api.h>
|
||||||
#include <esp_spp_api.h>
|
#include <esp_spp_api.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include "BTScan.h"
|
||||||
|
|
||||||
typedef std::function<void(const uint8_t *buffer, size_t size)> BluetoothSerialDataCb;
|
typedef std::function<void(const uint8_t *buffer, size_t size)> BluetoothSerialDataCb;
|
||||||
typedef std::function<void(uint32_t num_val)> ConfirmRequestCb;
|
typedef std::function<void(uint32_t num_val)> ConfirmRequestCb;
|
||||||
typedef std::function<void(boolean success)> AuthCompleteCb;
|
typedef std::function<void(boolean success)> AuthCompleteCb;
|
||||||
|
typedef std::function<void(BTAdvertisedDevice* pAdvertisedDevice)> BTAdvertisedDeviceCb;
|
||||||
|
|
||||||
class BluetoothSerial: public Stream
|
class BluetoothSerial: public Stream
|
||||||
{
|
{
|
||||||
@ -64,6 +67,16 @@ class BluetoothSerial: public Stream
|
|||||||
bool disconnect();
|
bool disconnect();
|
||||||
bool unpairDevice(uint8_t remoteAddress[]);
|
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;
|
operator bool() const;
|
||||||
private:
|
private:
|
||||||
String local_name;
|
String local_name;
|
||||||
|
Loading…
Reference in New Issue
Block a user