2020-03-30 01:44:20 +02:00
|
|
|
/*
|
|
|
|
* NimBLEDevice.cpp
|
|
|
|
*
|
|
|
|
* Created: on Jan 24 2020
|
|
|
|
* Author H2zero
|
2020-05-14 06:03:56 +02:00
|
|
|
*
|
2020-03-30 01:44:20 +02:00
|
|
|
* Originally:
|
|
|
|
*
|
|
|
|
* BLEDevice.cpp
|
|
|
|
*
|
|
|
|
* Created on: Mar 16, 2017
|
|
|
|
* Author: kolban
|
|
|
|
*/
|
|
|
|
|
2020-05-14 06:03:56 +02:00
|
|
|
#include "nimconfig.h"
|
2021-09-07 05:14:43 +02:00
|
|
|
#if defined(CONFIG_BT_ENABLED)
|
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
# include "NimBLEDevice.h"
|
|
|
|
# include "NimBLEUtils.h"
|
2020-03-30 01:44:20 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
# ifdef ESP_PLATFORM
|
2021-12-29 16:08:25 +01:00
|
|
|
# include "esp_err.h"
|
2024-09-29 23:59:42 +02:00
|
|
|
# ifndef CONFIG_IDF_TARGET_ESP32P4
|
|
|
|
# include "esp_bt.h"
|
|
|
|
# endif
|
2021-12-29 16:08:25 +01:00
|
|
|
# include "nvs_flash.h"
|
|
|
|
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
2024-09-29 23:59:42 +02:00
|
|
|
# if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) || CONFIG_BT_NIMBLE_LEGACY_VHCI_ENABLE)
|
|
|
|
# include "esp_nimble_hci.h"
|
|
|
|
# endif
|
|
|
|
# include "nimble/nimble_port.h"
|
|
|
|
# include "nimble/nimble_port_freertos.h"
|
|
|
|
# include "host/ble_hs.h"
|
|
|
|
# include "host/ble_hs_pvcy.h"
|
|
|
|
# include "host/util/util.h"
|
|
|
|
# include "services/gap/ble_svc_gap.h"
|
|
|
|
# include "services/gatt/ble_svc_gatt.h"
|
2021-12-29 16:08:25 +01:00
|
|
|
# else
|
2024-09-29 23:59:42 +02:00
|
|
|
# include "nimble/esp_port/esp-hci/include/esp_nimble_hci.h"
|
2021-12-29 16:08:25 +01:00
|
|
|
# endif
|
2024-09-29 23:59:42 +02:00
|
|
|
# else
|
2021-12-29 16:08:25 +01:00
|
|
|
# include "nimble/nimble/controller/include/controller/ble_phy.h"
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif
|
2020-03-30 01:44:20 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
# ifndef CONFIG_NIMBLE_CPP_IDF
|
2021-12-29 16:08:25 +01:00
|
|
|
# include "nimble/porting/nimble/include/nimble/nimble_port.h"
|
|
|
|
# include "nimble/porting/npl/freertos/include/nimble/nimble_port_freertos.h"
|
|
|
|
# include "nimble/nimble/host/include/host/ble_hs.h"
|
|
|
|
# include "nimble/nimble/host/include/host/ble_hs_pvcy.h"
|
|
|
|
# include "nimble/nimble/host/util/include/host/util/util.h"
|
|
|
|
# include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h"
|
|
|
|
# include "nimble/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h"
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif
|
2021-12-29 16:08:25 +01:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
# if defined(ESP_PLATFORM) && defined(CONFIG_ENABLE_ARDUINO_DEPENDS)
|
2021-12-29 16:08:25 +01:00
|
|
|
# include "esp32-hal-bt.h"
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif
|
|
|
|
|
|
|
|
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
|
|
|
# include "NimBLEClient.h"
|
|
|
|
# endif
|
2020-03-30 01:44:20 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
|
|
# include "NimBLEServer.h"
|
|
|
|
# endif
|
2020-03-30 01:44:20 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
# include "NimBLELog.h"
|
2024-07-05 03:17:13 +02:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
static const char* LOG_TAG = "NimBLEDevice";
|
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
extern "C" void ble_store_config_init(void);
|
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
/**
|
|
|
|
* Singletons for the NimBLEDevice.
|
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
# if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
|
|
|
NimBLEScan* NimBLEDevice::m_pScan = nullptr;
|
|
|
|
# endif
|
|
|
|
|
|
|
|
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
|
|
NimBLEServer* NimBLEDevice::m_pServer = nullptr;
|
|
|
|
# endif
|
|
|
|
|
|
|
|
# if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
2022-04-10 18:21:45 +02:00
|
|
|
# if CONFIG_BT_NIMBLE_EXT_ADV
|
|
|
|
NimBLEExtAdvertising* NimBLEDevice::m_bleAdvertising = nullptr;
|
|
|
|
# else
|
2020-03-30 01:44:20 +02:00
|
|
|
NimBLEAdvertising* NimBLEDevice::m_bleAdvertising = nullptr;
|
2022-04-10 18:21:45 +02:00
|
|
|
# endif
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif
|
2020-03-30 01:44:20 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
2024-07-04 20:03:03 +02:00
|
|
|
std::array<NimBLEClient*, NIMBLE_MAX_CONNECTIONS> NimBLEDevice::m_pClients{nullptr};
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif
|
|
|
|
|
|
|
|
bool NimBLEDevice::m_initialized{false};
|
|
|
|
uint32_t NimBLEDevice::m_passkey{123456};
|
|
|
|
bool NimBLEDevice::m_synced{false};
|
|
|
|
ble_gap_event_listener NimBLEDevice::m_listener{};
|
|
|
|
std::vector<NimBLEAddress> NimBLEDevice::m_ignoreList{};
|
|
|
|
std::vector<NimBLEAddress> NimBLEDevice::m_whiteList{};
|
|
|
|
uint8_t NimBLEDevice::m_ownAddrType{BLE_OWN_ADDR_PUBLIC};
|
|
|
|
|
|
|
|
# ifdef ESP_PLATFORM
|
2023-05-29 17:08:14 +02:00
|
|
|
# ifdef CONFIG_BTDM_BLE_SCAN_DUPL
|
2024-09-29 23:59:42 +02:00
|
|
|
uint16_t NimBLEDevice::m_scanDuplicateSize{CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE};
|
|
|
|
uint8_t NimBLEDevice::m_scanFilterMode{CONFIG_BTDM_SCAN_DUPL_TYPE};
|
2023-05-29 17:08:14 +02:00
|
|
|
# endif
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif
|
2020-03-30 01:44:20 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
/* SERVER FUNCTIONS */
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
2020-03-30 01:44:20 +02:00
|
|
|
/**
|
2024-09-29 23:59:42 +02:00
|
|
|
* @brief Create an instance of a server.
|
|
|
|
* @return A pointer to the instance of the server.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
NimBLEServer* NimBLEDevice::createServer() {
|
|
|
|
if (NimBLEDevice::m_pServer == nullptr) {
|
2020-03-30 01:44:20 +02:00
|
|
|
NimBLEDevice::m_pServer = new NimBLEServer();
|
2020-05-14 06:03:56 +02:00
|
|
|
ble_gatts_reset();
|
2020-03-30 01:44:20 +02:00
|
|
|
ble_svc_gap_init();
|
|
|
|
ble_svc_gatt_init();
|
|
|
|
}
|
|
|
|
|
|
|
|
return m_pServer;
|
|
|
|
} // createServer
|
2020-05-14 20:59:35 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get the instance of the server.
|
2024-09-29 23:59:42 +02:00
|
|
|
* @return A pointer to the server instance or nullptr if none have been created.
|
2020-05-14 20:59:35 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
NimBLEServer* NimBLEDevice::getServer() {
|
2020-05-14 20:59:35 +02:00
|
|
|
return m_pServer;
|
|
|
|
} // getServer
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
2020-03-30 01:44:20 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
/* ADVERTISING FUNCTIONS */
|
|
|
|
/* -------------------------------------------------------------------------- */
|
2020-03-30 01:44:20 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
# if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
2022-04-10 18:21:45 +02:00
|
|
|
# if CONFIG_BT_NIMBLE_EXT_ADV
|
|
|
|
/**
|
2024-09-29 23:59:42 +02:00
|
|
|
* @brief Get the instance of the extended advertising object.
|
|
|
|
* @return A pointer to the extended advertising object.
|
2022-04-10 18:21:45 +02:00
|
|
|
*/
|
|
|
|
NimBLEExtAdvertising* NimBLEDevice::getAdvertising() {
|
2024-09-29 23:59:42 +02:00
|
|
|
if (m_bleAdvertising == nullptr) {
|
2022-04-10 18:21:45 +02:00
|
|
|
m_bleAdvertising = new NimBLEExtAdvertising();
|
|
|
|
}
|
2024-09-29 23:59:42 +02:00
|
|
|
|
2022-04-10 18:21:45 +02:00
|
|
|
return m_bleAdvertising;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Convenience function to begin advertising.
|
2024-09-29 23:59:42 +02:00
|
|
|
* @param [in] instId The extended advertisement instance ID to start.
|
2022-04-10 18:21:45 +02:00
|
|
|
* @param [in] duration How long to advertise for in milliseconds, 0 = forever (default).
|
2024-09-29 23:59:42 +02:00
|
|
|
* @param [in] maxEvents Maximum number of advertisement events to send, 0 = no limit (default).
|
2022-04-10 18:21:45 +02:00
|
|
|
* @return True if advertising started successfully.
|
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
bool NimBLEDevice::startAdvertising(uint8_t instId, int duration, int maxEvents) {
|
|
|
|
return getAdvertising()->start(instId, duration, maxEvents);
|
2022-04-10 18:21:45 +02:00
|
|
|
} // startAdvertising
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Convenience function to stop advertising a data set.
|
2024-09-29 23:59:42 +02:00
|
|
|
* @param [in] instId The extended advertisement instance ID to stop advertising.
|
2022-04-10 18:21:45 +02:00
|
|
|
* @return True if advertising stopped successfully.
|
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
bool NimBLEDevice::stopAdvertising(uint8_t instId) {
|
|
|
|
return getAdvertising()->stop(instId);
|
2022-04-10 18:21:45 +02:00
|
|
|
} // stopAdvertising
|
|
|
|
# endif
|
|
|
|
|
|
|
|
# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
|
2020-07-09 03:27:26 +02:00
|
|
|
/**
|
|
|
|
* @brief Get the instance of the advertising object.
|
|
|
|
* @return A pointer to the advertising object.
|
|
|
|
*/
|
2020-03-30 01:44:20 +02:00
|
|
|
NimBLEAdvertising* NimBLEDevice::getAdvertising() {
|
2024-09-29 23:59:42 +02:00
|
|
|
if (m_bleAdvertising == nullptr) {
|
2020-05-14 06:03:56 +02:00
|
|
|
m_bleAdvertising = new NimBLEAdvertising();
|
|
|
|
}
|
|
|
|
return m_bleAdvertising;
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
|
|
|
|
2020-07-09 03:27:26 +02:00
|
|
|
/**
|
|
|
|
* @brief Convenience function to begin advertising.
|
2022-08-27 03:32:01 +02:00
|
|
|
* @param [in] duration The duration in milliseconds to advertise for, default = forever.
|
2022-04-10 18:21:45 +02:00
|
|
|
* @return True if advertising started successfully.
|
2020-07-09 03:27:26 +02:00
|
|
|
*/
|
2022-08-27 03:32:01 +02:00
|
|
|
bool NimBLEDevice::startAdvertising(uint32_t duration) {
|
|
|
|
return getAdvertising()->start(duration);
|
2020-03-30 01:44:20 +02:00
|
|
|
} // startAdvertising
|
2022-04-10 18:21:45 +02:00
|
|
|
# endif
|
2020-03-30 01:44:20 +02:00
|
|
|
|
2020-07-09 03:27:26 +02:00
|
|
|
/**
|
2022-04-10 18:21:45 +02:00
|
|
|
* @brief Convenience function to stop all advertising.
|
|
|
|
* @return True if advertising stopped successfully.
|
2020-07-09 03:27:26 +02:00
|
|
|
*/
|
2022-04-10 18:21:45 +02:00
|
|
|
bool NimBLEDevice::stopAdvertising() {
|
|
|
|
return getAdvertising()->stop();
|
2020-03-30 01:44:20 +02:00
|
|
|
} // stopAdvertising
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif // #if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
2020-03-30 01:44:20 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
/* SCAN FUNCTIONS */
|
|
|
|
/* -------------------------------------------------------------------------- */
|
2020-03-30 01:44:20 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @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.
|
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
# if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
2021-12-29 16:08:25 +01:00
|
|
|
NimBLEScan* NimBLEDevice::getScan() {
|
2020-03-30 01:44:20 +02:00
|
|
|
if (m_pScan == nullptr) {
|
|
|
|
m_pScan = new NimBLEScan();
|
|
|
|
}
|
2024-09-29 23:59:42 +02:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
return m_pScan;
|
|
|
|
} // getScan
|
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
# ifdef ESP_PLATFORM
|
|
|
|
# ifdef CONFIG_BTDM_BLE_SCAN_DUPL
|
|
|
|
/**
|
|
|
|
* @brief Set the duplicate filter cache size for filtering scanned devices.
|
|
|
|
* @param [in] size The number of advertisements filtered before the cache is reset.\n
|
|
|
|
* Range is 10-1000, a larger value will reduce how often the same devices are reported.
|
|
|
|
* @details Must only be called before calling NimBLEDevice::init.
|
|
|
|
*/
|
|
|
|
void NimBLEDevice::setScanDuplicateCacheSize(uint16_t size) {
|
|
|
|
if (m_initialized) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Cannot change scan cache size while initialized");
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
if (size > 1000) {
|
|
|
|
size = 1000;
|
|
|
|
} else if (size < 10) {
|
|
|
|
size = 10;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NIMBLE_LOGD(LOG_TAG, "Set duplicate cache size to: %u", size);
|
|
|
|
m_scanDuplicateSize = size;
|
|
|
|
}
|
2020-07-09 03:27:26 +02:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
/**
|
2024-09-29 23:59:42 +02:00
|
|
|
* @brief Set the duplicate filter mode for filtering scanned devices.
|
|
|
|
* @param [in] mode One of three possible options:
|
|
|
|
* * CONFIG_BTDM_SCAN_DUPL_TYPE_DEVICE (0) (default)\n
|
|
|
|
Filter by device address only, advertisements from the same address will be reported only once.
|
|
|
|
* * CONFIG_BTDM_SCAN_DUPL_TYPE_DATA (1)\n
|
|
|
|
Filter by data only, advertisements with the same data will only be reported once,\n
|
|
|
|
even from different addresses.
|
|
|
|
* * CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE (2)\n
|
|
|
|
Filter by address and data, advertisements from the same address will be reported only once,\n
|
|
|
|
except if the data in the advertisement has changed, then it will be reported again.
|
|
|
|
* @details Must only be called before calling NimBLEDevice::init.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
void NimBLEDevice::setScanFilterMode(uint8_t mode) {
|
|
|
|
if (m_initialized) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Cannot change scan duplicate type while initialized");
|
|
|
|
return;
|
|
|
|
} else if (mode > 2) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Invalid scan duplicate type");
|
|
|
|
return;
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
m_scanFilterMode = mode;
|
|
|
|
}
|
|
|
|
# endif // CONFIG_BTDM_BLE_SCAN_DUPL
|
|
|
|
# endif // ESP_PLATFORM
|
|
|
|
# endif // #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
/* CLIENT FUNCTIONS */
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
|
|
|
/**
|
|
|
|
* @brief Creates a new client object, each client can connect to 1 peripheral device.
|
|
|
|
* @return A pointer to the new client object, or nullptr on error.
|
|
|
|
*/
|
|
|
|
NimBLEClient* NimBLEDevice::createClient() {
|
|
|
|
return createClient(NimBLEAddress{});
|
|
|
|
} // createClient
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Creates a new client object, each client can connect to 1 peripheral device.
|
|
|
|
* @param [in] peerAddress A peer address reference that is copied to the new client
|
|
|
|
* object, allows for calling NimBLEClient::connect(bool) without a device or address parameter.
|
|
|
|
* @return A pointer to the new client object, or nullptr on error.
|
|
|
|
*/
|
|
|
|
NimBLEClient* NimBLEDevice::createClient(const NimBLEAddress& peerAddress) {
|
2024-07-04 20:03:03 +02:00
|
|
|
for (auto& clt : m_pClients) {
|
|
|
|
if (clt == nullptr) {
|
2024-09-29 23:59:42 +02:00
|
|
|
clt = new NimBLEClient(peerAddress);
|
|
|
|
return clt;
|
2024-07-04 20:03:03 +02:00
|
|
|
}
|
|
|
|
}
|
2020-03-30 01:44:20 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "Unable to create client; already at max: %d", NIMBLE_MAX_CONNECTIONS);
|
|
|
|
return nullptr;
|
2020-03-30 01:44:20 +02:00
|
|
|
} // createClient
|
|
|
|
|
|
|
|
/**
|
2020-07-09 03:27:26 +02:00
|
|
|
* @brief Delete the client object and remove it from the list.\n
|
|
|
|
* Checks if it is connected or trying to connect and disconnects/stops it first.
|
|
|
|
* @param [in] pClient A pointer to the client object.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2021-12-29 16:08:25 +01:00
|
|
|
bool NimBLEDevice::deleteClient(NimBLEClient* pClient) {
|
2024-09-29 23:59:42 +02:00
|
|
|
if (pClient == nullptr) {
|
2020-03-30 01:44:20 +02:00
|
|
|
return false;
|
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2021-01-12 22:01:44 +01:00
|
|
|
// Set the connection established flag to false to stop notifications
|
|
|
|
// from accessing the attribute vectors while they are being deleted.
|
|
|
|
pClient->m_connEstablished = false;
|
2024-09-29 23:59:42 +02:00
|
|
|
int rc = 0;
|
2020-05-30 17:01:42 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
if (pClient->isConnected()) {
|
2020-05-30 17:01:42 +02:00
|
|
|
rc = pClient->disconnect();
|
|
|
|
if (rc != 0 && rc != BLE_HS_EALREADY && rc != BLE_HS_ENOTCONN) {
|
2020-03-30 01:44:20 +02:00
|
|
|
return false;
|
|
|
|
}
|
2020-05-30 17:01:42 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
while (pClient->isConnected()) {
|
|
|
|
ble_npl_time_delay(1);
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
2021-01-12 22:01:44 +01:00
|
|
|
// Since we set the flag to false the app will not get a callback
|
|
|
|
// in the disconnect event so we call it here for good measure.
|
2022-08-27 03:51:19 +02:00
|
|
|
pClient->m_pClientCallbacks->onDisconnect(pClient, BLE_ERR_CONN_TERM_LOCAL);
|
2024-09-29 23:59:42 +02:00
|
|
|
} else if (pClient->m_pTaskData != nullptr) {
|
2020-05-30 17:01:42 +02:00
|
|
|
rc = ble_gap_conn_cancel();
|
|
|
|
if (rc != 0 && rc != BLE_HS_EALREADY) {
|
2020-03-30 01:44:20 +02:00
|
|
|
return false;
|
|
|
|
}
|
2024-09-29 23:59:42 +02:00
|
|
|
|
|
|
|
while (pClient->m_pTaskData != nullptr) {
|
|
|
|
ble_npl_time_delay(1);
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2024-07-04 20:03:03 +02:00
|
|
|
for (auto& clt : m_pClients) {
|
|
|
|
if (clt == pClient) {
|
|
|
|
delete pClient;
|
|
|
|
clt = nullptr;
|
|
|
|
}
|
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
return true;
|
|
|
|
} // deleteClient
|
|
|
|
|
|
|
|
/**
|
2020-07-09 03:27:26 +02:00
|
|
|
* @brief Get the number of created client objects.
|
|
|
|
* @return Number of client objects created.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-07-04 20:03:03 +02:00
|
|
|
size_t NimBLEDevice::getCreatedClientCount() {
|
2024-09-29 23:59:42 +02:00
|
|
|
size_t count = 0;
|
|
|
|
for (const auto clt : m_pClients) {
|
2024-07-04 20:03:03 +02:00
|
|
|
if (clt != nullptr) {
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
} // getCreatedClientCount
|
2020-03-30 01:44:20 +02:00
|
|
|
|
|
|
|
/**
|
2024-09-29 23:59:42 +02:00
|
|
|
* @brief Get a reference to a client by connection handle.
|
|
|
|
* @param [in] connHandle The client connection handle to search for.
|
|
|
|
* @return A pointer to the client object with the specified connection handle or nullptr.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
NimBLEClient* NimBLEDevice::getClientByHandle(uint16_t connHandle) {
|
|
|
|
for (const auto clt : m_pClients) {
|
|
|
|
if (clt != nullptr && clt->getConnId() == connHandle) {
|
2024-07-04 20:03:03 +02:00
|
|
|
return clt;
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
|
|
|
}
|
2024-07-03 21:11:03 +02:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
return nullptr;
|
2024-09-29 23:59:42 +02:00
|
|
|
} // getClientByHandle
|
2020-03-30 01:44:20 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get a reference to a client by peer address.
|
2024-09-29 23:59:42 +02:00
|
|
|
* @param [in] addr The address of the peer to search for.
|
2024-07-04 20:03:03 +02:00
|
|
|
* @return A pointer to the client object with the peer address or nullptr.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
NimBLEClient* NimBLEDevice::getClientByPeerAddress(const NimBLEAddress& addr) {
|
|
|
|
for (const auto clt : m_pClients) {
|
|
|
|
if (clt != nullptr && clt->getPeerAddress() == addr) {
|
2024-07-04 20:03:03 +02:00
|
|
|
return clt;
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
|
|
|
}
|
2024-07-04 20:03:03 +02:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
return nullptr;
|
|
|
|
} // getClientPeerAddress
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Finds the first disconnected client in the list.
|
2024-07-04 20:03:03 +02:00
|
|
|
* @return A pointer to the first client object that is not connected to a peer or nullptr.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2021-12-29 16:08:25 +01:00
|
|
|
NimBLEClient* NimBLEDevice::getDisconnectedClient() {
|
2024-09-29 23:59:42 +02:00
|
|
|
for (const auto clt : m_pClients) {
|
|
|
|
if (clt != nullptr && !clt->isConnected()) {
|
2024-07-04 20:03:03 +02:00
|
|
|
return clt;
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
|
|
|
}
|
2024-07-04 20:03:03 +02:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
return nullptr;
|
|
|
|
} // getDisconnectedClient
|
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif // #if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
/* TRANSMIT POWER */
|
|
|
|
/* -------------------------------------------------------------------------- */
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
/**
|
|
|
|
* @brief Set the transmission power.
|
2024-09-29 23:59:42 +02:00
|
|
|
* @param [in] dbm The power level to set in dBm.
|
|
|
|
* @return True if the power level was set successfully.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
bool NimBLEDevice::setPower(int8_t dbm) {
|
|
|
|
NIMBLE_LOGD(LOG_TAG, ">> setPower: %d", dbm);
|
|
|
|
# ifdef ESP_PLATFORM
|
|
|
|
# ifndef CONFIG_IDF_TARGET_ESP32P4
|
|
|
|
if (dbm >= 9) {
|
|
|
|
dbm = ESP_PWR_LVL_P9;
|
|
|
|
} else if (dbm >= 6) {
|
|
|
|
dbm = ESP_PWR_LVL_P6;
|
|
|
|
} else if (dbm >= 3) {
|
|
|
|
dbm = ESP_PWR_LVL_P3;
|
|
|
|
} else if (dbm >= 0) {
|
|
|
|
dbm = ESP_PWR_LVL_N0;
|
|
|
|
} else if (dbm >= -3) {
|
|
|
|
dbm = ESP_PWR_LVL_N3;
|
|
|
|
} else if (dbm >= -6) {
|
|
|
|
dbm = ESP_PWR_LVL_N6;
|
|
|
|
} else if (dbm >= -9) {
|
|
|
|
dbm = ESP_PWR_LVL_N9;
|
|
|
|
} else if (dbm >= -12) {
|
|
|
|
dbm = ESP_PWR_LVL_N12;
|
|
|
|
} else {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Unsupported power level");
|
|
|
|
return false;
|
|
|
|
}
|
2021-12-29 16:08:25 +01:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
esp_err_t errRc = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_DEFAULT, (esp_power_level_t)dbm);
|
2020-03-30 01:44:20 +02:00
|
|
|
if (errRc != ESP_OK) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "esp_ble_tx_power_set: rc=%d", errRc);
|
2020-04-14 03:13:51 +02:00
|
|
|
}
|
2021-12-29 16:08:25 +01:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
return errRc == ESP_OK;
|
|
|
|
# else
|
|
|
|
return 0xFF; // CONFIG_IDF_TARGET_ESP32P4
|
|
|
|
# endif
|
2020-03-30 01:44:20 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
# else
|
|
|
|
ble_hci_vs_set_tx_pwr_cp cmd{dbm};
|
|
|
|
ble_hci_vs_set_tx_pwr_rp rsp{0};
|
|
|
|
int rc = ble_hs_hci_send_vs_cmd(BLE_HCI_OCF_VS_SET_TX_PWR, &cmd, sizeof(cmd), &rsp, sizeof(rsp));
|
|
|
|
if (rc) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "failed to set TX power, rc: %04x\n", rc);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
NIMBLE_LOGD(LOG_TAG, "TX power set to %d dBm\n", rsp.tx_power);
|
|
|
|
return true;
|
|
|
|
# endif
|
|
|
|
} // setPower
|
2020-03-30 01:44:20 +02:00
|
|
|
|
2020-07-09 03:27:26 +02:00
|
|
|
/**
|
2021-02-06 19:12:40 +01:00
|
|
|
* @brief Get the transmission power.
|
2024-09-29 23:59:42 +02:00
|
|
|
* @return The power level currently used in dbm.
|
2020-07-09 03:27:26 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
int NimBLEDevice::getPower() {
|
|
|
|
# ifdef ESP_PLATFORM
|
|
|
|
# ifndef CONFIG_IDF_TARGET_ESP32P4
|
|
|
|
switch (esp_ble_tx_power_get(ESP_BLE_PWR_TYPE_DEFAULT)) {
|
2020-05-14 06:03:56 +02:00
|
|
|
case ESP_PWR_LVL_N12:
|
|
|
|
return -12;
|
|
|
|
case ESP_PWR_LVL_N9:
|
|
|
|
return -9;
|
|
|
|
case ESP_PWR_LVL_N6:
|
|
|
|
return -6;
|
|
|
|
case ESP_PWR_LVL_N3:
|
2022-09-02 16:27:23 +02:00
|
|
|
return -3;
|
2020-05-14 06:03:56 +02:00
|
|
|
case ESP_PWR_LVL_N0:
|
|
|
|
return 0;
|
|
|
|
case ESP_PWR_LVL_P3:
|
|
|
|
return 3;
|
|
|
|
case ESP_PWR_LVL_P6:
|
|
|
|
return 6;
|
|
|
|
case ESP_PWR_LVL_P9:
|
|
|
|
return 9;
|
|
|
|
default:
|
2024-09-29 23:59:42 +02:00
|
|
|
return 0xFF;
|
2020-05-14 06:03:56 +02:00
|
|
|
}
|
2024-09-29 23:59:42 +02:00
|
|
|
# else
|
|
|
|
return 0xFF; // CONFIG_IDF_TARGET_ESP32P4 does not support esp_ble_tx_power_get
|
|
|
|
# endif
|
2021-12-29 16:08:25 +01:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
# else
|
2021-12-29 16:08:25 +01:00
|
|
|
return ble_phy_txpwr_get();
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif
|
|
|
|
} // getPower
|
2020-03-30 01:44:20 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
/* MTU FUNCTIONS */
|
|
|
|
/* -------------------------------------------------------------------------- */
|
2020-03-30 01:44:20 +02:00
|
|
|
|
|
|
|
/**
|
2020-07-09 03:27:26 +02:00
|
|
|
* @brief Setup local mtu that will be used to negotiate mtu during request from client peer.
|
|
|
|
* @param [in] mtu Value to set local mtu:
|
|
|
|
* * This should be larger than 23 and lower or equal to BLE_ATT_MTU_MAX = 527.
|
2024-09-29 23:59:42 +02:00
|
|
|
* @return True if the mtu was set successfully.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
bool NimBLEDevice::setMTU(uint16_t mtu) {
|
|
|
|
int rc = ble_att_set_preferred_mtu(mtu);
|
2020-03-30 01:44:20 +02:00
|
|
|
if (rc != 0) {
|
2024-09-29 23:59:42 +02:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "Could not set local mtu value to: %d, rc: %d", mtu, rc);
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
return rc == 0;
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setMTU
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get local MTU value set.
|
2020-07-09 03:27:26 +02:00
|
|
|
* @return The current preferred MTU setting.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2021-12-29 16:08:25 +01:00
|
|
|
uint16_t NimBLEDevice::getMTU() {
|
2020-03-30 01:44:20 +02:00
|
|
|
return ble_att_preferred_mtu();
|
|
|
|
}
|
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
/* BOND MANAGEMENT */
|
|
|
|
/* -------------------------------------------------------------------------- */
|
2020-03-30 01:44:20 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) || defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
2021-04-25 16:06:38 +02:00
|
|
|
/**
|
|
|
|
* @brief Gets the number of bonded peers stored
|
|
|
|
*/
|
|
|
|
int NimBLEDevice::getNumBonds() {
|
|
|
|
ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
|
2024-09-29 23:59:42 +02:00
|
|
|
int num_peers, rc;
|
2021-04-25 16:06:38 +02:00
|
|
|
rc = ble_store_util_bonded_peers(&peer_id_addrs[0], &num_peers, MYNEWT_VAL(BLE_STORE_MAX_BONDS));
|
2024-09-29 23:59:42 +02:00
|
|
|
if (rc != 0) {
|
2021-04-25 16:06:38 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return num_peers;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Deletes all bonding information.
|
2024-09-29 23:59:42 +02:00
|
|
|
* @returns True on success.
|
2021-04-25 16:06:38 +02:00
|
|
|
*/
|
2024-06-05 00:52:55 +02:00
|
|
|
bool NimBLEDevice::deleteAllBonds() {
|
|
|
|
int rc = ble_store_clear();
|
|
|
|
if (rc != 0) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Failed to delete all bonds; rc=%d", rc);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2021-04-25 16:06:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Deletes a peer bond.
|
|
|
|
* @param [in] address The address of the peer with which to delete bond info.
|
2024-09-29 23:59:42 +02:00
|
|
|
* @returns True on success.
|
2021-04-25 16:06:38 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
bool NimBLEDevice::deleteBond(const NimBLEAddress& address) {
|
2024-07-05 03:17:13 +02:00
|
|
|
return ble_gap_unpair(address.getBase()) == 0;
|
2021-04-25 16:06:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Checks if a peer device is bonded.
|
|
|
|
* @param [in] address The address to check for bonding.
|
2024-09-29 23:59:42 +02:00
|
|
|
* @returns True if bonded.
|
2021-04-25 16:06:38 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
bool NimBLEDevice::isBonded(const NimBLEAddress& address) {
|
2021-04-25 16:06:38 +02:00
|
|
|
ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
|
2024-09-29 23:59:42 +02:00
|
|
|
int num_peers, rc;
|
2021-04-25 16:06:38 +02:00
|
|
|
|
|
|
|
rc = ble_store_util_bonded_peers(&peer_id_addrs[0], &num_peers, MYNEWT_VAL(BLE_STORE_MAX_BONDS));
|
|
|
|
if (rc != 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < num_peers; i++) {
|
|
|
|
NimBLEAddress storedAddr(peer_id_addrs[i]);
|
2024-09-29 23:59:42 +02:00
|
|
|
if (storedAddr == address) {
|
2021-04-25 16:06:38 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get the address of a bonded peer device by index.
|
|
|
|
* @param [in] index The index to retrieve the peer address of.
|
|
|
|
* @returns NimBLEAddress of the found bonded peer or nullptr if not found.
|
|
|
|
*/
|
|
|
|
NimBLEAddress NimBLEDevice::getBondedAddress(int index) {
|
|
|
|
ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
|
2024-09-29 23:59:42 +02:00
|
|
|
int num_peers, rc;
|
2021-04-25 16:06:38 +02:00
|
|
|
rc = ble_store_util_bonded_peers(&peer_id_addrs[0], &num_peers, MYNEWT_VAL(BLE_STORE_MAX_BONDS));
|
|
|
|
if (rc != 0) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index > num_peers || index < 0) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NimBLEAddress(peer_id_addrs[index]);
|
|
|
|
}
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
/* WHITELIST */
|
|
|
|
/* -------------------------------------------------------------------------- */
|
2021-02-01 05:15:31 +01:00
|
|
|
|
2021-05-23 21:12:44 +02:00
|
|
|
/**
|
|
|
|
* @brief Checks if a peer device is whitelisted.
|
|
|
|
* @param [in] address The address to check for in the whitelist.
|
2024-09-29 23:59:42 +02:00
|
|
|
* @returns True if the address is in the whitelist.
|
2021-05-23 21:12:44 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
bool NimBLEDevice::onWhiteList(const NimBLEAddress& address) {
|
|
|
|
for (const auto& addr : m_whiteList) {
|
|
|
|
if (addr == address) {
|
2021-05-23 21:12:44 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Add a peer address to the whitelist.
|
|
|
|
* @param [in] address The address to add to the whitelist.
|
2024-09-29 23:59:42 +02:00
|
|
|
* @returns True if successful.
|
2021-05-23 21:12:44 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
bool NimBLEDevice::whiteListAdd(const NimBLEAddress& address) {
|
2024-07-05 03:17:13 +02:00
|
|
|
if (!NimBLEDevice::onWhiteList(address)) {
|
|
|
|
m_whiteList.push_back(address);
|
|
|
|
int rc = ble_gap_wl_set(reinterpret_cast<ble_addr_t*>(&m_whiteList[0]), m_whiteList.size());
|
|
|
|
if (rc != 0) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Failed adding to whitelist rc=%d", rc);
|
|
|
|
m_whiteList.pop_back();
|
|
|
|
return false;
|
|
|
|
}
|
2021-05-23 21:12:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Remove a peer address from the whitelist.
|
|
|
|
* @param [in] address The address to remove from the whitelist.
|
2024-09-29 23:59:42 +02:00
|
|
|
* @returns True if successful.
|
2021-05-23 21:12:44 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
bool NimBLEDevice::whiteListRemove(const NimBLEAddress& address) {
|
|
|
|
for (auto it = m_whiteList.begin(); it < m_whiteList.end(); ++it) {
|
|
|
|
if (*it == address) {
|
|
|
|
m_whiteList.erase(it);
|
|
|
|
int rc = ble_gap_wl_set(reinterpret_cast<ble_addr_t*>(&m_whiteList[0]), m_whiteList.size());
|
|
|
|
if (rc != 0) {
|
|
|
|
m_whiteList.push_back(address);
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Failed removing from whitelist rc=%d", rc);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<NimBLEAddress>(m_whiteList).swap(m_whiteList);
|
2021-05-23 21:12:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Gets the count of addresses in the whitelist.
|
|
|
|
* @returns The number of addresses in the whitelist.
|
|
|
|
*/
|
|
|
|
size_t NimBLEDevice::getWhiteListCount() {
|
|
|
|
return m_whiteList.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Gets the address at the vector index.
|
|
|
|
* @param [in] index The vector index to retrieve the address from.
|
2024-09-29 23:59:42 +02:00
|
|
|
* @returns The NimBLEAddress at the whitelist index or nullptr if not found.
|
2021-05-23 21:12:44 +02:00
|
|
|
*/
|
|
|
|
NimBLEAddress NimBLEDevice::getWhiteListAddress(size_t index) {
|
|
|
|
if (index > m_whiteList.size()) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Invalid index; %u", index);
|
|
|
|
return nullptr;
|
|
|
|
}
|
2024-09-29 23:59:42 +02:00
|
|
|
|
2021-05-23 21:12:44 +02:00
|
|
|
return m_whiteList[index];
|
|
|
|
}
|
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
/* STACK FUNCTIONS */
|
|
|
|
/* -------------------------------------------------------------------------- */
|
2021-05-23 21:12:44 +02:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
/**
|
2024-09-29 23:59:42 +02:00
|
|
|
* @brief Host reset, we pass the message so we don't make calls until re-synced.
|
2020-07-09 03:27:26 +02:00
|
|
|
* @param [in] reason The reason code for the reset.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
void NimBLEDevice::onReset(int reason) {
|
|
|
|
if (!m_synced) {
|
2020-03-30 01:44:20 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
m_synced = false;
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "Resetting state; reason=%d, %s", reason, NimBLEUtils::returnCodeToString(reason));
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
# if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
|
|
|
if (m_initialized) {
|
|
|
|
if (m_pScan != nullptr) {
|
2021-01-13 04:42:19 +01:00
|
|
|
m_pScan->onHostReset();
|
|
|
|
}
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif
|
2020-03-30 01:44:20 +02:00
|
|
|
} // onReset
|
|
|
|
|
|
|
|
/**
|
2024-09-29 23:59:42 +02:00
|
|
|
* @brief Host synced with controller, all clear to make calls to the stack.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
void NimBLEDevice::onSync(void) {
|
2020-03-30 01:44:20 +02:00
|
|
|
NIMBLE_LOGI(LOG_TAG, "NimBle host synced.");
|
|
|
|
// This check is needed due to potentially being called multiple times in succession
|
|
|
|
// If this happens, the call to scan start may get stuck or cause an advertising fault.
|
2024-09-29 23:59:42 +02:00
|
|
|
if (m_synced) {
|
2020-03-30 01:44:20 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
// Get the public and random address for the device.
|
2020-03-30 01:44:20 +02:00
|
|
|
int rc = ble_hs_util_ensure_addr(0);
|
2024-09-29 23:59:42 +02:00
|
|
|
if (rc == 0) {
|
|
|
|
rc = ble_hs_util_ensure_addr(1);
|
|
|
|
}
|
|
|
|
|
2024-07-03 21:11:03 +02:00
|
|
|
if (rc != 0) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "error ensuring address; rc=%d", rc);
|
|
|
|
return;
|
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
// start with using the public address if available, if not then use random.
|
|
|
|
rc = ble_hs_id_copy_addr(BLE_OWN_ADDR_PUBLIC, NULL, NULL);
|
2021-12-29 16:08:25 +01:00
|
|
|
if (rc != 0) {
|
2024-09-29 23:59:42 +02:00
|
|
|
m_ownAddrType = BLE_OWN_ADDR_RANDOM;
|
2021-12-29 16:08:25 +01:00
|
|
|
}
|
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
// Yield for housekeeping tasks before returning to operations.
|
2021-01-12 21:59:49 +01:00
|
|
|
// Occasionally triggers exception without.
|
2024-09-29 23:59:42 +02:00
|
|
|
ble_npl_time_delay(1);
|
2021-01-12 21:59:49 +01:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
m_synced = true;
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
if (m_initialized) {
|
|
|
|
# if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
|
|
|
if (m_pScan != nullptr) {
|
2021-01-13 04:42:19 +01:00
|
|
|
m_pScan->onHostSync();
|
2020-05-03 21:50:49 +02:00
|
|
|
}
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif
|
2020-05-03 21:50:49 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
# if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
|
|
|
if (m_bleAdvertising != nullptr) {
|
2021-01-13 04:42:19 +01:00
|
|
|
m_bleAdvertising->onHostSync();
|
2020-05-03 21:50:49 +02:00
|
|
|
}
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
|
|
|
} // onSync
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief The main host task.
|
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
void NimBLEDevice::host_task(void* param) {
|
2020-03-30 01:44:20 +02:00
|
|
|
NIMBLE_LOGI(LOG_TAG, "BLE Host Task Started");
|
2024-09-29 23:59:42 +02:00
|
|
|
nimble_port_run(); // This function will return only when nimble_port_stop() is executed
|
2020-03-30 01:44:20 +02:00
|
|
|
nimble_port_freertos_deinit();
|
|
|
|
} // host_task
|
|
|
|
|
|
|
|
/**
|
2024-09-29 23:59:42 +02:00
|
|
|
* @brief Initialize the BLE environment.
|
2020-07-09 03:27:26 +02:00
|
|
|
* @param [in] deviceName The device name of the device.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
bool NimBLEDevice::init(const std::string& deviceName) {
|
|
|
|
if (!m_initialized) {
|
|
|
|
# ifdef ESP_PLATFORM
|
|
|
|
|
|
|
|
# ifdef CONFIG_ENABLE_ARDUINO_DEPENDS
|
2022-07-31 19:00:12 +02:00
|
|
|
// make sure the linker includes esp32-hal-bt.c so Arduino init doesn't release BLE memory.
|
2021-08-03 20:43:34 +02:00
|
|
|
btStarted();
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif
|
2020-05-03 21:50:49 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
esp_err_t err = nvs_flash_init();
|
|
|
|
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
|
|
|
err = nvs_flash_erase();
|
|
|
|
if (err == ESP_OK) {
|
|
|
|
err = nvs_flash_init();
|
|
|
|
}
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
if (err != ESP_OK) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "nvs_flash_init() failed; err=%d", err);
|
|
|
|
return false;
|
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
# if CONFIG_IDF_TARGET_ESP32
|
2021-02-01 05:15:31 +01:00
|
|
|
esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif
|
2021-02-01 05:15:31 +01:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
# if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) | !defined(CONFIG_NIMBLE_CPP_IDF)
|
2021-02-01 05:15:31 +01:00
|
|
|
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
2024-09-29 23:59:42 +02:00
|
|
|
# if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3)
|
2021-07-20 05:46:30 +02:00
|
|
|
bt_cfg.bluetooth_mode = ESP_BT_MODE_BLE;
|
2024-09-29 23:59:42 +02:00
|
|
|
# else
|
|
|
|
bt_cfg.mode = ESP_BT_MODE_BLE;
|
2021-02-01 05:15:31 +01:00
|
|
|
bt_cfg.ble_max_conn = CONFIG_BT_NIMBLE_MAX_CONNECTIONS;
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif
|
2023-05-29 17:08:14 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
# ifdef CONFIG_BTDM_BLE_SCAN_DUPL
|
|
|
|
bt_cfg.normal_adv_size = m_scanDuplicateSize;
|
2021-02-01 05:15:31 +01:00
|
|
|
bt_cfg.scan_duplicate_type = m_scanFilterMode;
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif
|
|
|
|
err = esp_bt_controller_init(&bt_cfg);
|
|
|
|
if (err != ESP_OK) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "esp_bt_controller_init() failed; err=%d", err);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
|
|
|
if (err != ESP_OK) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "esp_bt_controller_enable() failed; err=%d", err);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = esp_nimble_hci_init();
|
|
|
|
if (err != ESP_OK) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "esp_nimble_hci_init() failed; err=%d", err);
|
|
|
|
return false;
|
|
|
|
}
|
2023-05-29 17:08:14 +02:00
|
|
|
# endif
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif
|
2020-03-30 01:44:20 +02:00
|
|
|
nimble_port_init();
|
2020-05-14 06:03:56 +02:00
|
|
|
|
|
|
|
// Setup callbacks for host events
|
2020-03-30 01:44:20 +02:00
|
|
|
ble_hs_cfg.reset_cb = NimBLEDevice::onReset;
|
2024-09-29 23:59:42 +02:00
|
|
|
ble_hs_cfg.sync_cb = NimBLEDevice::onSync;
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
// Set initial security capabilities
|
2024-09-29 23:59:42 +02:00
|
|
|
ble_hs_cfg.sm_io_cap = BLE_HS_IO_NO_INPUT_OUTPUT;
|
|
|
|
ble_hs_cfg.sm_bonding = 0;
|
|
|
|
ble_hs_cfg.sm_mitm = 0;
|
|
|
|
ble_hs_cfg.sm_sc = 1;
|
|
|
|
ble_hs_cfg.sm_our_key_dist = BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID;
|
2024-06-02 17:00:07 +02:00
|
|
|
ble_hs_cfg.sm_their_key_dist = BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID;
|
2024-09-29 23:59:42 +02:00
|
|
|
ble_hs_cfg.store_status_cb = ble_store_util_status_rr; /*TODO: Implement handler for this*/
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
setDeviceName(deviceName);
|
2020-03-30 01:44:20 +02:00
|
|
|
ble_store_config_init();
|
|
|
|
nimble_port_freertos_init(NimBLEDevice::host_task);
|
|
|
|
}
|
2021-12-29 16:08:25 +01:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
// Wait for host and controller to sync before returning and accepting new tasks
|
2024-09-29 23:59:42 +02:00
|
|
|
while (!m_synced) {
|
|
|
|
ble_npl_time_delay(1);
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
2020-05-03 21:50:49 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
m_initialized = true; // Set the initialization flag to ensure we are only initialized once.
|
|
|
|
return true;
|
2020-03-30 01:44:20 +02:00
|
|
|
} // init
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Shutdown the NimBLE stack/controller.
|
2024-09-29 23:59:42 +02:00
|
|
|
* @param [in] clearAll If true, deletes all server/advertising/scan/client objects after de-initializing.
|
|
|
|
* @note If clearAll is true when called all objects created will be deleted and any references to the created objects become invalid.
|
|
|
|
* If clearAll is false, the objects will remain and can be used again after re-initializing the stack.
|
|
|
|
* If the stack was not already initialized, the objects created can be deleted when clearAll is true with no effect on the stack.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
bool NimBLEDevice::deinit(bool clearAll) {
|
|
|
|
int rc = 0;
|
|
|
|
if (m_initialized) {
|
|
|
|
rc = nimble_port_stop();
|
|
|
|
if (rc == 0) {
|
|
|
|
nimble_port_deinit();
|
|
|
|
# ifdef CONFIG_NIMBLE_CPP_IDF
|
|
|
|
# if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
|
|
|
rc = esp_nimble_hci_and_controller_deinit();
|
|
|
|
if (rc != ESP_OK) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "esp_nimble_hci_and_controller_deinit() failed with error: %d", rc);
|
|
|
|
}
|
|
|
|
# endif
|
|
|
|
# endif
|
|
|
|
m_initialized = false;
|
|
|
|
m_synced = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (clearAll) {
|
|
|
|
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
|
|
if (NimBLEDevice::m_pServer != nullptr) {
|
2024-09-06 15:52:04 +02:00
|
|
|
delete NimBLEDevice::m_pServer;
|
|
|
|
NimBLEDevice::m_pServer = nullptr;
|
|
|
|
}
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif
|
2024-09-06 15:52:04 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
# if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
|
|
|
if (NimBLEDevice::m_bleAdvertising != nullptr) {
|
2024-09-06 15:52:04 +02:00
|
|
|
delete NimBLEDevice::m_bleAdvertising;
|
|
|
|
NimBLEDevice::m_bleAdvertising = nullptr;
|
|
|
|
}
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif
|
2024-09-06 15:52:04 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
# if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
|
|
|
if (NimBLEDevice::m_pScan != nullptr) {
|
2024-09-06 15:52:04 +02:00
|
|
|
delete NimBLEDevice::m_pScan;
|
2024-09-29 23:59:42 +02:00
|
|
|
NimBLEDevice::m_pScan = nullptr;
|
2024-09-06 15:52:04 +02:00
|
|
|
}
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif
|
2024-09-06 15:52:04 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
|
|
|
for (auto clt : m_pClients) {
|
2024-09-06 15:52:04 +02:00
|
|
|
deleteClient(clt);
|
|
|
|
}
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif
|
2024-09-06 15:52:04 +02:00
|
|
|
m_ignoreList.clear();
|
|
|
|
}
|
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
return rc == 0;
|
2020-03-30 01:44:20 +02:00
|
|
|
} // deinit
|
|
|
|
|
2022-07-22 01:33:21 +02:00
|
|
|
/**
|
2024-09-29 23:59:42 +02:00
|
|
|
* @brief Check if the initialization is complete.
|
|
|
|
* @return true if initialized.
|
2022-07-22 01:33:21 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
bool NimBLEDevice::isInitialized() {
|
|
|
|
return m_initialized;
|
|
|
|
} // getInitialized
|
2022-07-22 01:33:21 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
/* ADDRESS MANAGEMENT */
|
|
|
|
/* -------------------------------------------------------------------------- */
|
2020-03-30 01:44:20 +02:00
|
|
|
|
|
|
|
/**
|
2024-09-29 23:59:42 +02:00
|
|
|
* @brief Get our device address.
|
|
|
|
* @return A NimBLEAddress object with the currently used address, or a NULL address if not set.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
NimBLEAddress NimBLEDevice::getAddress() {
|
|
|
|
ble_addr_t addr{};
|
|
|
|
uint8_t type = m_ownAddrType & 1; // input must be random or public, odd values are random
|
|
|
|
int rc = ble_hs_id_copy_addr(type, addr.val, NULL);
|
|
|
|
if (rc != 0) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "No address, rc: %d", rc);
|
|
|
|
} else {
|
|
|
|
addr.type = type;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NimBLEAddress{addr};
|
|
|
|
} // getAddress
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Sets the address type to use.
|
|
|
|
* @param [in] type Bluetooth Device address type.
|
|
|
|
* The available types are defined as:
|
|
|
|
* * 0x00: BLE_OWN_ADDR_PUBLIC - Public address; Uses the hardware static address.
|
|
|
|
* * 0x01: BLE_OWN_ADDR_RANDOM - Random static address; Uses the hardware or generated random static address.
|
|
|
|
* * 0x02: BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT - Resolvable private address, defaults to public if no RPA available.
|
|
|
|
* * 0x03: BLE_OWN_ADDR_RPA_RANDOM_DEFAULT - Resolvable private address, defaults to random static if no RPA available.
|
|
|
|
*/
|
|
|
|
bool NimBLEDevice::setOwnAddrType(uint8_t type) {
|
|
|
|
int rc = ble_hs_id_copy_addr(type & 1, NULL, NULL); // Odd values are random
|
|
|
|
if (rc != 0) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Unable to set address type %d, rc=%d", type, rc);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_ownAddrType = type;
|
2020-03-30 01:44:20 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
if (type == BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT || type == BLE_OWN_ADDR_RPA_RANDOM_DEFAULT) {
|
|
|
|
# ifdef CONFIG_IDF_TARGET_ESP32
|
|
|
|
// esp32 controller does not support RPA so we must use the random static for calls to the stack
|
|
|
|
// the host will take care of the random private address generation/setting.
|
|
|
|
m_ownAddrType = BLE_OWN_ADDR_RANDOM;
|
|
|
|
rc = ble_hs_pvcy_rpa_config(NIMBLE_HOST_ENABLE_RPA);
|
|
|
|
# endif
|
|
|
|
} else {
|
|
|
|
# ifdef CONFIG_IDF_TARGET_ESP32
|
|
|
|
rc = ble_hs_pvcy_rpa_config(NIMBLE_HOST_DISABLE_PRIVACY);
|
|
|
|
# endif
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc == 0;
|
|
|
|
} // setOwnAddrType
|
|
|
|
|
2024-11-03 00:56:23 +01:00
|
|
|
/**
|
|
|
|
* @brief Set the device address to use.
|
|
|
|
* @param [in] addr The address to set.
|
|
|
|
* @return True if the address was set successfully.
|
|
|
|
* @details To use the address generated the address type must be set to random with `setOwnAddrType`.
|
|
|
|
*/
|
|
|
|
bool NimBLEDevice::setOwnAddr(const NimBLEAddress& addr) {
|
|
|
|
return setOwnAddr(addr.getBase()->val);
|
|
|
|
} // setOwnAddr
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the device address to use.
|
|
|
|
* @param [in] addr The address to set.
|
|
|
|
* @return True if the address was set successfully.
|
|
|
|
* @details To use the address generated the address type must be set to random with `setOwnAddrType`.
|
|
|
|
*/
|
|
|
|
bool NimBLEDevice::setOwnAddr(const uint8_t* addr) {
|
|
|
|
int rc = ble_hs_id_set_rnd(addr);
|
|
|
|
if (rc != 0) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Failed to set address, rc=%d", rc);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
} // setOwnAddr
|
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
/* SECURITY */
|
|
|
|
/* -------------------------------------------------------------------------- */
|
2020-03-30 01:44:20 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the authorization mode for this device.
|
2020-07-09 03:27:26 +02:00
|
|
|
* @param bonding If true we allow bonding, false no bonding will be performed.
|
|
|
|
* @param mitm If true we are capable of man in the middle protection, false if not.
|
|
|
|
* @param sc If true we will perform secure connection pairing, false we will use legacy pairing.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2021-12-29 16:08:25 +01:00
|
|
|
void NimBLEDevice::setSecurityAuth(bool bonding, bool mitm, bool sc) {
|
2024-09-29 23:59:42 +02:00
|
|
|
NIMBLE_LOGD(LOG_TAG, "Setting bonding: %d, mitm: %d, sc: %d", bonding, mitm, sc);
|
2020-03-30 01:44:20 +02:00
|
|
|
ble_hs_cfg.sm_bonding = bonding;
|
2024-09-29 23:59:42 +02:00
|
|
|
ble_hs_cfg.sm_mitm = mitm;
|
|
|
|
ble_hs_cfg.sm_sc = sc;
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setSecurityAuth
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the authorization mode for this device.
|
2020-07-09 03:27:26 +02:00
|
|
|
* @param auth_req A bitmap indicating what modes are supported.\n
|
|
|
|
* The available bits are defined as:
|
|
|
|
* * 0x01 BLE_SM_PAIR_AUTHREQ_BOND
|
|
|
|
* * 0x04 BLE_SM_PAIR_AUTHREQ_MITM
|
|
|
|
* * 0x08 BLE_SM_PAIR_AUTHREQ_SC
|
|
|
|
* * 0x10 BLE_SM_PAIR_AUTHREQ_KEYPRESS - not yet supported.
|
2020-05-14 06:03:56 +02:00
|
|
|
*/
|
2021-12-29 16:08:25 +01:00
|
|
|
void NimBLEDevice::setSecurityAuth(uint8_t auth_req) {
|
2024-09-29 23:59:42 +02:00
|
|
|
NimBLEDevice::setSecurityAuth(auth_req & BLE_SM_PAIR_AUTHREQ_BOND,
|
|
|
|
auth_req & BLE_SM_PAIR_AUTHREQ_MITM,
|
|
|
|
auth_req & BLE_SM_PAIR_AUTHREQ_SC);
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setSecurityAuth
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the Input/Output capabilities of this device.
|
2020-07-09 03:27:26 +02:00
|
|
|
* @param iocap One of the following values:
|
|
|
|
* * 0x00 BLE_HS_IO_DISPLAY_ONLY DisplayOnly IO capability
|
|
|
|
* * 0x01 BLE_HS_IO_DISPLAY_YESNO DisplayYesNo IO capability
|
|
|
|
* * 0x02 BLE_HS_IO_KEYBOARD_ONLY KeyboardOnly IO capability
|
|
|
|
* * 0x03 BLE_HS_IO_NO_INPUT_OUTPUT NoInputNoOutput IO capability
|
|
|
|
* * 0x04 BLE_HS_IO_KEYBOARD_DISPLAY KeyboardDisplay Only IO capability
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2021-12-29 16:08:25 +01:00
|
|
|
void NimBLEDevice::setSecurityIOCap(uint8_t iocap) {
|
2020-03-30 01:44:20 +02:00
|
|
|
ble_hs_cfg.sm_io_cap = iocap;
|
|
|
|
} // setSecurityIOCap
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief If we are the initiator of the security procedure this sets the keys we will distribute.
|
2024-09-29 23:59:42 +02:00
|
|
|
* @param initKey A bitmap indicating which keys to distribute during pairing.\n
|
2020-07-09 03:27:26 +02:00
|
|
|
* The available bits are defined as:
|
|
|
|
* * 0x01: BLE_SM_PAIR_KEY_DIST_ENC - Distribute the encryption key.
|
|
|
|
* * 0x02: BLE_SM_PAIR_KEY_DIST_ID - Distribute the ID key (IRK).
|
|
|
|
* * 0x04: BLE_SM_PAIR_KEY_DIST_SIGN
|
|
|
|
* * 0x08: BLE_SM_PAIR_KEY_DIST_LINK
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
void NimBLEDevice::setSecurityInitKey(uint8_t initKey) {
|
|
|
|
ble_hs_cfg.sm_our_key_dist = initKey;
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setsSecurityInitKey
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the keys we are willing to accept during pairing.
|
2024-09-29 23:59:42 +02:00
|
|
|
* @param respKey A bitmap indicating which keys to accept during pairing.
|
2020-07-09 03:27:26 +02:00
|
|
|
* The available bits are defined as:
|
|
|
|
* * 0x01: BLE_SM_PAIR_KEY_DIST_ENC - Accept the encryption key.
|
|
|
|
* * 0x02: BLE_SM_PAIR_KEY_DIST_ID - Accept the ID key (IRK).
|
|
|
|
* * 0x04: BLE_SM_PAIR_KEY_DIST_SIGN
|
|
|
|
* * 0x08: BLE_SM_PAIR_KEY_DIST_LINK
|
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
void NimBLEDevice::setSecurityRespKey(uint8_t respKey) {
|
|
|
|
ble_hs_cfg.sm_their_key_dist = respKey;
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setsSecurityRespKey
|
|
|
|
|
|
|
|
/**
|
2020-07-09 03:27:26 +02:00
|
|
|
* @brief Set the passkey the server will ask for when pairing.
|
2024-09-29 23:59:42 +02:00
|
|
|
* @param [in] passkey The passkey to use.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
void NimBLEDevice::setSecurityPasskey(uint32_t passkey) {
|
|
|
|
m_passkey = passkey;
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setSecurityPasskey
|
|
|
|
|
|
|
|
/**
|
2020-07-09 03:27:26 +02:00
|
|
|
* @brief Get the current passkey used for pairing.
|
|
|
|
* @return The current passkey.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2021-12-29 16:08:25 +01:00
|
|
|
uint32_t NimBLEDevice::getSecurityPasskey() {
|
2020-03-30 01:44:20 +02:00
|
|
|
return m_passkey;
|
|
|
|
} // getSecurityPasskey
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Start the connection securing and authorization for this connection.
|
2024-09-29 23:59:42 +02:00
|
|
|
* @param connHandle The connection handle of the peer device.
|
2020-07-09 03:27:26 +02:00
|
|
|
* @returns NimBLE stack return code, 0 = success.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
bool NimBLEDevice::startSecurity(uint16_t connHandle) {
|
|
|
|
int rc = ble_gap_security_initiate(connHandle);
|
|
|
|
if (rc != 0) {
|
2020-03-30 01:44:20 +02:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "ble_gap_security_initiate: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
return rc == 0;
|
2020-03-30 01:44:20 +02:00
|
|
|
} // startSecurity
|
|
|
|
|
2024-06-07 03:36:14 +02:00
|
|
|
/**
|
2024-09-29 23:59:42 +02:00
|
|
|
* @brief Inject the provided passkey into the Security Manager.
|
|
|
|
* @param [in] peerInfo Connection information for the peer.
|
|
|
|
* @param [in] passkey The 6-digit passkey to inject.
|
2024-06-07 03:36:14 +02:00
|
|
|
* @return true if the passkey was injected successfully.
|
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
bool NimBLEDevice::injectPassKey(const NimBLEConnInfo& peerInfo, uint32_t passkey) {
|
|
|
|
ble_sm_io pkey{.action = BLE_SM_IOACT_INPUT, .passkey = passkey};
|
|
|
|
int rc = ble_sm_inject_io(peerInfo.getConnHandle(), &pkey);
|
2024-06-07 03:36:14 +02:00
|
|
|
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_INPUT; ble_sm_inject_io result: %d", rc);
|
|
|
|
return rc == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2024-09-29 23:59:42 +02:00
|
|
|
* @brief Inject the provided numeric comparison response into the Security Manager.
|
|
|
|
* @param [in] peerInfo Connection information for the peer.
|
|
|
|
* @param [in] accept Whether the user confirmed or declined the comparison.
|
2024-06-07 03:36:14 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
bool NimBLEDevice::injectConfirmPasskey(const NimBLEConnInfo& peerInfo, bool accept) {
|
|
|
|
ble_sm_io pkey{.action = BLE_SM_IOACT_NUMCMP, .numcmp_accept = accept};
|
|
|
|
int rc = ble_sm_inject_io(peerInfo.getConnHandle(), &pkey);
|
2024-06-07 03:36:14 +02:00
|
|
|
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_NUMCMP; ble_sm_inject_io result: %d", rc);
|
|
|
|
return rc == 0;
|
|
|
|
}
|
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
/* IGNORE LIST */
|
|
|
|
/* -------------------------------------------------------------------------- */
|
2024-06-07 03:36:14 +02:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
/**
|
|
|
|
* @brief Check if the device address is on our ignore list.
|
2020-07-09 03:27:26 +02:00
|
|
|
* @param [in] address The address to look for.
|
2020-03-30 01:44:20 +02:00
|
|
|
* @return True if ignoring.
|
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
bool NimBLEDevice::isIgnored(const NimBLEAddress& address) {
|
|
|
|
for (const auto& addr : m_ignoreList) {
|
|
|
|
if (addr == address) {
|
2020-03-30 01:44:20 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Add a device to the ignore list.
|
2020-07-09 03:27:26 +02:00
|
|
|
* @param [in] address The address of the device we want to ignore.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
void NimBLEDevice::addIgnored(const NimBLEAddress& address) {
|
|
|
|
if (!isIgnored(address)) {
|
|
|
|
m_ignoreList.push_back(address);
|
|
|
|
}
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Remove a device from the ignore list.
|
2020-07-09 03:27:26 +02:00
|
|
|
* @param [in] address The address of the device we want to remove from the list.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
void NimBLEDevice::removeIgnored(const NimBLEAddress& address) {
|
|
|
|
for (auto it = m_ignoreList.begin(); it < m_ignoreList.end(); ++it) {
|
|
|
|
if (*it == address) {
|
2020-03-30 01:44:20 +02:00
|
|
|
m_ignoreList.erase(it);
|
2024-09-29 23:59:42 +02:00
|
|
|
std::vector<NimBLEAddress>(m_ignoreList).swap(m_ignoreList);
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
/* UTILITIES */
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the BLEDevice name.
|
|
|
|
* @param [in] deviceName The name to set.
|
|
|
|
*/
|
|
|
|
bool NimBLEDevice::setDeviceName(const std::string& deviceName) {
|
|
|
|
int rc = ble_svc_gap_device_name_set(deviceName.c_str());
|
|
|
|
if (rc != 0) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Device name not set - too long");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
} // setDeviceName
|
2020-03-30 01:44:20 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set a custom callback for gap events.
|
2020-07-09 03:27:26 +02:00
|
|
|
* @param [in] handler The function to call when gap events occur.
|
2024-09-29 23:59:42 +02:00
|
|
|
* @returns
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
bool NimBLEDevice::setCustomGapHandler(gap_event_handler handler) {
|
|
|
|
int rc = ble_gap_event_listener_register(&m_listener, handler, NULL);
|
|
|
|
if (rc == BLE_HS_EALREADY) {
|
2020-03-30 01:44:20 +02:00
|
|
|
NIMBLE_LOGI(LOG_TAG, "Already listening to GAP events.");
|
2024-09-29 23:59:42 +02:00
|
|
|
return true;
|
2024-07-03 21:11:03 +02:00
|
|
|
} else if (rc != 0) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "ble_gap_event_listener_register: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
2024-07-03 21:11:03 +02:00
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
return rc == 0;
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setCustomGapHandler
|
|
|
|
|
2024-09-29 23:59:42 +02:00
|
|
|
/**
|
|
|
|
* @brief Return a string representation of the address of this device.
|
|
|
|
* @return A string representation of this device address.
|
|
|
|
*/
|
|
|
|
std::string NimBLEDevice::toString() {
|
|
|
|
return getAddress().toString();
|
|
|
|
} // toString
|
|
|
|
|
|
|
|
# if CONFIG_NIMBLE_CPP_DEBUG_ASSERT_ENABLED || __DOXYGEN__
|
2024-07-04 18:49:09 +02:00
|
|
|
/**
|
|
|
|
* @brief Debug assert - weak function.
|
|
|
|
* @param [in] file The file where the assert occurred.
|
|
|
|
* @param [in] line The line number where the assert occurred.
|
|
|
|
*/
|
2024-09-29 23:59:42 +02:00
|
|
|
void nimble_cpp_assert(const char* file, unsigned line) {
|
2024-07-04 18:49:09 +02:00
|
|
|
NIMBLE_LOGC("", "Assertion failed at %s:%u\n", file, line);
|
|
|
|
abort();
|
|
|
|
}
|
2024-09-29 23:59:42 +02:00
|
|
|
# endif // CONFIG_NIMBLE_CPP_DEBUG_ASSERT_ENABLED
|
2024-07-04 18:49:09 +02:00
|
|
|
|
2024-09-06 15:52:04 +02:00
|
|
|
#endif // CONFIG_BT_ENABLED
|