#include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED)
#include "BLEAdvertising.h"
#include <esp_log.h>
#include <esp_err.h>
#include "BLEUtils.h"
#include "GeneralUtils.h"
#ifdef ARDUINO_ARCH_ESP32
#include "esp32-hal-log.h"
#endif
static const char* LOG_TAG = "BLEAdvertising";
BLEAdvertising::BLEAdvertising() {
m_advData.set_scan_rsp = false;
m_advData.include_name = true;
m_advData.include_txpower = true;
m_advData.min_interval = 0x20;
m_advData.max_interval = 0x40;
m_advData.appearance = 0x00;
m_advData.manufacturer_len = 0;
m_advData.p_manufacturer_data = nullptr;
m_advData.service_data_len = 0;
m_advData.p_service_data = nullptr;
m_advData.service_uuid_len = 0;
m_advData.p_service_uuid = nullptr;
m_advData.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT);
m_advParams.adv_int_min = 0x20;
m_advParams.adv_int_max = 0x40;
m_advParams.adv_type = ADV_TYPE_IND;
m_advParams.own_addr_type = BLE_ADDR_TYPE_PUBLIC;
m_advParams.channel_map = ADV_CHNL_ALL;
m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY;
m_customAdvData = false;
m_customScanResponseData = false;
}
void BLEAdvertising::addServiceUUID(BLEUUID serviceUUID) {
m_serviceUUIDs.push_back(serviceUUID);
}
void BLEAdvertising::addServiceUUID(const char* serviceUUID) {
addServiceUUID(BLEUUID(serviceUUID));
}
void BLEAdvertising::setAppearance(uint16_t appearance) {
m_advData.appearance = appearance;
}
void BLEAdvertising::setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly) {
ESP_LOGD(LOG_TAG, ">> setScanFilter: scanRequestWhitelistOnly: %d, connectWhitelistOnly: %d", scanRequestWhitelistOnly, connectWhitelistOnly);
if (!scanRequestWhitelistOnly && !connectWhitelistOnly) {
m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY;
ESP_LOGD(LOG_TAG, "<< setScanFilter");
return;
}
if (scanRequestWhitelistOnly && !connectWhitelistOnly) {
m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_WLST_CON_ANY;
ESP_LOGD(LOG_TAG, "<< setScanFilter");
return;
}
if (!scanRequestWhitelistOnly && connectWhitelistOnly) {
m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_WLST;
ESP_LOGD(LOG_TAG, "<< setScanFilter");
return;
}
if (scanRequestWhitelistOnly && connectWhitelistOnly) {
m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_WLST_CON_WLST;
ESP_LOGD(LOG_TAG, "<< setScanFilter");
return;
}
}
void BLEAdvertising::setAdvertisementData(BLEAdvertisementData& advertisementData) {
ESP_LOGD(LOG_TAG, ">> setAdvertisementData");
esp_err_t errRc = ::esp_ble_gap_config_adv_data_raw(
(uint8_t*)advertisementData.getPayload().data(),
advertisementData.getPayload().length());
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_gap_config_adv_data_raw: %d %s", errRc, GeneralUtils::errorToString(errRc));
}
m_customAdvData = true;
ESP_LOGD(LOG_TAG, "<< setAdvertisementData");
}
void BLEAdvertising::setScanResponseData(BLEAdvertisementData& advertisementData) {
ESP_LOGD(LOG_TAG, ">> setScanResponseData");
esp_err_t errRc = ::esp_ble_gap_config_scan_rsp_data_raw(
(uint8_t*)advertisementData.getPayload().data(),
advertisementData.getPayload().length());
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_gap_config_scan_rsp_data_raw: %d %s", errRc, GeneralUtils::errorToString(errRc));
}
m_customScanResponseData = true;
ESP_LOGD(LOG_TAG, "<< setScanResponseData");
}
void BLEAdvertising::start() {
ESP_LOGD(LOG_TAG, ">> start: customAdvData: %d, customScanResponseData: %d", m_customAdvData, m_customScanResponseData);
int numServices = m_serviceUUIDs.size();
if (numServices > 0) {
m_advData.service_uuid_len = 16*numServices;
m_advData.p_service_uuid = new uint8_t[m_advData.service_uuid_len];
uint8_t* p = m_advData.p_service_uuid;
for (int i=0; i<numServices; i++) {
ESP_LOGD(LOG_TAG, "- advertising service: %s", m_serviceUUIDs[i].toString().c_str());
BLEUUID serviceUUID128 = m_serviceUUIDs[i].to128();
memcpy(p, serviceUUID128.getNative()->uuid.uuid128, 16);
p+=16;
}
} else {
m_advData.service_uuid_len = 0;
ESP_LOGD(LOG_TAG, "- no services advertised");
}
esp_err_t errRc;
if (m_customAdvData == false) {
m_advData.set_scan_rsp = false;
errRc = ::esp_ble_gap_config_adv_data(&m_advData);
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "<< esp_ble_gap_config_adv_data: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return;
}
}
if (m_customScanResponseData == false) {
m_advData.set_scan_rsp = true;
errRc = ::esp_ble_gap_config_adv_data(&m_advData);
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "<< esp_ble_gap_config_adv_data (Scan response): rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return;
}
}
if (m_advData.service_uuid_len > 0) {
delete[] m_advData.p_service_uuid;
m_advData.p_service_uuid = nullptr;
}
errRc = ::esp_ble_gap_start_advertising(&m_advParams);
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "<< esp_ble_gap_start_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return;
}
ESP_LOGD(LOG_TAG, "<< start");
}
void BLEAdvertising::stop() {
ESP_LOGD(LOG_TAG, ">> stop");
esp_err_t errRc = ::esp_ble_gap_stop_advertising();
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_gap_stop_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return;
}
ESP_LOGD(LOG_TAG, "<< stop");
}
void BLEAdvertisementData::addData(std::string data) {
if ((m_payload.length() + data.length()) > ESP_BLE_ADV_DATA_LEN_MAX) {
return;
}
m_payload.append(data);
}
void BLEAdvertisementData::setAppearance(uint16_t appearance) {
char cdata[2];
cdata[0] = 3;
cdata[1] = ESP_BLE_AD_TYPE_APPEARANCE;
addData(std::string(cdata, 2) + std::string((char *)&appearance,2));
}
void BLEAdvertisementData::setCompleteServices(BLEUUID uuid) {
char cdata[2];
switch(uuid.bitSize()) {
case 16: {
cdata[0] = 3;
cdata[1] = ESP_BLE_AD_TYPE_16SRV_CMPL;
addData(std::string(cdata, 2) + std::string((char *)&uuid.getNative()->uuid.uuid16,2));
break;
}
case 32: {
cdata[0] = 5;
cdata[1] = ESP_BLE_AD_TYPE_32SRV_CMPL;
addData(std::string(cdata, 2) + std::string((char *)&uuid.getNative()->uuid.uuid32,4));
break;
}
case 128: {
cdata[0] = 17;
cdata[1] = ESP_BLE_AD_TYPE_128SRV_CMPL;
addData(std::string(cdata, 2) + std::string((char *)uuid.getNative()->uuid.uuid128,16));
break;
}
default:
return;
}
}
void BLEAdvertisementData::setFlags(uint8_t flag) {
char cdata[3];
cdata[0] = 2;
cdata[1] = ESP_BLE_AD_TYPE_FLAG;
cdata[2] = flag;
addData(std::string(cdata, 3));
}
void BLEAdvertisementData::setManufacturerData(std::string data) {
ESP_LOGD("BLEAdvertisementData", ">> setManufacturerData");
char cdata[2];
cdata[0] = data.length() + 1;
cdata[1] = ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE;
addData(std::string(cdata, 2) + data);
ESP_LOGD("BLEAdvertisementData", "<< setManufacturerData");
}
void BLEAdvertisementData::setName(std::string name) {
ESP_LOGD("BLEAdvertisementData", ">> setName: %s", name.c_str());
char cdata[2];
cdata[0] = name.length() + 1;
cdata[1] = ESP_BLE_AD_TYPE_NAME_CMPL;
addData(std::string(cdata, 2) + name);
ESP_LOGD("BLEAdvertisementData", "<< setName");
}
void BLEAdvertisementData::setPartialServices(BLEUUID uuid) {
char cdata[2];
switch(uuid.bitSize()) {
case 16: {
cdata[0] = 3;
cdata[1] = ESP_BLE_AD_TYPE_16SRV_PART;
addData(std::string(cdata, 2) + std::string((char *)&uuid.getNative()->uuid.uuid16,2));
break;
}
case 32: {
cdata[0] = 5;
cdata[1] = ESP_BLE_AD_TYPE_32SRV_PART;
addData(std::string(cdata, 2) + std::string((char *)&uuid.getNative()->uuid.uuid32,4));
break;
}
case 128: {
cdata[0] = 17;
cdata[1] = ESP_BLE_AD_TYPE_128SRV_PART;
addData(std::string(cdata, 2) + std::string((char *)uuid.getNative()->uuid.uuid128,16));
break;
}
default:
return;
}
}
void BLEAdvertisementData::setServiceData(BLEUUID uuid, std::string data) {
char cdata[2];
switch(uuid.bitSize()) {
case 16: {
cdata[0] = data.length() + 3;
cdata[1] = ESP_BLE_AD_TYPE_SERVICE_DATA;
addData(std::string(cdata, 2) + std::string((char *)&uuid.getNative()->uuid.uuid16,2) + data);
break;
}
case 32: {
cdata[0] = data.length() + 5;
cdata[1] = ESP_BLE_AD_TYPE_32SERVICE_DATA;
addData(std::string(cdata, 2) + std::string((char *)&uuid.getNative()->uuid.uuid32,4) + data);
break;
}
case 128: {
cdata[0] = data.length() + 17;
cdata[1] = ESP_BLE_AD_TYPE_128SERVICE_DATA;
addData(std::string(cdata, 2) + std::string((char *)uuid.getNative()->uuid.uuid128,16) + data);
break;
}
default:
return;
}
}
void BLEAdvertisementData::setShortName(std::string name) {
ESP_LOGD("BLEAdvertisementData", ">> setShortName: %s", name.c_str());
char cdata[2];
cdata[0] = name.length() + 1;
cdata[1] = ESP_BLE_AD_TYPE_NAME_SHORT;
addData(std::string(cdata, 2) + name);
ESP_LOGD("BLEAdvertisementData", "<< setShortName");
}
std::string BLEAdvertisementData::getPayload() {
return m_payload;
}
#endif