From 821d510c87beda796071b37629b0d844cfeeadbb Mon Sep 17 00:00:00 2001 From: h2zero Date: Wed, 17 Jul 2024 19:52:01 -0600 Subject: [PATCH] [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` 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. --- src/NimBLEAdvertisedDevice.cpp | 626 +++++++++++++-------------------- src/NimBLEAdvertisedDevice.h | 218 ++++++------ src/NimBLEScan.cpp | 16 +- 3 files changed, 358 insertions(+), 502 deletions(-) diff --git a/src/NimBLEAdvertisedDevice.cpp b/src/NimBLEAdvertisedDevice.cpp index fba6f5d7..dea7127e 100644 --- a/src/NimBLEAdvertisedDevice.cpp +++ b/src/NimBLEAdvertisedDevice.cpp @@ -15,39 +15,72 @@ #include "nimconfig.h" #if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) -#include "NimBLEDevice.h" -#include "NimBLEAdvertisedDevice.h" -#include "NimBLEUtils.h" -#include "NimBLELog.h" +# include "NimBLEDevice.h" +# include "NimBLEAdvertisedDevice.h" +# include "NimBLEUtils.h" +# include "NimBLELog.h" -#include +# include static const char* LOG_TAG = "NimBLEAdvertisedDevice"; - /** * @brief Constructor - */ -NimBLEAdvertisedDevice::NimBLEAdvertisedDevice() : - m_payload(62,0) -{ - m_advType = 0; - m_rssi = -9999; - m_callbackSent = 0; - m_timestamp = 0; - m_advLength = 0; + * @param [in] event The advertisement event data. + */ +NimBLEAdvertisedDevice::NimBLEAdvertisedDevice(const ble_gap_event* event, uint8_t eventType) +# if CONFIG_BT_NIMBLE_EXT_ADV + : m_address{event->ext_disc.addr}, + m_advType{eventType}, + m_rssi{event->ext_disc.rssi}, + m_callbackSent{0}, + m_advLength{event->ext_disc.length_data}, + m_isLegacyAdv{!!(event->ext_disc.props & BLE_HCI_ADV_LEGACY_MASK)}, + m_sid{event->ext_disc.sid}, + m_primPhy{event->ext_disc.prim_phy}, + m_secPhy{event->ext_disc.sec_phy}, + m_periodicItvl{event->ext_disc.periodic_adv_itvl}, + m_payload(event->ext_disc.data, event->ext_disc.data + event->ext_disc.length_data) { +# else + : m_address{event->disc.addr}, + m_advType{eventType}, + m_rssi{event->disc.rssi}, + m_callbackSent{0}, + m_advLength{event->disc.length_data}, + m_payload{event->disc.data, event->disc.data + event->disc.length_data} { +# endif } // NimBLEAdvertisedDevice +/** + * @brief Update the advertisement data. + * @param [in] event The advertisement event data. + */ +void NimBLEAdvertisedDevice::update(const ble_gap_event* event, uint8_t eventType) { +# if CONFIG_BT_NIMBLE_EXT_ADV + const auto& disc = event->ext_disc; + m_isLegacyAdv = disc.props & BLE_HCI_ADV_LEGACY_MASK; +# else + const auto& disc = event->disc; +# endif + + m_rssi = disc.rssi; + if (eventType == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP && isLegacyAdvertisement()) { + m_payload.insert(m_payload.end(), disc.data, disc.data + disc.length_data); + return; + } + m_advLength = disc.length_data; + m_payload.assign(disc.data, disc.data + disc.length_data); + m_callbackSent = 0; // new data, reset callback sent flag +} // update /** * @brief Get the address of the advertising device. * @return The address of the advertised device. */ -NimBLEAddress NimBLEAdvertisedDevice::getAddress() { +const NimBLEAddress& NimBLEAdvertisedDevice::getAddress() const { return m_address; } // getAddress - /** * @brief Get the advertisement type. * @return The advertising type the device is reporting: @@ -57,11 +90,10 @@ NimBLEAddress NimBLEAdvertisedDevice::getAddress() { * * BLE_HCI_ADV_TYPE_ADV_NONCONN_IND (3) - indirect advertising - not connectable * * BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD (4) - direct advertising - low duty cycle */ -uint8_t NimBLEAdvertisedDevice::getAdvType() { +uint8_t NimBLEAdvertisedDevice::getAdvType() const { return m_advType; } // getAdvType - /** * @brief Get the advertisement flags. * @return The advertisement flags, a bitmask of: @@ -69,15 +101,15 @@ uint8_t NimBLEAdvertisedDevice::getAdvType() { * BLE_HS_ADV_F_DISC_GEN (0x02) - general discoverability * BLE_HS_ADV_F_BREDR_UNSUP - BR/EDR not supported */ -uint8_t NimBLEAdvertisedDevice::getAdvFlags() { - size_t data_loc = 0; - - if(findAdvField(BLE_HS_ADV_TYPE_FLAGS, 0, &data_loc) > 0) { - ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length == BLE_HS_ADV_FLAGS_LEN + 1) { +uint8_t NimBLEAdvertisedDevice::getAdvFlags() const { + size_t data_loc; + if (findAdvField(BLE_HS_ADV_TYPE_FLAGS, 0, &data_loc) > 0) { + const ble_hs_adv_field* field = reinterpret_cast(&m_payload[data_loc]); + if (field->length == BLE_HS_ADV_FLAGS_LEN + 1) { return *field->value; } } + return 0; } // getAdvFlags @@ -89,12 +121,11 @@ uint8_t NimBLEAdvertisedDevice::getAdvFlags() { * * @return The appearance of the advertised device. */ -uint16_t NimBLEAdvertisedDevice::getAppearance() { - size_t data_loc = 0; - - if(findAdvField(BLE_HS_ADV_TYPE_APPEARANCE, 0, &data_loc) > 0) { - ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length == BLE_HS_ADV_APPEARANCE_LEN + 1) { +uint16_t NimBLEAdvertisedDevice::getAppearance() const { + size_t data_loc; + if (findAdvField(BLE_HS_ADV_TYPE_APPEARANCE, 0, &data_loc) > 0) { + const ble_hs_adv_field* field = reinterpret_cast(&m_payload[data_loc]); + if (field->length == BLE_HS_ADV_APPEARANCE_LEN + 1) { return *field->value | *(field->value + 1) << 8; } } @@ -102,17 +133,15 @@ uint16_t NimBLEAdvertisedDevice::getAppearance() { return 0; } // getAppearance - /** * @brief Get the advertisement interval. * @return The advertisement interval in 0.625ms units. */ -uint16_t NimBLEAdvertisedDevice::getAdvInterval() { - size_t data_loc = 0; - - if(findAdvField(BLE_HS_ADV_TYPE_ADV_ITVL, 0, &data_loc) > 0) { - ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length == BLE_HS_ADV_ADV_ITVL_LEN + 1) { +uint16_t NimBLEAdvertisedDevice::getAdvInterval() const { + size_t data_loc; + if (findAdvField(BLE_HS_ADV_TYPE_ADV_ITVL, 0, &data_loc) > 0) { + const ble_hs_adv_field* field = reinterpret_cast(&m_payload[data_loc]); + if (field->length == BLE_HS_ADV_ADV_ITVL_LEN + 1) { return *field->value | *(field->value + 1) << 8; } } @@ -120,17 +149,15 @@ uint16_t NimBLEAdvertisedDevice::getAdvInterval() { return 0; } // getAdvInterval - /** * @brief Get the preferred min connection interval. * @return The preferred min connection interval in 1.25ms units. */ -uint16_t NimBLEAdvertisedDevice::getMinInterval() { - size_t data_loc = 0; - - if(findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE, 0, &data_loc) > 0) { - ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length == BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1) { +uint16_t NimBLEAdvertisedDevice::getMinInterval() const { + size_t data_loc; + if (findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE, 0, &data_loc) > 0) { + const ble_hs_adv_field* field = reinterpret_cast(&m_payload[data_loc]); + if (field->length == BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1) { return *field->value | *(field->value + 1) << 8; } } @@ -138,17 +165,15 @@ uint16_t NimBLEAdvertisedDevice::getMinInterval() { return 0; } // getMinInterval - /** * @brief Get the preferred max connection interval. * @return The preferred max connection interval in 1.25ms units. */ -uint16_t NimBLEAdvertisedDevice::getMaxInterval() { - size_t data_loc = 0; - - if(findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE, 0, &data_loc) > 0) { - ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length == BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1) { +uint16_t NimBLEAdvertisedDevice::getMaxInterval() const { + size_t data_loc; + if (findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE, 0, &data_loc) > 0) { + const ble_hs_adv_field* field = reinterpret_cast(&m_payload[data_loc]); + if (field->length == BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1) { return *(field->value + 2) | *(field->value + 3) << 8; } } @@ -156,64 +181,42 @@ uint16_t NimBLEAdvertisedDevice::getMaxInterval() { return 0; } // getMaxInterval - /** * @brief Get the manufacturer data. * @param [in] index The index of the of the manufacturer data set to get. * @return The manufacturer data. */ -std::string NimBLEAdvertisedDevice::getManufacturerData(uint8_t index) { - size_t data_loc = 0; - index++; - - if(findAdvField(BLE_HS_ADV_TYPE_MFG_DATA, index, &data_loc) > 0) { - ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length > 1) { - return std::string((char*)field->value, field->length - 1); - } - } - - return ""; +std::string NimBLEAdvertisedDevice::getManufacturerData(uint8_t index) const { + return getPayloadByType(BLE_HS_ADV_TYPE_MFG_DATA, index); } // getManufacturerData - /** * @brief Get the count of manufacturer data sets. * @return The number of manufacturer data sets. */ -uint8_t NimBLEAdvertisedDevice::getManufacturerDataCount() { +uint8_t NimBLEAdvertisedDevice::getManufacturerDataCount() const { return findAdvField(BLE_HS_ADV_TYPE_MFG_DATA); } // getManufacturerDataCount - /** * @brief Get the URI from the advertisement. * @return The URI data. */ -std::string NimBLEAdvertisedDevice::getURI() { - size_t data_loc = 0; - - if(findAdvField(BLE_HS_ADV_TYPE_URI, 0, &data_loc) > 0) { - ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length > 1) { - return std::string((char*)field->value, field->length - 1); - } - } - - return ""; +std::string NimBLEAdvertisedDevice::getURI() const { + return getPayloadByType(BLE_HS_ADV_TYPE_URI); } // getURI /** - * @brief Get the data from any type available in the advertisement - * @param [in] type The advertised data type BLE_HS_ADV_TYPE - * @return The data available under the type `type` -*/ -std::string NimBLEAdvertisedDevice::getPayloadByType(uint16_t type) { - size_t data_loc = 0; - - if(findAdvField(type, 0, &data_loc) > 0) { - ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length > 1) { + * @brief Get the data from any type available in the advertisement. + * @param [in] type The advertised data type BLE_HS_ADV_TYPE. + * @param [in] index The index of the data type. + * @return The data available under the type `type`. + */ +std::string NimBLEAdvertisedDevice::getPayloadByType(uint16_t type, uint8_t index) const { + size_t data_loc; + if (findAdvField(type, index, &data_loc) > 0) { + const ble_hs_adv_field* field = reinterpret_cast(&m_payload[data_loc]); + if (field->length > 1) { return std::string((char*)field->value, field->length - 1); } } @@ -221,129 +224,105 @@ std::string NimBLEAdvertisedDevice::getPayloadByType(uint16_t type) { return ""; } // getPayloadByType - /** * @brief Get the advertised name. * @return The name of the advertised device. */ -std::string NimBLEAdvertisedDevice::getName() { - size_t data_loc = 0; - - if(findAdvField(BLE_HS_ADV_TYPE_COMP_NAME, 0, &data_loc) > 0 || - findAdvField(BLE_HS_ADV_TYPE_INCOMP_NAME, 0, &data_loc) > 0) - { - ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length > 1) { - return std::string((char*)field->value, field->length - 1); - } - } - - return ""; +std::string NimBLEAdvertisedDevice::getName() const { + return getPayloadByType(BLE_HS_ADV_TYPE_COMP_NAME); } // getName - /** * @brief Get the RSSI. * @return The RSSI of the advertised device. */ -int NimBLEAdvertisedDevice::getRSSI() { +int8_t NimBLEAdvertisedDevice::getRSSI() const { return m_rssi; } // getRSSI - /** * @brief Get the scan object that created this advertised device. * @return The scan object. */ -NimBLEScan* NimBLEAdvertisedDevice::getScan() { +NimBLEScan* NimBLEAdvertisedDevice::getScan() const { return NimBLEDevice::getScan(); } // getScan - /** * @brief Get the number of target addresses. * @return The number of addresses. */ -uint8_t NimBLEAdvertisedDevice::getTargetAddressCount() { - uint8_t count = 0; - - count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR); - count += findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR); +uint8_t NimBLEAdvertisedDevice::getTargetAddressCount() const { + uint8_t count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR); + count += findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR); return count; } - /** * @brief Get the target address at the index. * @param [in] index The index of the target address. * @return The target address. */ -NimBLEAddress NimBLEAdvertisedDevice::getTargetAddress(uint8_t index) { - ble_hs_adv_field *field = nullptr; - uint8_t count = 0; - size_t data_loc = ULONG_MAX; - - index++; - count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR, index, &data_loc); - - if (count < index) { +NimBLEAddress NimBLEAdvertisedDevice::getTargetAddress(uint8_t index) const { + size_t data_loc = ULONG_MAX; + uint8_t count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR, index, &data_loc); + if (count < index + 1) { index -= count; count = findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR, index, &data_loc); } - if(count > 0 && data_loc != ULONG_MAX) { - field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length < index * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN) { + if (count > 0 && data_loc != ULONG_MAX) { + index++; + const ble_hs_adv_field* field = reinterpret_cast(&m_payload[data_loc]); + if (field->length < index * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN) { + // In the case of more than one field of target addresses we need to adjust the index index -= count - field->length / BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN; } - if(field->length > index * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN) { - return NimBLEAddress(field->value + (index - 1) * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN); + if (field->length > index * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN) { + return NimBLEAddress{field->value + (index - 1) * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN, field->type}; } } return NimBLEAddress{}; } - /** * @brief Get the service data. * @param [in] index The index of the service data requested. * @return The advertised service data or empty string if no data. */ -std::string NimBLEAdvertisedDevice::getServiceData(uint8_t index) { - ble_hs_adv_field *field = nullptr; +std::string NimBLEAdvertisedDevice::getServiceData(uint8_t index) const { uint8_t bytes; - size_t data_loc = findServiceData(index, &bytes); - - if(data_loc != ULONG_MAX) { - field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length > bytes) { - return std::string((char*)(field->value + bytes), field->length - bytes - 1); + size_t data_loc = findServiceData(index, &bytes); + if (data_loc != ULONG_MAX) { + const ble_hs_adv_field* field = reinterpret_cast(&m_payload[data_loc]); + if (field->length > bytes) { + const char* field_data = reinterpret_cast(field->value + bytes); + return std::string(field_data, field->length - bytes - 1); } } return ""; -} //getServiceData - +} // getServiceData /** * @brief Get the service data. * @param [in] uuid The uuid of the service data requested. * @return The advertised service data or empty string if no data. */ -std::string NimBLEAdvertisedDevice::getServiceData(const NimBLEUUID &uuid) { - ble_hs_adv_field *field = nullptr; +std::string NimBLEAdvertisedDevice::getServiceData(const NimBLEUUID& uuid) const { uint8_t bytes; - uint8_t index = 0; - size_t data_loc = findServiceData(index, &bytes); - size_t plSize = m_payload.size() - 2; - uint8_t uuidBytes = uuid.bitSize() / 8; - - while(data_loc < plSize) { - field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(bytes == uuidBytes && NimBLEUUID(field->value, bytes, false) == uuid) { - return std::string((char*)(field->value + bytes), field->length - bytes - 1); + uint8_t index = 0; + size_t data_loc = findServiceData(index, &bytes); + size_t pl_size = m_payload.size() - 2; + uint8_t uuid_bytes = uuid.bitSize() / 8; + + while (data_loc < pl_size) { + const ble_hs_adv_field* field = reinterpret_cast(&m_payload[data_loc]); + if (bytes == uuid_bytes && NimBLEUUID(field->value, bytes, false) == uuid) { + const char* field_data = reinterpret_cast(field->value + bytes); + return std::string(field_data, field->length - bytes - 1); } index++; @@ -352,22 +331,19 @@ std::string NimBLEAdvertisedDevice::getServiceData(const NimBLEUUID &uuid) { NIMBLE_LOGI(LOG_TAG, "No service data found"); return ""; -} //getServiceData - +} // getServiceData /** * @brief Get the UUID of the service data at the index. * @param [in] index The index of the service data UUID requested. * @return The advertised service data UUID or an empty UUID if not found. */ -NimBLEUUID NimBLEAdvertisedDevice::getServiceDataUUID(uint8_t index) { - ble_hs_adv_field *field = nullptr; +NimBLEUUID NimBLEAdvertisedDevice::getServiceDataUUID(uint8_t index) const { uint8_t bytes; - size_t data_loc = findServiceData(index, &bytes); - - if(data_loc != ULONG_MAX) { - field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length >= bytes) { + size_t data_loc = findServiceData(index, &bytes); + if (data_loc != ULONG_MAX) { + const ble_hs_adv_field* field = reinterpret_cast(&m_payload[data_loc]); + if (field->length >= bytes) { return NimBLEUUID(field->value, bytes, false); } } @@ -375,35 +351,32 @@ NimBLEUUID NimBLEAdvertisedDevice::getServiceDataUUID(uint8_t index) { return NimBLEUUID(""); } // getServiceDataUUID - /** * @brief Find the service data at the index. * @param [in] index The index of the service data to find. * @param [in] bytes A pointer to storage for the number of the bytes in the UUID. * @return The index in the vector where the data is located, ULONG_MAX if not found. */ -size_t NimBLEAdvertisedDevice::findServiceData(uint8_t index, uint8_t *bytes) { - size_t data_loc = 0; - uint8_t found = 0; - +size_t NimBLEAdvertisedDevice::findServiceData(uint8_t index, uint8_t* bytes) const { *bytes = 0; - index++; - found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID16, index, &data_loc); - if(found == index) { + + size_t data_loc = 0; + uint8_t found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID16, index, &data_loc); + if (found > index) { *bytes = 2; return data_loc; } index -= found; found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID32, index, &data_loc); - if(found == index) { + if (found > index) { *bytes = 4; return data_loc; } index -= found; found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID128, index, &data_loc); - if(found == index) { + if (found > index) { *bytes = 16; return data_loc; } @@ -411,45 +384,38 @@ size_t NimBLEAdvertisedDevice::findServiceData(uint8_t index, uint8_t *bytes) { return ULONG_MAX; } - /** * @brief Get the count of advertised service data UUIDS * @return The number of service data UUIDS in the vector. */ -uint8_t NimBLEAdvertisedDevice::getServiceDataCount() { - uint8_t count = 0; - - count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID16); - count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID32); - count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID128); +uint8_t NimBLEAdvertisedDevice::getServiceDataCount() const { + uint8_t count = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID16); + count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID32); + count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID128); return count; } // getServiceDataCount - /** * @brief Get the Service UUID. * @param [in] index The index of the service UUID requested. * @return The Service UUID of the advertised service, or an empty UUID if not found. */ -NimBLEUUID NimBLEAdvertisedDevice::getServiceUUID(uint8_t index) { - uint8_t count = 0; - size_t data_loc = 0; - uint8_t uuidBytes = 0; - uint8_t type = BLE_HS_ADV_TYPE_INCOMP_UUIDS16; - ble_hs_adv_field *field = nullptr; - - index++; +NimBLEUUID NimBLEAdvertisedDevice::getServiceUUID(uint8_t index) const { + uint8_t type = BLE_HS_ADV_TYPE_INCOMP_UUIDS16; + size_t data_loc = 0; + uint8_t uuid_bytes = 0; + uint8_t count = 0; do { count = findAdvField(type, index, &data_loc); - if(count >= index) { - if(type < BLE_HS_ADV_TYPE_INCOMP_UUIDS32) { - uuidBytes = 2; - } else if(type < BLE_HS_ADV_TYPE_INCOMP_UUIDS128) { - uuidBytes = 4; + if (count > index) { + if (type < BLE_HS_ADV_TYPE_INCOMP_UUIDS32) { + uuid_bytes = 2; + } else if (type < BLE_HS_ADV_TYPE_INCOMP_UUIDS128) { + uuid_bytes = 4; } else { - uuidBytes = 16; + uuid_bytes = 16; } break; @@ -458,52 +424,49 @@ NimBLEUUID NimBLEAdvertisedDevice::getServiceUUID(uint8_t index) { index -= count; } - } while(type <= BLE_HS_ADV_TYPE_COMP_UUIDS128); + } while (type <= BLE_HS_ADV_TYPE_COMP_UUIDS128); - if(uuidBytes > 0) { - field = (ble_hs_adv_field *)&m_payload[data_loc]; + if (uuid_bytes > 0) { + index++; + const ble_hs_adv_field* field = reinterpret_cast(&m_payload[data_loc]); // In the case of more than one field of service uuid's we need to adjust // the index to account for the uuids of the previous fields. - if(field->length < index * uuidBytes) { - index -= count - field->length / uuidBytes; + if (field->length < index * uuid_bytes) { + index -= count - field->length / uuid_bytes; } - if(field->length > uuidBytes * index) { - return NimBLEUUID(field->value + uuidBytes * (index - 1), uuidBytes, false); + if (field->length > uuid_bytes * index) { + return NimBLEUUID(field->value + uuid_bytes * (index - 1), uuid_bytes, false); } } return NimBLEUUID(""); } // getServiceUUID - /** * @brief Get the number of services advertised * @return The count of services in the advertising packet. */ -uint8_t NimBLEAdvertisedDevice::getServiceUUIDCount() { - uint8_t count = 0; - - count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS16); - count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS16); - count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS32); - count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS32); - count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS128); - count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS128); +uint8_t NimBLEAdvertisedDevice::getServiceUUIDCount() const { + uint8_t count = findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS16); + count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS16); + count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS32); + count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS32); + count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS128); + count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS128); return count; } // getServiceUUIDCount - /** * @brief Check advertised services for existence of the required UUID * @param [in] uuid The service uuid to look for in the advertisement. * @return Return true if service is advertised */ -bool NimBLEAdvertisedDevice::isAdvertisingService(const NimBLEUUID &uuid) { +bool NimBLEAdvertisedDevice::isAdvertisingService(const NimBLEUUID& uuid) const { size_t count = getServiceUUIDCount(); - for(size_t i = 0; i < count; i++) { - if(uuid == getServiceUUID(i)) { + for (size_t i = 0; i < count; i++) { + if (uuid == getServiceUUID(i)) { return true; } } @@ -511,17 +474,15 @@ bool NimBLEAdvertisedDevice::isAdvertisingService(const NimBLEUUID &uuid) { return false; } // isAdvertisingService - /** * @brief Get the TX Power. * @return The TX Power of the advertised device. */ -int8_t NimBLEAdvertisedDevice::getTXPower() { +int8_t NimBLEAdvertisedDevice::getTXPower() const { size_t data_loc = 0; - - if(findAdvField(BLE_HS_ADV_TYPE_TX_PWR_LVL, 0, &data_loc) > 0) { - ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length == BLE_HS_ADV_TX_PWR_LVL_LEN + 1) { + if (findAdvField(BLE_HS_ADV_TYPE_TX_PWR_LVL, 0, &data_loc) > 0) { + const ble_hs_adv_field* field = reinterpret_cast(&m_payload[data_loc]); + if (field->length == BLE_HS_ADV_TX_PWR_LVL_LEN + 1) { return *(int8_t*)field->value; } } @@ -529,137 +490,113 @@ int8_t NimBLEAdvertisedDevice::getTXPower() { return -99; } // getTXPower - /** * @brief Does this advertisement have preferred connection parameters? * @return True if connection parameters are present. */ -bool NimBLEAdvertisedDevice::haveConnParams() { +bool NimBLEAdvertisedDevice::haveConnParams() const { return findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE) > 0; } // haveConnParams - /** * @brief Does this advertisement have have the advertising interval? * @return True if the advertisement interval is present. */ -bool NimBLEAdvertisedDevice::haveAdvInterval() { +bool NimBLEAdvertisedDevice::haveAdvInterval() const { return findAdvField(BLE_HS_ADV_TYPE_ADV_ITVL) > 0; } // haveAdvInterval - /** * @brief Does this advertisement have an appearance value? * @return True if there is an appearance value present. */ -bool NimBLEAdvertisedDevice::haveAppearance() { +bool NimBLEAdvertisedDevice::haveAppearance() const { return findAdvField(BLE_HS_ADV_TYPE_APPEARANCE) > 0; } // haveAppearance - /** * @brief Does this advertisement have manufacturer data? * @return True if there is manufacturer data present. */ -bool NimBLEAdvertisedDevice::haveManufacturerData() { +bool NimBLEAdvertisedDevice::haveManufacturerData() const { return findAdvField(BLE_HS_ADV_TYPE_MFG_DATA) > 0; } // haveManufacturerData - /** * @brief Does this advertisement have a URI? * @return True if there is a URI present. */ -bool NimBLEAdvertisedDevice::haveURI() { +bool NimBLEAdvertisedDevice::haveURI() const { return findAdvField(BLE_HS_ADV_TYPE_URI) > 0; } // haveURI /** * @brief Does this advertisement have a adv type `type`? * @return True if there is a `type` present. -*/ -bool NimBLEAdvertisedDevice::haveType(uint16_t type) { + */ +bool NimBLEAdvertisedDevice::haveType(uint16_t type) const { return findAdvField(type) > 0; } - /** * @brief Does the advertisement contain a target address? * @return True if an address is present. */ -bool NimBLEAdvertisedDevice::haveTargetAddress() { - return findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR) > 0 || - findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR) > 0; +bool NimBLEAdvertisedDevice::haveTargetAddress() const { + return findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR) > 0 || findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR) > 0; } - /** * @brief Does this advertisement have a name value? * @return True if there is a name value present. */ -bool NimBLEAdvertisedDevice::haveName() { - return findAdvField(BLE_HS_ADV_TYPE_COMP_NAME) > 0 || - findAdvField(BLE_HS_ADV_TYPE_INCOMP_NAME) > 0; +bool NimBLEAdvertisedDevice::haveName() const { + return findAdvField(BLE_HS_ADV_TYPE_COMP_NAME) > 0; } // haveName - -/** - * @brief Does this advertisement have a signal strength value? - * @return True if there is a signal strength value present. - */ -bool NimBLEAdvertisedDevice::haveRSSI() { - return m_rssi != -9999; -} // haveRSSI - - /** * @brief Does this advertisement have a service data value? * @return True if there is a service data value present. */ -bool NimBLEAdvertisedDevice::haveServiceData() { +bool NimBLEAdvertisedDevice::haveServiceData() const { return getServiceDataCount() > 0; } // haveServiceData - /** * @brief Does this advertisement have a service UUID value? * @return True if there is a service UUID value present. */ -bool NimBLEAdvertisedDevice::haveServiceUUID() { +bool NimBLEAdvertisedDevice::haveServiceUUID() const { return getServiceUUIDCount() > 0; } // haveServiceUUID - /** * @brief Does this advertisement have a transmission power value? * @return True if there is a transmission power value present. */ -bool NimBLEAdvertisedDevice::haveTXPower() { +bool NimBLEAdvertisedDevice::haveTXPower() const { return findAdvField(BLE_HS_ADV_TYPE_TX_PWR_LVL) > 0; } // haveTXPower - -#if CONFIG_BT_NIMBLE_EXT_ADV +# if CONFIG_BT_NIMBLE_EXT_ADV /** * @brief Get the set ID of the extended advertisement. * @return The set ID. */ -uint8_t NimBLEAdvertisedDevice::getSetId() { +uint8_t NimBLEAdvertisedDevice::getSetId() const { return m_sid; } // getSetId - /** * @brief Get the primary PHY used by this advertisement. * @return The PHY type, one of: * * BLE_HCI_LE_PHY_1M * * BLE_HCI_LE_PHY_CODED */ -uint8_t NimBLEAdvertisedDevice::getPrimaryPhy() { +uint8_t NimBLEAdvertisedDevice::getPrimaryPhy() const { return m_primPhy; } // getPrimaryPhy - /** * @brief Get the primary PHY used by this advertisement. * @return The PHY type, one of: @@ -667,39 +604,31 @@ uint8_t NimBLEAdvertisedDevice::getPrimaryPhy() { * * BLE_HCI_LE_PHY_2M * * BLE_HCI_LE_PHY_CODED */ -uint8_t NimBLEAdvertisedDevice::getSecondaryPhy() { +uint8_t NimBLEAdvertisedDevice::getSecondaryPhy() const { return m_secPhy; } // getSecondaryPhy - /** * @brief Get the periodic interval of the advertisement. * @return The periodic advertising interval, 0 if not periodic advertising. */ -uint16_t NimBLEAdvertisedDevice::getPeriodicInterval() { +uint16_t NimBLEAdvertisedDevice::getPeriodicInterval() const { return m_periodicItvl; } // getPeriodicInterval -#endif +# endif - -uint8_t NimBLEAdvertisedDevice::findAdvField(uint8_t type, uint8_t index, size_t * data_loc) { - ble_hs_adv_field *field = nullptr; +uint8_t NimBLEAdvertisedDevice::findAdvField(uint8_t type, uint8_t index, size_t* data_loc) const { size_t length = m_payload.size(); size_t data = 0; uint8_t count = 0; - if (length < 3) { - return count; - } - while (length > 2) { - field = (ble_hs_adv_field*)&m_payload[data]; - + const ble_hs_adv_field* field = reinterpret_cast(&m_payload[data]); if (field->length >= length) { return count; } - if (field->type == type) { + if (field->type == type || (type == BLE_HS_ADV_TYPE_COMP_NAME && field->type == BLE_HS_ADV_TYPE_INCOMP_NAME)) { switch (type) { case BLE_HS_ADV_TYPE_INCOMP_UUIDS16: case BLE_HS_ADV_TYPE_COMP_UUIDS16: @@ -721,67 +650,41 @@ uint8_t NimBLEAdvertisedDevice::findAdvField(uint8_t type, uint8_t index, size_t count += field->length / 6; break; + case BLE_HS_ADV_TYPE_COMP_NAME: + // keep looking for complete name, else use this + if (data_loc != nullptr && field->type == BLE_HS_ADV_TYPE_INCOMP_NAME) { + *data_loc = data; + index++; + } + // fall through default: count++; break; } if (data_loc != nullptr) { - if (index == 0 || count >= index) { + if (count > index) { // assumes index values default to 0 break; } } } length -= 1 + field->length; - data += 1 + field->length; + data += 1 + field->length; } - if (data_loc != nullptr && field != nullptr) { + if (data_loc != nullptr && count > index) { *data_loc = data; } return count; -} - - -/** - * @brief Set the address of the advertised device. - * @param [in] address The address of the advertised device. - */ -void NimBLEAdvertisedDevice::setAddress(NimBLEAddress address) { - m_address = address; -} // setAddress - - -/** - * @brief Set the adFlag for this device. - * @param [in] advType The advertisement flag data from the advertisement. - */ -void NimBLEAdvertisedDevice::setAdvType(uint8_t advType, bool isLegacyAdv) { - m_advType = advType; -#if CONFIG_BT_NIMBLE_EXT_ADV - m_isLegacyAdv = isLegacyAdv; -#else - (void)isLegacyAdv; -#endif -} // setAdvType - - -/** - * @brief Set the RSSI for this device. - * @param [in] rssi The RSSI of the discovered device. - */ -void NimBLEAdvertisedDevice::setRSSI(int rssi) { - m_rssi = rssi; -} // setRSSI - +} // findAdvField /** * @brief Create a string representation of this device. * @return A string representation of this device. */ -std::string NimBLEAdvertisedDevice::toString() { +std::string NimBLEAdvertisedDevice::toString() const { std::string res = "Name: " + getName() + ", Address: " + getAddress().toString(); if (haveAppearance()) { @@ -792,7 +695,8 @@ std::string NimBLEAdvertisedDevice::toString() { } if (haveManufacturerData()) { - char *pHex = NimBLEUtils::buildHexData(nullptr, (uint8_t*)getManufacturerData().data(), getManufacturerData().length()); + char* pHex = + NimBLEUtils::buildHexData(nullptr, (uint8_t*)getManufacturerData().data(), getManufacturerData().length()); res += ", manufacturer data: "; res += pHex; free(pHex); @@ -811,8 +715,8 @@ std::string NimBLEAdvertisedDevice::toString() { if (haveServiceData()) { uint8_t count = getServiceDataCount(); - res += "\nService Data:"; - for(uint8_t i = 0; i < count; i++) { + res += "\nService Data:"; + for (uint8_t i = 0; i < count; i++) { res += "\nUUID: " + std::string(getServiceDataUUID(i)); res += ", Data: " + getServiceData(i); } @@ -822,41 +726,14 @@ std::string NimBLEAdvertisedDevice::toString() { } // toString - -/** - * @brief Get the payload advertised by the device. - * @return The advertisement payload. - */ -uint8_t* NimBLEAdvertisedDevice::getPayload() { - return &m_payload[0]; -} // getPayload - - -/** - * @brief Stores the payload of the advertised device in a vector. - * @param [in] payload The advertisement payload. - * @param [in] length The length of the payload in bytes. - * @param [in] append Indicates if the the data should be appended (scan response). - */ -void NimBLEAdvertisedDevice::setPayload(const uint8_t *payload, uint8_t length, bool append) { - if(!append) { - m_advLength = length; - m_payload.assign(payload, payload + length); - } else { - m_payload.insert(m_payload.end(), payload, payload + length); - } -} - - /** * @brief Get the length of the advertisement data in the payload. * @return The number of bytes in the payload that is from the advertisement. */ -uint8_t NimBLEAdvertisedDevice::getAdvLength() { +uint8_t NimBLEAdvertisedDevice::getAdvLength() const { return m_advLength; } - /** * @brief Get the advertised device address type. * @return The device address type: @@ -865,56 +742,57 @@ uint8_t NimBLEAdvertisedDevice::getAdvLength() { * * BLE_ADDR_PUBLIC_ID (0x02) * * BLE_ADDR_RANDOM_ID (0x03) */ -uint8_t NimBLEAdvertisedDevice::getAddressType() { +uint8_t NimBLEAdvertisedDevice::getAddressType() const { return m_address.getType(); } // getAddressType - -/** - * @brief Get the timeStamp of when the device last advertised. - * @return The timeStamp of when the device was last seen. - */ -time_t NimBLEAdvertisedDevice::getTimestamp() { - return m_timestamp; -} // getTimestamp - - -/** - * @brief Get the length of the payload advertised by the device. - * @return The size of the payload in bytes. - */ -size_t NimBLEAdvertisedDevice::getPayloadLength() { - return m_payload.size(); -} // getPayloadLength - - /** * @brief Check if this device is advertising as connectable. * @return True if the device is connectable. */ -bool NimBLEAdvertisedDevice::isConnectable() { -#if CONFIG_BT_NIMBLE_EXT_ADV +bool NimBLEAdvertisedDevice::isConnectable() const { +# if CONFIG_BT_NIMBLE_EXT_ADV if (m_isLegacyAdv) { - return m_advType == BLE_HCI_ADV_RPT_EVTYPE_ADV_IND || - m_advType == BLE_HCI_ADV_RPT_EVTYPE_DIR_IND; + return m_advType == BLE_HCI_ADV_RPT_EVTYPE_ADV_IND || m_advType == BLE_HCI_ADV_RPT_EVTYPE_DIR_IND; } -#endif - return (m_advType & BLE_HCI_ADV_CONN_MASK) || - (m_advType & BLE_HCI_ADV_DIRECT_MASK); +# endif + return (m_advType & BLE_HCI_ADV_CONN_MASK) || (m_advType & BLE_HCI_ADV_DIRECT_MASK); } // isConnectable - /** * @brief Check if this advertisement is a legacy or extended type * @return True if legacy (Bluetooth 4.x), false if extended (bluetooth 5.x). */ -bool NimBLEAdvertisedDevice::isLegacyAdvertisement() { -#if CONFIG_BT_NIMBLE_EXT_ADV +bool NimBLEAdvertisedDevice::isLegacyAdvertisement() const { +# if CONFIG_BT_NIMBLE_EXT_ADV return m_isLegacyAdv; # else return true; -#endif +# endif } // isLegacyAdvertisement -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */ +/** + * @brief Get the payload advertised by the device. + * @return The advertisement payload. + */ +const std::vector& NimBLEAdvertisedDevice::getPayload() const { + return m_payload; +} + +/** + * @brief Get the begin iterator for the payload. + * @return A read only iterator pointing to the first byte in the payload. + */ +const std::vector::const_iterator NimBLEAdvertisedDevice::begin() const { + return m_payload.cbegin(); +} +/** + * @brief Get the end iterator for the payload. + * @return A read only iterator pointing to one past the last byte of the payload. + */ +const std::vector::const_iterator NimBLEAdvertisedDevice::end() const { + return m_payload.cend(); +} + +#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */ diff --git a/src/NimBLEAdvertisedDevice.h b/src/NimBLEAdvertisedDevice.h index 50d3f70c..e5563e08 100644 --- a/src/NimBLEAdvertisedDevice.h +++ b/src/NimBLEAdvertisedDevice.h @@ -12,25 +12,25 @@ * Author: kolban */ -#ifndef COMPONENTS_NIMBLEADVERTISEDDEVICE_H_ -#define COMPONENTS_NIMBLEADVERTISEDDEVICE_H_ +#ifndef NIMBLE_CPP_ADVERTISED_DEVICE_H_ +#define NIMBLE_CPP_ADVERTISED_DEVICE_H_ + #include "nimconfig.h" #if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) -#include "NimBLEAddress.h" -#include "NimBLEScan.h" -#include "NimBLEUUID.h" - -#if defined(CONFIG_NIMBLE_CPP_IDF) -#include "host/ble_hs_adv.h" -#else -#include "nimble/nimble/host/include/host/ble_hs_adv.h" -#endif +# include "NimBLEAddress.h" +# include "NimBLEScan.h" +# include "NimBLEUUID.h" -#include -#include -#include +# if defined(CONFIG_NIMBLE_CPP_IDF) +# include "host/ble_hs_adv.h" +# include "host/ble_gap.h" +# else +# include "nimble/nimble/host/include/host/ble_hs_adv.h" +# include "nimble/nimble/host/include/host/ble_gap.h" +# endif +# include class NimBLEScan; /** @@ -40,20 +40,59 @@ class NimBLEScan; * class provides a model of a detected device. */ class NimBLEAdvertisedDevice { -public: - NimBLEAdvertisedDevice(); - - NimBLEAddress getAddress(); - uint8_t getAdvType(); - uint8_t getAdvFlags(); - uint16_t getAppearance(); - uint16_t getAdvInterval(); - uint16_t getMinInterval(); - uint16_t getMaxInterval(); - uint8_t getManufacturerDataCount(); - std::string getManufacturerData(uint8_t index = 0); - std::string getURI(); - std::string getPayloadByType(uint16_t type); + public: + NimBLEAdvertisedDevice() = default; + + uint8_t getAdvType() const; + uint8_t getAdvFlags() const; + uint16_t getAppearance() const; + uint16_t getAdvInterval() const; + uint16_t getMinInterval() const; + uint16_t getMaxInterval() const; + uint8_t getManufacturerDataCount() const; + const NimBLEAddress& getAddress() const; + std::string getManufacturerData(uint8_t index = 0) const; + std::string getURI() const; + 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& getPayload() const; + const std::vector::const_iterator begin() const; + const std::vector::const_iterator end() const; /** * @brief A template to convert the service data to . @@ -63,21 +102,14 @@ class NimBLEAdvertisedDevice { * less than sizeof(). * @details Use: getManufacturerData(skipSizeCheck); */ - template - T getManufacturerData(bool skipSizeCheck = false) { + template + T getManufacturerData(bool skipSizeCheck = false) const { std::string data = getManufacturerData(); - if(!skipSizeCheck && data.size() < sizeof(T)) return T(); - const char *pData = data.data(); - return *((T *)pData); + if (!skipSizeCheck && data.size() < sizeof(T)) return T(); + const char* pData = data.data(); + 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 . * @tparam T The type to convert the data to. @@ -87,12 +119,12 @@ class NimBLEAdvertisedDevice { * less than sizeof(). * @details Use: getServiceData(skipSizeCheck); */ - template - T getServiceData(uint8_t index = 0, bool skipSizeCheck = false) { + template + T getServiceData(uint8_t index = 0, bool skipSizeCheck = false) const { std::string data = getServiceData(index); - if(!skipSizeCheck && data.size() < sizeof(T)) return T(); - const char *pData = data.data(); - return *((T *)pData); + if (!skipSizeCheck && data.size() < sizeof(T)) return T(); + const char* pData = data.data(); + return *((T*)pData); } /** @@ -104,80 +136,38 @@ class NimBLEAdvertisedDevice { * less than sizeof(). * @details Use: getServiceData(skipSizeCheck); */ - template - T getServiceData(const NimBLEUUID &uuid, bool skipSizeCheck = false) { + template + T getServiceData(const NimBLEUUID& uuid, bool skipSizeCheck = false) const { std::string data = getServiceData(uuid); - if(!skipSizeCheck && data.size() < sizeof(T)) return T(); - const char *pData = data.data(); - return *((T *)pData); + if (!skipSizeCheck && data.size() < sizeof(T)) return T(); + const char* pData = data.data(); + return *((T*)pData); } - NimBLEUUID getServiceDataUUID(uint8_t index = 0); - 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: + private: friend class NimBLEScan; - void setAddress(NimBLEAddress address); - void setAdvType(uint8_t advType, bool isLegacyAdv); - void setPayload(const uint8_t *payload, uint8_t length, bool append); - void setRSSI(int rssi); -#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; - uint8_t m_advType; - int m_rssi; - time_t m_timestamp; - uint8_t m_callbackSent; - uint8_t m_advLength; -#if CONFIG_BT_NIMBLE_EXT_ADV - bool m_isLegacyAdv; - uint8_t m_sid; - uint8_t m_primPhy; - uint8_t m_secPhy; - uint16_t m_periodicItvl; -#endif - - std::vector m_payload; + NimBLEAdvertisedDevice(const ble_gap_event* event, uint8_t eventType); + void update(const ble_gap_event* event, uint8_t eventType); + uint8_t findAdvField(uint8_t type, uint8_t index = 0, size_t* data_loc = nullptr) const; + size_t findServiceData(uint8_t index, uint8_t* bytes) const; + + NimBLEAddress m_address{}; + uint8_t m_advType{}; + int8_t m_rssi{}; + uint8_t m_callbackSent{}; + uint8_t m_advLength{}; + +# if CONFIG_BT_NIMBLE_EXT_ADV + bool m_isLegacyAdv{}; + uint8_t m_sid{}; + uint8_t m_primPhy{}; + uint8_t m_secPhy{}; + uint16_t m_periodicItvl{}; +# endif + + std::vector m_payload; }; #endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_OBSERVER */ -#endif /* COMPONENTS_NIMBLEADVERTISEDDEVICE_H_ */ +#endif /* NIMBLE_CPP_ADVERTISED_DEVICE_H_ */ diff --git a/src/NimBLEScan.cpp b/src/NimBLEScan.cpp index b4fe6a92..1590b7c6 100644 --- a/src/NimBLEScan.cpp +++ b/src/NimBLEScan.cpp @@ -111,29 +111,17 @@ int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) { return 0; } - advertisedDevice = new NimBLEAdvertisedDevice(); - 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 + advertisedDevice = new NimBLEAdvertisedDevice(event, event_type); pScan->m_scanResults.m_advertisedDevicesVector.push_back(advertisedDevice); NIMBLE_LOGI(LOG_TAG, "New advertiser: %s", advertisedAddress.toString().c_str()); } else if (advertisedDevice != nullptr) { + advertisedDevice->update(event, event_type); NIMBLE_LOGI(LOG_TAG, "Updated advertiser: %s", advertisedAddress.toString().c_str()); } else { // Scan response from unknown device 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 (advertisedDevice->m_callbackSent == 0 || !pScan->m_scan_params.filter_duplicates) { advertisedDevice->m_callbackSent = 1;