diff options
Diffstat (limited to 'src/BLEClient.cpp')
-rw-r--r-- | src/BLEClient.cpp | 536 |
1 files changed, 0 insertions, 536 deletions
diff --git a/src/BLEClient.cpp b/src/BLEClient.cpp deleted file mode 100644 index 0e552ec..0000000 --- a/src/BLEClient.cpp +++ /dev/null @@ -1,536 +0,0 @@ -/* - * BLEDevice.cpp - * - * Created on: Mar 22, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include <esp_bt.h> -#include <esp_bt_main.h> -#include <esp_gap_ble_api.h> -#include <esp_gattc_api.h> -#include "BLEClient.h" -#include "BLEUtils.h" -#include "BLEService.h" -#include "GeneralUtils.h" -#include <string> -#include <sstream> -#include <unordered_set> -#include "BLEDevice.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 = "BLEClient"; -#endif - - -/* - * Design - * ------ - * When we perform a searchService() requests, we are asking the BLE server to return each of the services - * that it exposes. For each service, we received an ESP_GATTC_SEARCH_RES_EVT event which contains details - * of the exposed service including its UUID. - * - * The objects we will invent for a BLEClient will be as follows: - * * BLERemoteService - A model of a remote service. - * * BLERemoteCharacteristic - A model of a remote characteristic - * * BLERemoteDescriptor - A model of a remote descriptor. - * - * Since there is a hierarchical relationship here, we will have the idea that from a BLERemoteService will own - * zero or more remote characteristics and a BLERemoteCharacteristic will own zero or more remote BLEDescriptors. - * - * We will assume that a BLERemoteService contains a map that maps BLEUUIDs to the set of owned characteristics - * and that a BLECharacteristic contains a map that maps BLEUUIDs to the set of owned descriptors. - * - * - */ - -BLEClient::BLEClient() { - m_pClientCallbacks = nullptr; - m_conn_id = ESP_GATT_IF_NONE; - m_gattc_if = ESP_GATT_IF_NONE; - m_haveServices = false; - m_isConnected = false; // Initially, we are flagged as not connected. -} // BLEClient - - -/** - * @brief Destructor. - */ -BLEClient::~BLEClient() { - // We may have allocated service references associated with this client. Before we are finished - // with the client, we must release resources. - for (auto &myPair : m_servicesMap) { - delete myPair.second; - } - m_servicesMap.clear(); -} // ~BLEClient - - -/** - * @brief Clear any existing services. - * - */ -void BLEClient::clearServices() { - ESP_LOGD(LOG_TAG, ">> clearServices"); - // Delete all the services. - for (auto &myPair : m_servicesMap) { - delete myPair.second; - } - m_servicesMap.clear(); - m_haveServices = false; - ESP_LOGD(LOG_TAG, "<< clearServices"); -} // clearServices - -/** - * Add overloaded function to ease connect to peer device with not public address - */ -bool BLEClient::connect(BLEAdvertisedDevice* device) { - BLEAddress address = device->getAddress(); - esp_ble_addr_type_t type = device->getAddressType(); - return connect(address, type); -} - -/** - * @brief Connect to the partner (BLE Server). - * @param [in] address The address of the partner. - * @return True on success. - */ -bool BLEClient::connect(BLEAddress address, esp_ble_addr_type_t type) { - ESP_LOGD(LOG_TAG, ">> connect(%s)", address.toString().c_str()); - -// We need the connection handle that we get from registering the application. We register the app -// and then block on its completion. When the event has arrived, we will have the handle. - m_appId = BLEDevice::m_appId++; - BLEDevice::addPeerDevice(this, true, m_appId); - m_semaphoreRegEvt.take("connect"); - - // clearServices(); // we dont need to delete services since every client is unique? - esp_err_t errRc = ::esp_ble_gattc_app_register(m_appId); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gattc_app_register: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return false; - } - - m_semaphoreRegEvt.wait("connect"); - - m_peerAddress = address; - - // Perform the open connection request against the target BLE Server. - m_semaphoreOpenEvt.take("connect"); - errRc = ::esp_ble_gattc_open( - m_gattc_if, - *getPeerAddress().getNative(), // address - type, // Note: This was added on 2018-04-03 when the latest ESP-IDF was detected to have changed the signature. - 1 // direct connection <-- maybe needs to be changed in case of direct indirect connection??? - ); - 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"); // Wait for the connection to complete. - ESP_LOGD(LOG_TAG, "<< connect(), rc=%d", rc==ESP_GATT_OK); - return rc == ESP_GATT_OK; -} // connect - - -/** - * @brief Disconnect from the peer. - * @return N/A. - */ -void BLEClient::disconnect() { - ESP_LOGD(LOG_TAG, ">> disconnect()"); - esp_err_t errRc = ::esp_ble_gattc_close(getGattcIf(), getConnId()); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gattc_close: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - ESP_LOGD(LOG_TAG, "<< disconnect()"); -} // disconnect - - -/** - * @brief Handle GATT Client events - */ -void BLEClient::gattClientEventHandler( - esp_gattc_cb_event_t event, - esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t* evtParam) { - - ESP_LOGD(LOG_TAG, "gattClientEventHandler [esp_gatt_if: %d] ... %s", - gattc_if, BLEUtils::gattClientEventTypeToString(event).c_str()); - - // Execute handler code based on the type of event received. - switch(event) { - - case ESP_GATTC_SRVC_CHG_EVT: - ESP_LOGI(LOG_TAG, "SERVICE CHANGED"); - break; - - case ESP_GATTC_CLOSE_EVT: { - // esp_ble_gattc_app_unregister(m_appId); - // BLEDevice::removePeerDevice(m_gattc_if, true); - break; - } - - // - // ESP_GATTC_DISCONNECT_EVT - // - // disconnect: - // - esp_gatt_status_t status - // - uint16_t conn_id - // - esp_bd_addr_t remote_bda - case ESP_GATTC_DISCONNECT_EVT: { - // If we receive a disconnect event, set the class flag that indicates that we are - // no longer connected. - m_isConnected = false; - if (m_pClientCallbacks != nullptr) { - m_pClientCallbacks->onDisconnect(this); - } - BLEDevice::removePeerDevice(m_appId, true); - esp_ble_gattc_app_unregister(m_gattc_if); - m_semaphoreRssiCmplEvt.give(); - m_semaphoreSearchCmplEvt.give(1); - break; - } // ESP_GATTC_DISCONNECT_EVT - - // - // ESP_GATTC_OPEN_EVT - // - // open: - // - esp_gatt_status_t status - // - uint16_t conn_id - // - esp_bd_addr_t remote_bda - // - case ESP_GATTC_OPEN_EVT: { - m_conn_id = evtParam->open.conn_id; - if (m_pClientCallbacks != nullptr) { - m_pClientCallbacks->onConnect(this); - } - if (evtParam->open.status == ESP_GATT_OK) { - m_isConnected = true; // Flag us as connected. - } - m_semaphoreOpenEvt.give(evtParam->open.status); - break; - } // ESP_GATTC_OPEN_EVT - - - // - // ESP_GATTC_REG_EVT - // - // reg: - // esp_gatt_status_t status - // uint16_t app_id - // - case ESP_GATTC_REG_EVT: { - m_gattc_if = gattc_if; - m_semaphoreRegEvt.give(); - break; - } // ESP_GATTC_REG_EVT - - case ESP_GATTC_CFG_MTU_EVT: - if(evtParam->cfg_mtu.status != ESP_GATT_OK) { - ESP_LOGE(LOG_TAG,"Config mtu failed"); - } - m_mtu = evtParam->cfg_mtu.mtu; - break; - - case ESP_GATTC_CONNECT_EVT: { - BLEDevice::updatePeerDevice(this, true, m_gattc_if); - esp_err_t errRc = esp_ble_gattc_send_mtu_req(gattc_if, evtParam->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 // Check that BLE SMP (security) is configured in make menuconfig - if(BLEDevice::m_securityLevel){ - esp_ble_set_encryption(evtParam->connect.remote_bda, BLEDevice::m_securityLevel); - } -#endif // CONFIG_BLE_SMP_ENABLE - break; - } // ESP_GATTC_CONNECT_EVT - - // - // ESP_GATTC_SEARCH_CMPL_EVT - // - // search_cmpl: - // - esp_gatt_status_t status - // - uint16_t conn_id - // - case ESP_GATTC_SEARCH_CMPL_EVT: { - esp_ble_gattc_cb_param_t* p_data = (esp_ble_gattc_cb_param_t*)evtParam; - if (p_data->search_cmpl.status != ESP_GATT_OK){ - ESP_LOGE(LOG_TAG, "search service failed, error status = %x", p_data->search_cmpl.status); - break; - } -#ifndef ARDUINO_ARCH_ESP32 -// commented out just for now to keep backward compatibility - // if(p_data->search_cmpl.searched_service_source == ESP_GATT_SERVICE_FROM_REMOTE_DEVICE) { - // ESP_LOGI(LOG_TAG, "Get service information from remote device"); - // } else if (p_data->search_cmpl.searched_service_source == ESP_GATT_SERVICE_FROM_NVS_FLASH) { - // ESP_LOGI(LOG_TAG, "Get service information from flash"); - // } else { - // ESP_LOGI(LOG_TAG, "unknown service source"); - // } -#endif - m_semaphoreSearchCmplEvt.give(0); - break; - } // ESP_GATTC_SEARCH_CMPL_EVT - - - // - // ESP_GATTC_SEARCH_RES_EVT - // - // search_res: - // - uint16_t conn_id - // - uint16_t start_handle - // - uint16_t end_handle - // - esp_gatt_id_t srvc_id - // - case ESP_GATTC_SEARCH_RES_EVT: { - BLEUUID uuid = BLEUUID(evtParam->search_res.srvc_id); - BLERemoteService* pRemoteService = new BLERemoteService( - evtParam->search_res.srvc_id, - this, - evtParam->search_res.start_handle, - evtParam->search_res.end_handle - ); - m_servicesMap.insert(std::pair<std::string, BLERemoteService*>(uuid.toString(), pRemoteService)); - m_servicesMapByInstID.insert(std::pair<BLERemoteService *, uint16_t>(pRemoteService, evtParam->search_res.srvc_id.inst_id)); - break; - } // ESP_GATTC_SEARCH_RES_EVT - - - default: { - break; - } - } // Switch - - // Pass the request on to all services. - for (auto &myPair : m_servicesMap) { - myPair.second->gattClientEventHandler(event, gattc_if, evtParam); - } - -} // gattClientEventHandler - - -uint16_t BLEClient::getConnId() { - return m_conn_id; -} // getConnId - - - -esp_gatt_if_t BLEClient::getGattcIf() { - return m_gattc_if; -} // getGattcIf - - -/** - * @brief Retrieve the address of the peer. - * - * Returns the Bluetooth device address of the %BLE peer to which this client is connected. - */ -BLEAddress BLEClient::getPeerAddress() { - return m_peerAddress; -} // getAddress - - -/** - * @brief Ask the BLE server for the RSSI value. - * @return The RSSI value. - */ -int BLEClient::getRssi() { - ESP_LOGD(LOG_TAG, ">> getRssi()"); - if (!isConnected()) { - ESP_LOGD(LOG_TAG, "<< getRssi(): Not connected"); - return 0; - } - // We make the API call to read the RSSI value which is an asynchronous operation. We expect to receive - // an ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT to indicate completion. - // - m_semaphoreRssiCmplEvt.take("getRssi"); - esp_err_t rc = ::esp_ble_gap_read_rssi(*getPeerAddress().getNative()); - if (rc != ESP_OK) { - ESP_LOGE(LOG_TAG, "<< getRssi: esp_ble_gap_read_rssi: rc=%d %s", rc, GeneralUtils::errorToString(rc)); - return 0; - } - int rssiValue = m_semaphoreRssiCmplEvt.wait("getRssi"); - ESP_LOGD(LOG_TAG, "<< getRssi(): %d", rssiValue); - return rssiValue; -} // getRssi - - -/** - * @brief Get the service BLE Remote Service instance corresponding to the uuid. - * @param [in] uuid The UUID of the service being sought. - * @return A reference to the Service or nullptr if don't know about it. - */ -BLERemoteService* BLEClient::getService(const char* uuid) { - return getService(BLEUUID(uuid)); -} // getService - - -/** - * @brief Get the service object corresponding to the uuid. - * @param [in] uuid The UUID of the service being sought. - * @return A reference to the Service or nullptr if don't know about it. - * @throws BLEUuidNotFound - */ -BLERemoteService* BLEClient::getService(BLEUUID uuid) { - ESP_LOGD(LOG_TAG, ">> getService: uuid: %s", uuid.toString().c_str()); -// Design -// ------ -// We wish to retrieve the service given its UUID. It is possible that we have not yet asked the -// device what services it has in which case we have nothing to match against. If we have not -// asked the device about its services, then we do that now. Once we get the results we can then -// examine the services map to see if it has the service we are looking for. - if (!m_haveServices) { - getServices(); - } - std::string uuidStr = uuid.toString(); - for (auto &myPair : m_servicesMap) { - if (myPair.first == uuidStr) { - ESP_LOGD(LOG_TAG, "<< getService: found the service with uuid: %s", uuid.toString().c_str()); - return myPair.second; - } - } // End of each of the services. - ESP_LOGD(LOG_TAG, "<< getService: not found"); - return nullptr; -} // getService - - -/** - * @brief Ask the remote %BLE server for its services. - * A %BLE Server exposes a set of services for its partners. Here we ask the server for its set of - * services and wait until we have received them all. - * @return N/A - */ -std::map<std::string, BLERemoteService*>* BLEClient::getServices() { -/* - * Design - * ------ - * We invoke esp_ble_gattc_search_service. This will request a list of the service exposed by the - * peer BLE partner to be returned as events. Each event will be an an instance of ESP_GATTC_SEARCH_RES_EVT - * and will culminate with an ESP_GATTC_SEARCH_CMPL_EVT when all have been received. - */ - ESP_LOGD(LOG_TAG, ">> getServices"); -// TODO implement retrieving services from cache - clearServices(); // Clear any services that may exist. - - esp_err_t errRc = esp_ble_gattc_search_service( - getGattcIf(), - getConnId(), - NULL // Filter UUID - ); - - m_semaphoreSearchCmplEvt.take("getServices"); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gattc_search_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return &m_servicesMap; - } - // If sucessfull, remember that we now have services. - m_haveServices = (m_semaphoreSearchCmplEvt.wait("getServices") == 0); - ESP_LOGD(LOG_TAG, "<< getServices"); - return &m_servicesMap; -} // getServices - - -/** - * @brief Get the value of a specific characteristic associated with a specific service. - * @param [in] serviceUUID The service that owns the characteristic. - * @param [in] characteristicUUID The characteristic whose value we wish to read. - * @throws BLEUuidNotFound - */ -std::string BLEClient::getValue(BLEUUID serviceUUID, BLEUUID characteristicUUID) { - ESP_LOGD(LOG_TAG, ">> getValue: serviceUUID: %s, characteristicUUID: %s", serviceUUID.toString().c_str(), characteristicUUID.toString().c_str()); - std::string ret = getService(serviceUUID)->getCharacteristic(characteristicUUID)->readValue(); - ESP_LOGD(LOG_TAG, "<<getValue"); - return ret; -} // getValue - - -/** - * @brief Handle a received GAP event. - * - * @param [in] event - * @param [in] param - */ -void BLEClient::handleGAPEvent( - esp_gap_ble_cb_event_t event, - esp_ble_gap_cb_param_t* param) { - ESP_LOGD(LOG_TAG, "BLEClient ... handling GAP event!"); - switch (event) { - // - // ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT - // - // read_rssi_cmpl - // - esp_bt_status_t status - // - int8_t rssi - // - esp_bd_addr_t remote_addr - // - case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT: { - m_semaphoreRssiCmplEvt.give((uint32_t) param->read_rssi_cmpl.rssi); - break; - } // ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT - - default: - break; - } -} // handleGAPEvent - - -/** - * @brief Are we connected to a partner? - * @return True if we are connected and false if we are not connected. - */ -bool BLEClient::isConnected() { - return m_isConnected; -} // isConnected - - - - -/** - * @brief Set the callbacks that will be invoked. - */ -void BLEClient::setClientCallbacks(BLEClientCallbacks* pClientCallbacks) { - m_pClientCallbacks = pClientCallbacks; -} // setClientCallbacks - - -/** - * @brief Set the value of a specific characteristic associated with a specific service. - * @param [in] serviceUUID The service that owns the characteristic. - * @param [in] characteristicUUID The characteristic whose value we wish to write. - * @throws BLEUuidNotFound - */ -void BLEClient::setValue(BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value) { - ESP_LOGD(LOG_TAG, ">> setValue: serviceUUID: %s, characteristicUUID: %s", serviceUUID.toString().c_str(), characteristicUUID.toString().c_str()); - getService(serviceUUID)->getCharacteristic(characteristicUUID)->writeValue(value); - ESP_LOGD(LOG_TAG, "<< setValue"); -} // setValue - -uint16_t BLEClient::getMTU() { - return m_mtu; -} - -/** - * @brief Return a string representation of this client. - * @return A string representation of this client. - */ -std::string BLEClient::toString() { - std::ostringstream ss; - ss << "peer address: " << m_peerAddress.toString(); - ss << "\nServices:\n"; - for (auto &myPair : m_servicesMap) { - ss << myPair.second->toString() << "\n"; - // myPair.second is the value - } - return ss.str(); -} // toString - - -#endif // CONFIG_BT_ENABLED |