#include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED)
#include <freertos/FreeRTOS.h>
#include <freertos/event_groups.h>
#include <freertos/task.h>
#include <esp_err.h>
#include <nvs_flash.h>
#include <esp_bt.h>
#include <esp_bt_device.h>
#include <esp_bt_main.h>
#include <esp_gap_ble_api.h>
#include <esp_gatts_api.h>
#include <esp_gattc_api.h>
#include <esp_gatt_common_api.h>
#include <esp_err.h>
#include <esp_log.h>
#include <map>
#include <sstream>
#include <iomanip>
#include "BLEDevice.h"
#include "BLEClient.h"
#include "BLEUtils.h"
#include "GeneralUtils.h"
#ifdef ARDUINO_ARCH_ESP32
#include "esp32-hal-log.h"
#endif
static const char* LOG_TAG = "BLEDevice";
BLEServer* BLEDevice::m_pServer = nullptr;
BLEScan* BLEDevice::m_pScan = nullptr;
BLEClient* BLEDevice::m_pClient = nullptr;
bool initialized = false;
esp_ble_sec_act_t BLEDevice::m_securityLevel = (esp_ble_sec_act_t)0;
BLESecurityCallbacks* BLEDevice::m_securityCallbacks = nullptr;
uint16_t BLEDevice::m_localMTU = 23;
BLEClient* BLEDevice::createClient() {
ESP_LOGD(LOG_TAG, ">> createClient");
#ifndef CONFIG_GATTC_ENABLE
ESP_LOGE(LOG_TAG, "BLE GATTC is not enabled - CONFIG_GATTC_ENABLE not defined");
abort();
#endif
m_pClient = new BLEClient();
ESP_LOGD(LOG_TAG, "<< createClient");
return m_pClient;
}
BLEServer* BLEDevice::createServer() {
ESP_LOGD(LOG_TAG, ">> createServer");
#ifndef CONFIG_GATTS_ENABLE
ESP_LOGE(LOG_TAG, "BLE GATTS is not enabled - CONFIG_GATTS_ENABLE not defined");
abort();
#endif
m_pServer = new BLEServer();
m_pServer->createApp(0);
ESP_LOGD(LOG_TAG, "<< createServer");
return m_pServer;
}
void BLEDevice::gattServerEventHandler(
esp_gatts_cb_event_t event,
esp_gatt_if_t gatts_if,
esp_ble_gatts_cb_param_t* param
) {
ESP_LOGD(LOG_TAG, "gattServerEventHandler [esp_gatt_if: %d] ... %s",
gatts_if,
BLEUtils::gattServerEventTypeToString(event).c_str());
BLEUtils::dumpGattServerEvent(event, gatts_if, param);
switch(event) {
case ESP_GATTS_CONNECT_EVT: {
BLEDevice::m_localMTU = 23;
#ifdef CONFIG_BLE_SMP_ENABLE
if(BLEDevice::m_securityLevel){
esp_ble_set_encryption(param->connect.remote_bda, BLEDevice::m_securityLevel);
}
#endif
break;
}
case ESP_GATTS_MTU_EVT: {
BLEDevice::m_localMTU = param->mtu.mtu;
ESP_LOGI(LOG_TAG, "ESP_GATTS_MTU_EVT, MTU %d", BLEDevice::m_localMTU);
break;
}
default: {
break;
}
}
if (BLEDevice::m_pServer != nullptr) {
BLEDevice::m_pServer->handleGATTServerEvent(event, gatts_if, param);
}
}
void BLEDevice::gattClientEventHandler(
esp_gattc_cb_event_t event,
esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t* param) {
ESP_LOGD(LOG_TAG, "gattClientEventHandler [esp_gatt_if: %d] ... %s",
gattc_if, BLEUtils::gattClientEventTypeToString(event).c_str());
BLEUtils::dumpGattClientEvent(event, gattc_if, param);
switch(event) {
case ESP_GATTC_CONNECT_EVT: {
if(BLEDevice::getMTU() != 23){
esp_err_t errRc = esp_ble_gattc_send_mtu_req(gattc_if, param->connect.conn_id);
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_gattc_send_mtu_req: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
}
}
#ifdef CONFIG_BLE_SMP_ENABLE
if(BLEDevice::m_securityLevel){
esp_ble_set_encryption(param->connect.remote_bda, BLEDevice::m_securityLevel);
}
#endif
break;
}
default: {
break;
}
}
if (BLEDevice::m_pClient != nullptr) {
BLEDevice::m_pClient->gattClientEventHandler(event, gattc_if, param);
}
}
void BLEDevice::gapEventHandler(
esp_gap_ble_cb_event_t event,
esp_ble_gap_cb_param_t *param) {
BLEUtils::dumpGapEvent(event, param);
switch(event) {
case ESP_GAP_BLE_OOB_REQ_EVT:
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_OOB_REQ_EVT");
break;
case ESP_GAP_BLE_LOCAL_IR_EVT:
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_LOCAL_IR_EVT");
break;
case ESP_GAP_BLE_LOCAL_ER_EVT:
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_LOCAL_ER_EVT");
break;
case ESP_GAP_BLE_NC_REQ_EVT:
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_NC_REQ_EVT");
#ifdef CONFIG_BLE_SMP_ENABLE
if(BLEDevice::m_securityCallbacks!=nullptr){
esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, BLEDevice::m_securityCallbacks->onConfirmPIN(param->ble_security.key_notif.passkey));
}
#endif
break;
case ESP_GAP_BLE_PASSKEY_REQ_EVT:
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PASSKEY_REQ_EVT: ");
#ifdef CONFIG_BLE_SMP_ENABLE
if(BLEDevice::m_securityCallbacks!=nullptr){
esp_ble_passkey_reply(param->ble_security.ble_req.bd_addr, true, BLEDevice::m_securityCallbacks->onPassKeyRequest());
}
#endif
break;
case ESP_GAP_BLE_SEC_REQ_EVT:
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_SEC_REQ_EVT");
#ifdef CONFIG_BLE_SMP_ENABLE
if(BLEDevice::m_securityCallbacks!=nullptr){
esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, BLEDevice::m_securityCallbacks->onSecurityRequest());
}
else{
esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true);
}
#endif
break;
case ESP_GAP_BLE_PASSKEY_NOTIF_EVT:
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PASSKEY_NOTIF_EVT");
#ifdef CONFIG_BLE_SMP_ENABLE
if(BLEDevice::m_securityCallbacks!=nullptr){
ESP_LOGI(LOG_TAG, "passKey = %d", param->ble_security.key_notif.passkey);
BLEDevice::m_securityCallbacks->onPassKeyNotify(param->ble_security.key_notif.passkey);
}
#endif
break;
case ESP_GAP_BLE_KEY_EVT:
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_KEY_EVT");
#ifdef CONFIG_BLE_SMP_ENABLE
ESP_LOGI(LOG_TAG, "key type = %s", BLESecurity::esp_key_type_to_str(param->ble_security.ble_key.key_type));
#endif
break;
case ESP_GAP_BLE_AUTH_CMPL_EVT:
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_AUTH_CMPL_EVT");
#ifdef CONFIG_BLE_SMP_ENABLE
if(BLEDevice::m_securityCallbacks!=nullptr){
BLEDevice::m_securityCallbacks->onAuthenticationComplete(param->ble_security.auth_cmpl);
}
#endif
break;
default: {
break;
}
}
if (BLEDevice::m_pServer != nullptr) {
BLEDevice::m_pServer->handleGAPEvent(event, param);
}
if (BLEDevice::m_pClient != nullptr) {
BLEDevice::m_pClient->handleGAPEvent(event, param);
}
if (BLEDevice::m_pScan != nullptr) {
BLEDevice::getScan()->handleGAPEvent(event, param);
}
}
BLEAddress BLEDevice::getAddress() {
const uint8_t* bdAddr = esp_bt_dev_get_address();
esp_bd_addr_t addr;
memcpy(addr, bdAddr, sizeof(addr));
return BLEAddress(addr);
}
BLEScan* BLEDevice::getScan() {
if (m_pScan == nullptr) {
m_pScan = new BLEScan();
}
return m_pScan;
}
std::string BLEDevice::getValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID) {
ESP_LOGD(LOG_TAG, ">> getValue: bdAddress: %s, serviceUUID: %s, characteristicUUID: %s", bdAddress.toString().c_str(), serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
BLEClient *pClient = createClient();
pClient->connect(bdAddress);
std::string ret = pClient->getValue(serviceUUID, characteristicUUID);
pClient->disconnect();
ESP_LOGD(LOG_TAG, "<< getValue");
return ret;
}
void BLEDevice::init(std::string deviceName) {
if(!initialized){
initialized = true;
esp_err_t errRc = ESP_OK;
#ifdef ARDUINO_ARCH_ESP32
if (!btStart()) {
errRc = ESP_FAIL;
return;
}
#else
errRc = ::nvs_flash_init();
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "nvs_flash_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return;
}
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
errRc = esp_bt_controller_init(&bt_cfg);
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_bt_controller_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return;
}
#ifndef CLASSIC_BT_ENABLED
errRc = esp_bt_controller_enable(ESP_BT_MODE_BLE);
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_bt_controller_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return;
}
#else
errRc = esp_bt_controller_enable(ESP_BT_MODE_BTDM);
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_bt_controller_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return;
}
#endif
#endif
esp_bluedroid_status_t bt_state = esp_bluedroid_get_status();
if (bt_state == ESP_BLUEDROID_STATUS_UNINITIALIZED){
errRc = esp_bluedroid_init();
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_bluedroid_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return;
}
}
if (bt_state != ESP_BLUEDROID_STATUS_ENABLED){
errRc = esp_bluedroid_enable();
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_bluedroid_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return;
}
}
errRc = esp_ble_gap_register_callback(BLEDevice::gapEventHandler);
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_gap_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return;
}
#ifdef CONFIG_GATTC_ENABLE
errRc = esp_ble_gattc_register_callback(BLEDevice::gattClientEventHandler);
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_gattc_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return;
}
#endif
#ifdef CONFIG_GATTS_ENABLE
errRc = esp_ble_gatts_register_callback(BLEDevice::gattServerEventHandler);
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_gatts_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return;
}
#endif
errRc = ::esp_ble_gap_set_device_name(deviceName.c_str());
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_gap_set_device_name: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return;
};
#ifdef CONFIG_BLE_SMP_ENABLE
esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE;
errRc = ::esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_gap_set_security_param: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return;
};
#endif
}
vTaskDelay(200/portTICK_PERIOD_MS);
}
void BLEDevice::setPower(esp_power_level_t powerLevel) {
ESP_LOGD(LOG_TAG, ">> setPower: %d", powerLevel);
esp_err_t errRc = ::esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_DEFAULT, powerLevel);
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_tx_power_set: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
};
ESP_LOGD(LOG_TAG, "<< setPower");
}
void BLEDevice::setValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value) {
ESP_LOGD(LOG_TAG, ">> setValue: bdAddress: %s, serviceUUID: %s, characteristicUUID: %s", bdAddress.toString().c_str(), serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
BLEClient *pClient = createClient();
pClient->connect(bdAddress);
pClient->setValue(serviceUUID, characteristicUUID, value);
pClient->disconnect();
}
std::string BLEDevice::toString() {
std::ostringstream oss;
oss << "BD Address: " << getAddress().toString();
return oss.str();
}
void BLEDevice::whiteListAdd(BLEAddress address) {
ESP_LOGD(LOG_TAG, ">> whiteListAdd: %s", address.toString().c_str());
esp_err_t errRc = esp_ble_gap_update_whitelist(true, *address.getNative());
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_gap_update_whitelist: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
}
ESP_LOGD(LOG_TAG, "<< whiteListAdd");
}
void BLEDevice::whiteListRemove(BLEAddress address) {
ESP_LOGD(LOG_TAG, ">> whiteListRemove: %s", address.toString().c_str());
esp_err_t errRc = esp_ble_gap_update_whitelist(false, *address.getNative());
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_gap_update_whitelist: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
}
ESP_LOGD(LOG_TAG, "<< whiteListRemove");
}
void BLEDevice::setEncryptionLevel(esp_ble_sec_act_t level) {
BLEDevice::m_securityLevel = level;
}
void BLEDevice::setSecurityCallbacks(BLESecurityCallbacks* callbacks) {
BLEDevice::m_securityCallbacks = callbacks;
}
esp_err_t BLEDevice::setMTU(uint16_t mtu) {
ESP_LOGD(LOG_TAG, ">> setLocalMTU: %d", mtu);
esp_err_t err = esp_ble_gatt_set_local_mtu(mtu);
if(err == ESP_OK){
m_localMTU = mtu;
} else {
ESP_LOGE(LOG_TAG, "can't set local mtu value: %d", mtu);
}
ESP_LOGD(LOG_TAG, "<< setLocalMTU");
return err;
}
uint16_t BLEDevice::getMTU() {
return m_localMTU;
}
bool BLEDevice::getInitialized() {
return initialized;
}
#endif