#include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED)
#include <esp_err.h>
#include <map>
#include "BLEAdvertisedDevice.h"
#include "BLEScan.h"
#include "BLEUtils.h"
#include "GeneralUtils.h"
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
#include "esp32-hal-log.h"
#define LOG_TAG ""
#else
#include "esp_log.h"
static const char* LOG_TAG = "BLEScan";
#endif
BLEScan::BLEScan() {
m_scan_params.scan_type = BLE_SCAN_TYPE_PASSIVE;
m_scan_params.own_addr_type = BLE_ADDR_TYPE_PUBLIC;
m_scan_params.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL;
m_pAdvertisedDeviceCallbacks = nullptr;
m_stopped = true;
m_wantDuplicates = false;
setInterval(100);
setWindow(100);
}
void BLEScan::handleGAPEvent(
esp_gap_ble_cb_event_t event,
esp_ble_gap_cb_param_t* param) {
switch(event) {
case ESP_GAP_BLE_SCAN_RESULT_EVT: {
switch(param->scan_rst.search_evt) {
case ESP_GAP_SEARCH_INQ_CMPL_EVT: {
ESP_LOGW(LOG_TAG, "ESP_GAP_SEARCH_INQ_CMPL_EVT");
m_stopped = true;
m_semaphoreScanEnd.give();
if (m_scanCompleteCB != nullptr) {
m_scanCompleteCB(m_scanResults);
}
break;
}
case ESP_GAP_SEARCH_INQ_RES_EVT: {
if (m_stopped) {
break;
}
BLEAddress advertisedAddress(param->scan_rst.bda);
bool found = false;
if (m_scanResults.m_vectorAdvertisedDevices.count(advertisedAddress.toString()) != 0) {
found = true;
}
if (found && !m_wantDuplicates) {
ESP_LOGD(LOG_TAG, "Ignoring %s, already seen it.", advertisedAddress.toString().c_str());
vTaskDelay(1);
break;
}
BLEAdvertisedDevice *advertisedDevice = new BLEAdvertisedDevice();
advertisedDevice->setAddress(advertisedAddress);
advertisedDevice->setRSSI(param->scan_rst.rssi);
advertisedDevice->setAdFlag(param->scan_rst.flag);
advertisedDevice->parseAdvertisement((uint8_t*)param->scan_rst.ble_adv, param->scan_rst.adv_data_len + param->scan_rst.scan_rsp_len);
advertisedDevice->setScan(this);
advertisedDevice->setAddressType(param->scan_rst.ble_addr_type);
if (!found) {
m_scanResults.m_vectorAdvertisedDevices.insert(std::pair<std::string, BLEAdvertisedDevice*>(advertisedAddress.toString(), advertisedDevice));
}
if (m_pAdvertisedDeviceCallbacks) {
m_pAdvertisedDeviceCallbacks->onResult(*advertisedDevice);
}
if(found)
delete advertisedDevice;
break;
}
default: {
break;
}
}
break;
}
default: {
break;
}
}
}
void BLEScan::setActiveScan(bool active) {
if (active) {
m_scan_params.scan_type = BLE_SCAN_TYPE_ACTIVE;
} else {
m_scan_params.scan_type = BLE_SCAN_TYPE_PASSIVE;
}
}
void BLEScan::setAdvertisedDeviceCallbacks(BLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks, bool wantDuplicates) {
m_wantDuplicates = wantDuplicates;
m_pAdvertisedDeviceCallbacks = pAdvertisedDeviceCallbacks;
}
void BLEScan::setInterval(uint16_t intervalMSecs) {
m_scan_params.scan_interval = intervalMSecs / 0.625;
}
void BLEScan::setWindow(uint16_t windowMSecs) {
m_scan_params.scan_window = windowMSecs / 0.625;
}
bool BLEScan::start(uint32_t duration, void (*scanCompleteCB)(BLEScanResults), bool is_continue) {
ESP_LOGD(LOG_TAG, ">> start(duration=%d)", duration);
m_semaphoreScanEnd.take(std::string("start"));
m_scanCompleteCB = scanCompleteCB;
if(!is_continue) {
for(auto _dev : m_scanResults.m_vectorAdvertisedDevices){
delete _dev.second;
}
m_scanResults.m_vectorAdvertisedDevices.clear();
}
esp_err_t errRc = ::esp_ble_gap_set_scan_params(&m_scan_params);
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_gap_set_scan_params: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc));
m_semaphoreScanEnd.give();
return false;
}
errRc = ::esp_ble_gap_start_scanning(duration);
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_gap_start_scanning: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc));
m_semaphoreScanEnd.give();
return false;
}
m_stopped = false;
ESP_LOGD(LOG_TAG, "<< start()");
return true;
}
BLEScanResults BLEScan::start(uint32_t duration, bool is_continue) {
if(start(duration, nullptr, is_continue)) {
m_semaphoreScanEnd.wait("start");
}
return m_scanResults;
}
void BLEScan::stop() {
ESP_LOGD(LOG_TAG, ">> stop()");
esp_err_t errRc = ::esp_ble_gap_stop_scanning();
m_stopped = true;
m_semaphoreScanEnd.give();
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_gap_stop_scanning: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc));
return;
}
ESP_LOGD(LOG_TAG, "<< stop()");
}
void BLEScan::erase(BLEAddress address) {
ESP_LOGI(LOG_TAG, "erase device: %s", address.toString().c_str());
BLEAdvertisedDevice *advertisedDevice = m_scanResults.m_vectorAdvertisedDevices.find(address.toString())->second;
m_scanResults.m_vectorAdvertisedDevices.erase(address.toString());
delete advertisedDevice;
}
void BLEScanResults::dump() {
ESP_LOGD(LOG_TAG, ">> Dump scan results:");
for (int i=0; i<getCount(); i++) {
ESP_LOGD(LOG_TAG, "- %s", getDevice(i).toString().c_str());
}
}
int BLEScanResults::getCount() {
return m_vectorAdvertisedDevices.size();
}
BLEAdvertisedDevice BLEScanResults::getDevice(uint32_t i) {
uint32_t x = 0;
BLEAdvertisedDevice dev = *m_vectorAdvertisedDevices.begin()->second;
for (auto it = m_vectorAdvertisedDevices.begin(); it != m_vectorAdvertisedDevices.end(); it++) {
dev = *it->second;
if (x==i) break;
x++;
}
return dev;
}
BLEScanResults BLEScan::getResults() {
return m_scanResults;
}
void BLEScan::clearResults() {
for(auto _dev : m_scanResults.m_vectorAdvertisedDevices){
delete _dev.second;
}
m_scanResults.m_vectorAdvertisedDevices.clear();
}
#endif