[BREAKING] Refactor NimBLEAdvertised device.

* Construct the device with the parameters from the advertisement in the initialization list.
* Removed no longer needed methods; setAddress, setAdvType, setRSSI, setSetId, setPrimaryPhy, setSecondaryPhy, setPeriodicInterval.
* Removed `hasRSSI()` method, the RSSI is always reported so this is redundant.
* Replace setPayload with new method; `update` which will update the device info when new advertisement data is received.
* getPayload now returns `const std::vector<uint8_t>` instead of a pointer to internal memory.
* Added `begin` and `end` read-only iterators for convienience and use in range loops.
* Timestamp removed, if needed then the app should track the time in the callback.
* Consolidate some functions to use getPayloadByType.
* Add optional index parameter to getPayloadByType.
* Change payload indexing to use 0 as the first item.
* Code cleanup and apply const correctness.
This commit is contained in:
h2zero 2024-07-17 19:52:01 -06:00 committed by h2zero
parent 6279817143
commit c2ab790e1d
3 changed files with 353 additions and 497 deletions

File diff suppressed because it is too large Load diff

View file

@ -12,25 +12,25 @@
* Author: kolban * Author: kolban
*/ */
#ifndef COMPONENTS_NIMBLEADVERTISEDDEVICE_H_ #ifndef NIMBLE_CPP_ADVERTISED_DEVICE_H_
#define COMPONENTS_NIMBLEADVERTISEDDEVICE_H_ #define NIMBLE_CPP_ADVERTISED_DEVICE_H_
#include "nimconfig.h" #include "nimconfig.h"
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) #if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
#include "NimBLEAddress.h" # include "NimBLEAddress.h"
#include "NimBLEScan.h" # include "NimBLEScan.h"
#include "NimBLEUUID.h" # include "NimBLEUUID.h"
#if defined(CONFIG_NIMBLE_CPP_IDF) # if defined(CONFIG_NIMBLE_CPP_IDF)
#include "host/ble_hs_adv.h" # include "host/ble_hs_adv.h"
#else # include "host/ble_gap.h"
#include "nimble/nimble/host/include/host/ble_hs_adv.h" # else
#endif # include "nimble/nimble/host/include/host/ble_hs_adv.h"
# include "nimble/nimble/host/include/host/ble_gap.h"
#include <map> # endif
#include <vector>
#include <time.h>
# include <vector>
class NimBLEScan; class NimBLEScan;
/** /**
@ -40,20 +40,59 @@ class NimBLEScan;
* class provides a model of a detected device. * class provides a model of a detected device.
*/ */
class NimBLEAdvertisedDevice { class NimBLEAdvertisedDevice {
public: public:
NimBLEAdvertisedDevice(); NimBLEAdvertisedDevice() = default;
NimBLEAddress getAddress(); uint8_t getAdvType() const;
uint8_t getAdvType(); uint8_t getAdvFlags() const;
uint8_t getAdvFlags(); uint16_t getAppearance() const;
uint16_t getAppearance(); uint16_t getAdvInterval() const;
uint16_t getAdvInterval(); uint16_t getMinInterval() const;
uint16_t getMinInterval(); uint16_t getMaxInterval() const;
uint16_t getMaxInterval(); uint8_t getManufacturerDataCount() const;
uint8_t getManufacturerDataCount(); const NimBLEAddress& getAddress() const;
std::string getManufacturerData(uint8_t index = 0); std::string getManufacturerData(uint8_t index = 0) const;
std::string getURI(); std::string getURI() const;
std::string getPayloadByType(uint16_t type); std::string getPayloadByType(uint16_t type, uint8_t index = 0) const;
std::string getName() const;
int8_t getRSSI() const;
NimBLEScan* getScan() const;
uint8_t getServiceDataCount() const;
std::string getServiceData(uint8_t index = 0) const;
std::string getServiceData(const NimBLEUUID& uuid) const;
NimBLEUUID getServiceDataUUID(uint8_t index = 0) const;
NimBLEUUID getServiceUUID(uint8_t index = 0) const;
uint8_t getServiceUUIDCount() const;
NimBLEAddress getTargetAddress(uint8_t index = 0) const;
uint8_t getTargetAddressCount() const;
int8_t getTXPower() const;
uint8_t getAdvLength() const;
uint8_t getAddressType() const;
bool isAdvertisingService(const NimBLEUUID& uuid) const;
bool haveAppearance() const;
bool haveManufacturerData() const;
bool haveName() const;
bool haveServiceData() const;
bool haveServiceUUID() const;
bool haveTXPower() const;
bool haveConnParams() const;
bool haveAdvInterval() const;
bool haveTargetAddress() const;
bool haveURI() const;
bool haveType(uint16_t type) const;
std::string toString() const;
bool isConnectable() const;
bool isLegacyAdvertisement() const;
# if CONFIG_BT_NIMBLE_EXT_ADV
uint8_t getSetId() const;
uint8_t getPrimaryPhy() const;
uint8_t getSecondaryPhy() const;
uint16_t getPeriodicInterval() const;
# endif
const std::vector<uint8_t>& getPayload() const;
const std::vector<uint8_t>::const_iterator begin() const;
const std::vector<uint8_t>::const_iterator end() const;
/** /**
* @brief A template to convert the service data to <type\>. * @brief A template to convert the service data to <type\>.
@ -63,21 +102,14 @@ public:
* less than <tt>sizeof(<type\>)</tt>. * less than <tt>sizeof(<type\>)</tt>.
* @details <b>Use:</b> <tt>getManufacturerData<type>(skipSizeCheck);</tt> * @details <b>Use:</b> <tt>getManufacturerData<type>(skipSizeCheck);</tt>
*/ */
template<typename T> template <typename T>
T getManufacturerData(bool skipSizeCheck = false) { T getManufacturerData(bool skipSizeCheck = false) const {
std::string data = getManufacturerData(); std::string data = getManufacturerData();
if(!skipSizeCheck && data.size() < sizeof(T)) return T(); if (!skipSizeCheck && data.size() < sizeof(T)) return T();
const char *pData = data.data(); const char* pData = data.data();
return *((T *)pData); return *((T*)pData);
} }
std::string getName();
int getRSSI();
NimBLEScan* getScan();
uint8_t getServiceDataCount();
std::string getServiceData(uint8_t index = 0);
std::string getServiceData(const NimBLEUUID &uuid);
/** /**
* @brief A template to convert the service data to <tt><type\></tt>. * @brief A template to convert the service data to <tt><type\></tt>.
* @tparam T The type to convert the data to. * @tparam T The type to convert the data to.
@ -87,12 +119,12 @@ public:
* less than <tt>sizeof(<type\>)</tt>. * less than <tt>sizeof(<type\>)</tt>.
* @details <b>Use:</b> <tt>getServiceData<type>(skipSizeCheck);</tt> * @details <b>Use:</b> <tt>getServiceData<type>(skipSizeCheck);</tt>
*/ */
template<typename T> template <typename T>
T getServiceData(uint8_t index = 0, bool skipSizeCheck = false) { T getServiceData(uint8_t index = 0, bool skipSizeCheck = false) const {
std::string data = getServiceData(index); std::string data = getServiceData(index);
if(!skipSizeCheck && data.size() < sizeof(T)) return T(); if (!skipSizeCheck && data.size() < sizeof(T)) return T();
const char *pData = data.data(); const char* pData = data.data();
return *((T *)pData); return *((T*)pData);
} }
/** /**
@ -104,80 +136,38 @@ public:
* less than <tt>sizeof(<type\>)</tt>. * less than <tt>sizeof(<type\>)</tt>.
* @details <b>Use:</b> <tt>getServiceData<type>(skipSizeCheck);</tt> * @details <b>Use:</b> <tt>getServiceData<type>(skipSizeCheck);</tt>
*/ */
template<typename T> template <typename T>
T getServiceData(const NimBLEUUID &uuid, bool skipSizeCheck = false) { T getServiceData(const NimBLEUUID& uuid, bool skipSizeCheck = false) const {
std::string data = getServiceData(uuid); std::string data = getServiceData(uuid);
if(!skipSizeCheck && data.size() < sizeof(T)) return T(); if (!skipSizeCheck && data.size() < sizeof(T)) return T();
const char *pData = data.data(); const char* pData = data.data();
return *((T *)pData); return *((T*)pData);
} }
NimBLEUUID getServiceDataUUID(uint8_t index = 0); private:
NimBLEUUID getServiceUUID(uint8_t index = 0);
uint8_t getServiceUUIDCount();
NimBLEAddress getTargetAddress(uint8_t index = 0);
uint8_t getTargetAddressCount();
int8_t getTXPower();
uint8_t* getPayload();
uint8_t getAdvLength();
size_t getPayloadLength();
uint8_t getAddressType();
time_t getTimestamp();
bool isAdvertisingService(const NimBLEUUID &uuid);
bool haveAppearance();
bool haveManufacturerData();
bool haveName();
bool haveRSSI();
bool haveServiceData();
bool haveServiceUUID();
bool haveTXPower();
bool haveConnParams();
bool haveAdvInterval();
bool haveTargetAddress();
bool haveURI();
bool haveType(uint16_t type);
std::string toString();
bool isConnectable();
bool isLegacyAdvertisement();
#if CONFIG_BT_NIMBLE_EXT_ADV
uint8_t getSetId();
uint8_t getPrimaryPhy();
uint8_t getSecondaryPhy();
uint16_t getPeriodicInterval();
#endif
private:
friend class NimBLEScan; friend class NimBLEScan;
void setAddress(NimBLEAddress address); NimBLEAdvertisedDevice(const ble_gap_event* event, uint8_t eventType);
void setAdvType(uint8_t advType, bool isLegacyAdv); void update(const ble_gap_event* event, uint8_t eventType);
void setPayload(const uint8_t *payload, uint8_t length, bool append); uint8_t findAdvField(uint8_t type, uint8_t index = 0, size_t* data_loc = nullptr) const;
void setRSSI(int rssi); size_t findServiceData(uint8_t index, uint8_t* bytes) const;
#if CONFIG_BT_NIMBLE_EXT_ADV
void setSetId(uint8_t sid) { m_sid = sid; }
void setPrimaryPhy(uint8_t phy) { m_primPhy = phy; }
void setSecondaryPhy(uint8_t phy) { m_secPhy = phy; }
void setPeriodicInterval(uint16_t itvl) { m_periodicItvl = itvl; }
#endif
uint8_t findAdvField(uint8_t type, uint8_t index = 0, size_t * data_loc = nullptr);
size_t findServiceData(uint8_t index, uint8_t* bytes);
NimBLEAddress m_address; NimBLEAddress m_address{};
uint8_t m_advType; uint8_t m_advType{};
int m_rssi; int8_t m_rssi{};
time_t m_timestamp; uint8_t m_callbackSent{};
uint8_t m_callbackSent; uint8_t m_advLength{};
uint8_t m_advLength;
#if CONFIG_BT_NIMBLE_EXT_ADV # if CONFIG_BT_NIMBLE_EXT_ADV
bool m_isLegacyAdv; bool m_isLegacyAdv{};
uint8_t m_sid; uint8_t m_sid{};
uint8_t m_primPhy; uint8_t m_primPhy{};
uint8_t m_secPhy; uint8_t m_secPhy{};
uint16_t m_periodicItvl; uint16_t m_periodicItvl{};
#endif # endif
std::vector<uint8_t> m_payload; std::vector<uint8_t> m_payload;
}; };
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_OBSERVER */ #endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_OBSERVER */
#endif /* COMPONENTS_NIMBLEADVERTISEDDEVICE_H_ */ #endif /* NIMBLE_CPP_ADVERTISED_DEVICE_H_ */

