diff options
Diffstat (limited to 'src/BLEDevice.cpp')
-rw-r--r-- | src/BLEDevice.cpp | 269 |
1 files changed, 250 insertions, 19 deletions
diff --git a/src/BLEDevice.cpp b/src/BLEDevice.cpp index a701459..b333ed7 100644 --- a/src/BLEDevice.cpp +++ b/src/BLEDevice.cpp @@ -11,11 +11,13 @@ #include <freertos/task.h> #include <esp_err.h> #include <nvs_flash.h> -#include <bt.h> // ESP32 BLE +#include <esp_bt.h> // ESP32 BLE +#include <esp_bt_device.h> // ESP32 BLE #include <esp_bt_main.h> // ESP32 BLE #include <esp_gap_ble_api.h> // ESP32 BLE #include <esp_gatts_api.h> // ESP32 BLE #include <esp_gattc_api.h> // ESP32 BLE +#include <esp_gatt_common_api.h>// ESP32 BLE #include <esp_err.h> // ESP32 ESP-IDF #include <esp_log.h> // ESP32 ESP-IDF #include <map> // Part of C++ Standard library @@ -32,20 +34,29 @@ static const char* LOG_TAG = "BLEDevice"; - /** * Singletons for the BLEDevice. */ BLEServer* BLEDevice::m_pServer = nullptr; BLEScan* BLEDevice::m_pScan = nullptr; BLEClient* BLEDevice::m_pClient = nullptr; -bool initialized = false; +bool initialized = false; // Have we been initialized? +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; + /** * @brief Create a new instance of a client. * @return A new instance of the client. */ -BLEClient* BLEDevice::createClient() { +/* STATIC */ BLEClient* BLEDevice::createClient() { + ESP_LOGD(LOG_TAG, ">> createClient"); +#ifndef CONFIG_GATTC_ENABLE // Check that BLE GATTC is enabled in make menuconfig + ESP_LOGE(LOG_TAG, "BLE GATTC is not enabled - CONFIG_GATTC_ENABLE not defined"); + abort(); +#endif // CONFIG_GATTC_ENABLE m_pClient = new BLEClient(); + ESP_LOGD(LOG_TAG, "<< createClient"); return m_pClient; } // createClient @@ -54,8 +65,12 @@ BLEClient* BLEDevice::createClient() { * @brief Create a new instance of a server. * @return A new instance of the server. */ -BLEServer* BLEDevice::createServer() { +/* STATIC */ BLEServer* BLEDevice::createServer() { ESP_LOGD(LOG_TAG, ">> createServer"); +#ifndef CONFIG_GATTS_ENABLE // Check that BLE GATTS is enabled in make menuconfig + ESP_LOGE(LOG_TAG, "BLE GATTS is not enabled - CONFIG_GATTS_ENABLE not defined"); + abort(); +#endif // CONFIG_GATTS_ENABLE m_pServer = new BLEServer(); m_pServer->createApp(0); ESP_LOGD(LOG_TAG, "<< createServer"); @@ -70,7 +85,7 @@ BLEServer* BLEDevice::createServer() { * @param [in] gatts_if The connection to the GATT interface. * @param [in] param Parameters for the event. */ -void BLEDevice::gattServerEventHandler( +/* STATIC */ void BLEDevice::gattServerEventHandler( esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param @@ -81,6 +96,26 @@ void BLEDevice::gattServerEventHandler( BLEUtils::dumpGattServerEvent(event, gatts_if, param); + switch(event) { + case ESP_GATTS_CONNECT_EVT: { + BLEDevice::m_localMTU = 23; + if(BLEDevice::m_securityLevel){ + esp_ble_set_encryption(param->connect.remote_bda, BLEDevice::m_securityLevel); + } + break; + } // ESP_GATTS_CONNECT_EVT + + 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; + } + } // switch + + if (BLEDevice::m_pServer != nullptr) { BLEDevice::m_pServer->handleGATTServerEvent(event, gatts_if, param); } @@ -96,7 +131,7 @@ void BLEDevice::gattServerEventHandler( * @param [in] gattc_if * @param [in] param */ -void BLEDevice::gattClientEventHandler( +/* STATIC */ void BLEDevice::gattClientEventHandler( esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t* param) { @@ -104,13 +139,26 @@ void BLEDevice::gattClientEventHandler( 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)); + } + } + if(BLEDevice::m_securityLevel){ + esp_ble_set_encryption(param->connect.remote_bda, BLEDevice::m_securityLevel); + } + break; + } // ESP_GATTC_CONNECT_EVT + default: { break; } } // switch - */ + // If we have a client registered, call it. if (BLEDevice::m_pClient != nullptr) { @@ -123,21 +171,70 @@ void BLEDevice::gattClientEventHandler( /** * @brief Handle GAP events. */ -void BLEDevice::gapEventHandler( +/* STATIC */ 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_SEC_REQ_EVT: { - esp_err_t errRc = ::esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gap_security_rsp: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + + case ESP_GAP_BLE_OOB_REQ_EVT: /* OOB request event */ + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_OOB_REQ_EVT"); + break; + case ESP_GAP_BLE_LOCAL_IR_EVT: /* BLE local IR event */ + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_LOCAL_IR_EVT"); + break; + case ESP_GAP_BLE_LOCAL_ER_EVT: /* BLE local ER event */ + 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"); + 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)); + } + break; + case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */ + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PASSKEY_REQ_EVT: "); + // esp_log_buffer_hex(LOG_TAG, m_remote_bda, sizeof(m_remote_bda)); + if(BLEDevice::m_securityCallbacks!=nullptr){ + esp_ble_passkey_reply(param->ble_security.ble_req.bd_addr, true, BLEDevice::m_securityCallbacks->onPassKeyRequest()); } break; - } - + /* + * TODO should we add white/black list comparison? + */ + case ESP_GAP_BLE_SEC_REQ_EVT: + /* send the positive(true) security response to the peer device to accept the security request. + If not accept the security request, should sent the security response with negative(false) accept value*/ + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_SEC_REQ_EVT"); + 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); + } + break; + /* + * + */ + case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: ///the app will receive this evt when the IO has Output capability and the peer device IO has Input capability. + ///show the passkey number to the user to input it in the peer deivce. + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PASSKEY_NOTIF_EVT"); + 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); + } + break; + case ESP_GAP_BLE_KEY_EVT: + //shows the ble key type info share with peer device to the user. + ESP_LOGI(LOG_TAG, "key type = %s", BLESecurity::esp_key_type_to_str(param->ble_security.ble_key.key_type)); + break; + case ESP_GAP_BLE_AUTH_CMPL_EVT: + if(BLEDevice::m_securityCallbacks!=nullptr){ + BLEDevice::m_securityCallbacks->onAuthenticationComplete(param->ble_security.auth_cmpl); + } + break; default: { break; } @@ -154,15 +251,33 @@ void BLEDevice::gapEventHandler( if (BLEDevice::m_pScan != nullptr) { BLEDevice::getScan()->handleGAPEvent(event, param); } + + /* + * Security events: + */ + + } // gapEventHandler /** + * @brief Get the BLE device address. + * @return The BLE device address. + */ +/* STATIC*/ 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); +} // getAddress + + +/** * @brief Retrieve the Scan object that we use for scanning. * @return The scanning object reference. This is a singleton object. The caller should not * try and release/delete it. */ -BLEScan* BLEDevice::getScan() { +/* STATIC */ BLEScan* BLEDevice::getScan() { //ESP_LOGD(LOG_TAG, ">> getScan"); if (m_pScan == nullptr) { m_pScan = new BLEScan(); @@ -174,12 +289,30 @@ BLEScan* BLEDevice::getScan() { /** + * @brief Get the value of a characteristic of a service on a remote device. + * @param [in] bdAddress + * @param [in] serviceUUID + * @param [in] characteristicUUID + */ +/* STATIC */ 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; +} // getValue + + +/** * @brief Initialize the %BLE environment. * @param deviceName The device name of the device. */ -void BLEDevice::init(std::string deviceName) { +/* STATIC */ void BLEDevice::init(std::string deviceName) { if(!initialized){ - initialized = true; + initialized = true; // Set the initialization flag to ensure we are only initialized once. + esp_err_t errRc = ::nvs_flash_init(); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "nvs_flash_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); @@ -192,6 +325,7 @@ void BLEDevice::init(std::string deviceName) { ESP_LOGE(LOG_TAG, "esp_bt_controller_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); return; } + #ifndef CLASSIC_BT_ENABLED // esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); //FIXME waiting for response from esp-idf issue errRc = esp_bt_controller_enable(ESP_BT_MODE_BLE); @@ -207,6 +341,7 @@ void BLEDevice::init(std::string deviceName) { return; } #endif + errRc = esp_bluedroid_init(); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "esp_bluedroid_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); @@ -225,17 +360,21 @@ void BLEDevice::init(std::string deviceName) { return; } +#ifdef CONFIG_GATTC_ENABLE // Check that BLE client is configured in make menuconfig 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 // CONFIG_GATTC_ENABLE +#ifdef CONFIG_GATTS_ENABLE // Check that BLE server is configured in make menuconfig 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 // CONFIG_GATTS_ENABLE errRc = ::esp_ble_gap_set_device_name(deviceName.c_str()); if (errRc != ESP_OK) { @@ -276,4 +415,96 @@ void BLEDevice::init(std::string deviceName) { ESP_LOGD(LOG_TAG, "<< setPower"); } // setPower + +/** + * @brief Set the value of a characteristic of a service on a remote device. + * @param [in] bdAddress + * @param [in] serviceUUID + * @param [in] characteristicUUID + */ +/* STATIC */ 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(); +} // setValue + + +/** + * @brief Return a string representation of the nature of this device. + * @return A string representation of the nature of this device. + */ +/* STATIC */ std::string BLEDevice::toString() { + std::ostringstream oss; + oss << "BD Address: " << getAddress().toString(); + return oss.str(); +} // toString + + +/** + * @brief Add an entry to the BLE white list. + * @param [in] address The address to add to the white list. + */ +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()); // True to add an entry. + 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"); +} // whiteListAdd + + +/** + * @brief Remove an entry from the BLE white list. + * @param [in] address The address to remove from the white list. + */ +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()); // False to remove an entry. + 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"); +} // whiteListRemove + +/* + * @brief Set encryption level that will be negotiated with peer device durng connection + * @param [in] level Requested encryption level + */ +void BLEDevice::setEncryptionLevel(esp_ble_sec_act_t level) { + BLEDevice::m_securityLevel = level; +} + +/* + * @brief Set callbacks that will be used to handle encryption negotiation events and authentication events + * @param [in] cllbacks Pointer to BLESecurityCallbacks class callback + */ +void BLEDevice::setSecurityCallbacks(BLESecurityCallbacks* callbacks) { + BLEDevice::m_securityCallbacks = callbacks; +} + +/* + * @brief Setup local mtu that will be used to negotiate mtu during request from client peer + * @param [in] mtu Value to set local mtu, should be larger than 23 and lower or equal to 517 + */ +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; +} + +/* + * @brief Get local MTU value set during mtu request or default value + */ +uint16_t BLEDevice::getMTU() { + return m_localMTU; +} #endif // CONFIG_BT_ENABLED |