#include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED)
#include <esp_bt.h>
#include <esp_bt_main.h>
#include "GeneralUtils.h"
#include "BLEDevice.h"
#include "BLEServer.h"
#include "BLEService.h"
#include "BLEUtils.h"
#include <string.h>
#include <string>
#include <unordered_set>
#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 = "BLEServer";
#endif
BLEServer::BLEServer() {
m_appId = ESP_GATT_IF_NONE;
m_gatts_if = ESP_GATT_IF_NONE;
m_connectedCount = 0;
m_connId = ESP_GATT_IF_NONE;
m_pServerCallbacks = nullptr;
}
void BLEServer::createApp(uint16_t appId) {
m_appId = appId;
registerApp(appId);
}
BLEService* BLEServer::createService(const char* uuid) {
return createService(BLEUUID(uuid));
}
BLEService* BLEServer::createService(BLEUUID uuid, uint32_t numHandles, uint8_t inst_id) {
ESP_LOGD(LOG_TAG, ">> createService - %s", uuid.toString().c_str());
m_semaphoreCreateEvt.take("createService");
if (m_serviceMap.getByUUID(uuid) != nullptr) {
ESP_LOGW(LOG_TAG, "<< Attempt to create a new service with uuid %s but a service with that UUID already exists.",
uuid.toString().c_str());
}
BLEService* pService = new BLEService(uuid, numHandles);
pService->m_instId = inst_id;
m_serviceMap.setByUUID(uuid, pService);
pService->executeCreate(this);
m_semaphoreCreateEvt.wait("createService");
ESP_LOGD(LOG_TAG, "<< createService");
return pService;
}
BLEService* BLEServer::getServiceByUUID(const char* uuid) {
return m_serviceMap.getByUUID(uuid);
}
BLEService* BLEServer::getServiceByUUID(BLEUUID uuid) {
return m_serviceMap.getByUUID(uuid);
}
BLEAdvertising* BLEServer::getAdvertising() {
return BLEDevice::getAdvertising();
}
uint16_t BLEServer::getConnId() {
return m_connId;
}
uint32_t BLEServer::getConnectedCount() {
return m_connectedCount;
}
uint16_t BLEServer::getGattsIf() {
return m_gatts_if;
}
void BLEServer::handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param) {
ESP_LOGD(LOG_TAG, ">> handleGATTServerEvent: %s",
BLEUtils::gattServerEventTypeToString(event).c_str());
switch(event) {
case ESP_GATTS_ADD_CHAR_EVT: {
break;
}
case ESP_GATTS_MTU_EVT:
updatePeerMTU(param->mtu.conn_id, param->mtu.mtu);
break;
case ESP_GATTS_CONNECT_EVT: {
m_connId = param->connect.conn_id;
addPeerDevice((void*)this, false, m_connId);
if (m_pServerCallbacks != nullptr) {
m_pServerCallbacks->onConnect(this);
m_pServerCallbacks->onConnect(this, param);
}
m_connectedCount++;
break;
}
case ESP_GATTS_CREATE_EVT: {
BLEService* pService = m_serviceMap.getByUUID(param->create.service_id.id.uuid, param->create.service_id.id.inst_id);
m_serviceMap.setByHandle(param->create.service_handle, pService);
m_semaphoreCreateEvt.give();
break;
}
case ESP_GATTS_DISCONNECT_EVT: {
m_connectedCount--;
if (m_pServerCallbacks != nullptr) {
m_pServerCallbacks->onDisconnect(this);
}
startAdvertising();
removePeerDevice(param->disconnect.conn_id, false);
break;
}
case ESP_GATTS_READ_EVT: {
break;
}
case ESP_GATTS_REG_EVT: {
m_gatts_if = gatts_if;
m_semaphoreRegisterAppEvt.give();
break;
}
case ESP_GATTS_WRITE_EVT: {
break;
}
case ESP_GATTS_OPEN_EVT:
m_semaphoreOpenEvt.give(param->open.status);
break;
default:
break;
}
m_serviceMap.handleGATTServerEvent(event, gatts_if, param);
ESP_LOGD(LOG_TAG, "<< handleGATTServerEvent");
}
void BLEServer::registerApp(uint16_t m_appId) {
ESP_LOGD(LOG_TAG, ">> registerApp - %d", m_appId);
m_semaphoreRegisterAppEvt.take("registerApp");
::esp_ble_gatts_app_register(m_appId);
m_semaphoreRegisterAppEvt.wait("registerApp");
ESP_LOGD(LOG_TAG, "<< registerApp");
}
void BLEServer::setCallbacks(BLEServerCallbacks* pCallbacks) {
m_pServerCallbacks = pCallbacks;
}
void BLEServer::removeService(BLEService* service) {
service->stop();
service->executeDelete();
m_serviceMap.removeService(service);
}
void BLEServer::startAdvertising() {
ESP_LOGD(LOG_TAG, ">> startAdvertising");
BLEDevice::startAdvertising();
ESP_LOGD(LOG_TAG, "<< startAdvertising");
}
bool BLEServer::connect(BLEAddress address) {
esp_bd_addr_t addr;
memcpy(&addr, address.getNative(), 6);
m_semaphoreOpenEvt.take("connect");
esp_err_t errRc = ::esp_ble_gatts_open(
getGattsIf(),
addr,
1
);
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "esp_ble_gattc_open: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return false;
}
uint32_t rc = m_semaphoreOpenEvt.wait("connect");
ESP_LOGD(LOG_TAG, "<< connect(), rc=%d", rc==ESP_GATT_OK);
return rc == ESP_GATT_OK;
}
void BLEServerCallbacks::onConnect(BLEServer* pServer) {
ESP_LOGD("BLEServerCallbacks", ">> onConnect(): Default");
ESP_LOGD("BLEServerCallbacks", "Device: %s", BLEDevice::toString().c_str());
ESP_LOGD("BLEServerCallbacks", "<< onConnect()");
}
void BLEServerCallbacks::onConnect(BLEServer* pServer, esp_ble_gatts_cb_param_t* param) {
ESP_LOGD("BLEServerCallbacks", ">> onConnect(): Default");
ESP_LOGD("BLEServerCallbacks", "Device: %s", BLEDevice::toString().c_str());
ESP_LOGD("BLEServerCallbacks", "<< onConnect()");
}
void BLEServerCallbacks::onDisconnect(BLEServer* pServer) {
ESP_LOGD("BLEServerCallbacks", ">> onDisconnect(): Default");
ESP_LOGD("BLEServerCallbacks", "Device: %s", BLEDevice::toString().c_str());
ESP_LOGD("BLEServerCallbacks", "<< onDisconnect()");
}
void BLEServer::updatePeerMTU(uint16_t conn_id, uint16_t mtu) {
const std::map<uint16_t, conn_status_t>::iterator it = m_connectedServersMap.find(conn_id);
if (it != m_connectedServersMap.end()) {
it->second.mtu = mtu;
std::swap(m_connectedServersMap[conn_id], it->second);
}
}
std::map<uint16_t, conn_status_t> BLEServer::getPeerDevices(bool _client) {
return m_connectedServersMap;
}
uint16_t BLEServer::getPeerMTU(uint16_t conn_id) {
return m_connectedServersMap.find(conn_id)->second.mtu;
}
void BLEServer::addPeerDevice(void* peer, bool _client, uint16_t conn_id) {
conn_status_t status = {
.peer_device = peer,
.connected = true,
.mtu = 23
};
m_connectedServersMap.insert(std::pair<uint16_t, conn_status_t>(conn_id, status));
}
void BLEServer::removePeerDevice(uint16_t conn_id, bool _client) {
m_connectedServersMap.erase(conn_id);
}
void BLEServer::updateConnParams(esp_bd_addr_t remote_bda, uint16_t minInterval, uint16_t maxInterval, uint16_t latency, uint16_t timeout) {
esp_ble_conn_update_params_t conn_params;
memcpy(conn_params.bda, remote_bda, sizeof(esp_bd_addr_t));
conn_params.latency = latency;
conn_params.max_int = maxInterval;
conn_params.min_int = minInterval;
conn_params.timeout = timeout;
esp_ble_gap_update_conn_params(&conn_params);
}
#endif