View file

@ -111,29 +111,17 @@ int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) {
return 0; return 0;
} }
advertisedDevice = new NimBLEAdvertisedDevice(); advertisedDevice = new NimBLEAdvertisedDevice(event, event_type);
advertisedDevice->setAddress(advertisedAddress);
advertisedDevice->setAdvType(event_type, isLegacyAdv);
#if CONFIG_BT_NIMBLE_EXT_ADV
advertisedDevice->setSetId(disc.sid);
advertisedDevice->setPrimaryPhy(disc.prim_phy);
advertisedDevice->setSecondaryPhy(disc.sec_phy);
advertisedDevice->setPeriodicInterval(disc.periodic_adv_itvl);
#endif
pScan->m_scanResults.m_advertisedDevicesVector.push_back(advertisedDevice); pScan->m_scanResults.m_advertisedDevicesVector.push_back(advertisedDevice);
NIMBLE_LOGI(LOG_TAG, "New advertiser: %s", advertisedAddress.toString().c_str()); NIMBLE_LOGI(LOG_TAG, "New advertiser: %s", advertisedAddress.toString().c_str());
} else if (advertisedDevice != nullptr) { } else if (advertisedDevice != nullptr) {
advertisedDevice->update(event, event_type);
NIMBLE_LOGI(LOG_TAG, "Updated advertiser: %s", advertisedAddress.toString().c_str()); NIMBLE_LOGI(LOG_TAG, "Updated advertiser: %s", advertisedAddress.toString().c_str());
} else { } else {
// Scan response from unknown device // Scan response from unknown device
return 0; return 0;
} }
advertisedDevice->m_timestamp = time(nullptr);
advertisedDevice->setRSSI(disc.rssi);
advertisedDevice->setPayload(disc.data, disc.length_data, (isLegacyAdv &&
event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP));
if (pScan->m_pScanCallbacks) { if (pScan->m_pScanCallbacks) {
if (advertisedDevice->m_callbackSent == 0 || !pScan->m_scan_params.filter_duplicates) { if (advertisedDevice->m_callbackSent == 0 || !pScan->m_scan_params.filter_duplicates) {
advertisedDevice->m_callbackSent = 1; advertisedDevice->m_callbackSent = 1;