From dff5122ce2b807f48ea34516d538af9e1939a38f Mon Sep 17 00:00:00 2001 From: h2zero Date: Sun, 7 Feb 2021 20:33:57 -0700 Subject: [PATCH] Add complementary methods to NimBLEAdvertising and NimBLEAdvertisementData Previous to this NimBLEAdvertising did not have some functionality that was in NimBLEAdvertisementData. Also NimBLEAdvertisementData was missing functionality that exists in NimBLEAdvertising. This resolves that by adding the missing functions to both classes. Changed: NimBLEAdvertising: Transmission power is no longer advertised by default and can be added to the advertisement by calling ::addTxPower() Added: - NimBLEAdvertising::setName - NimBLEAdvertising::setManufacturerData - NimBLEAdvertising::setURI - NimBLEAdvertising::setServiceData - NimBLEAdvertising::addTxPower - NimBLEAdvertising::reset - NimBLEAdvertisementData::addTxPower - NimBLEAdvertisementData::setPreferredParams - NimBLEAdvertisementData::setURI --- src/NimBLEAdvertising.cpp | 195 +++++++++++++++++++++++++++++++++----- src/NimBLEAdvertising.h | 15 +++ 2 files changed, 187 insertions(+), 23 deletions(-) diff --git a/src/NimBLEAdvertising.cpp b/src/NimBLEAdvertising.cpp index 64524dd..81ce79c 100644 --- a/src/NimBLEAdvertising.cpp +++ b/src/NimBLEAdvertising.cpp @@ -32,23 +32,27 @@ static const char* LOG_TAG = "NimBLEAdvertising"; /** * @brief Construct a default advertising object. */ -NimBLEAdvertising::NimBLEAdvertising() : m_slaveItvl() { +NimBLEAdvertising::NimBLEAdvertising() { + reset(); +} // NimBLEAdvertising + + +/** + * @brief Stops the current advertising and resets the advertising data to the default values. + */ +void NimBLEAdvertising::reset() { + stop(); memset(&m_advData, 0, sizeof m_advData); memset(&m_scanData, 0, sizeof m_scanData); memset(&m_advParams, 0, sizeof m_advParams); + memset(&m_slaveItvl, 0, sizeof m_slaveItvl); const char *name = ble_svc_gap_device_name(); m_advData.name = (uint8_t *)name; m_advData.name_len = strlen(name); m_advData.name_is_complete = 1; - m_advData.tx_pwr_lvl_is_present = 1; m_advData.tx_pwr_lvl = NimBLEDevice::getPower(); m_advData.flags = (BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP); - m_advData.appearance = 0; - m_advData.appearance_is_present = 0; - m_advData.mfg_data_len = 0; - m_advData.mfg_data = nullptr; - m_advData.slave_itvl_range = nullptr; #if !defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) m_advParams.conn_mode = BLE_GAP_CONN_MODE_NON; @@ -56,17 +60,13 @@ NimBLEAdvertising::NimBLEAdvertising() : m_slaveItvl() { m_advParams.conn_mode = BLE_GAP_CONN_MODE_UND; #endif m_advParams.disc_mode = BLE_GAP_DISC_MODE_GEN; - m_advParams.itvl_min = 0; - m_advParams.itvl_max = 0; - m_customAdvData = false; m_customScanResponseData = false; m_scanResp = true; m_advDataSet = false; // Set this to non-zero to prevent auto start if host reset before started by app. m_duration = BLE_HS_FOREVER; - -} // NimBLEAdvertising +} // reset /** @@ -85,6 +85,7 @@ void NimBLEAdvertising::addServiceUUID(const NimBLEUUID &serviceUUID) { */ void NimBLEAdvertising::addServiceUUID(const char* serviceUUID) { addServiceUUID(NimBLEUUID(serviceUUID)); + m_advDataSet = false; } // addServiceUUID @@ -112,9 +113,95 @@ void NimBLEAdvertising::removeServiceUUID(const NimBLEUUID &serviceUUID) { void NimBLEAdvertising::setAppearance(uint16_t appearance) { m_advData.appearance = appearance; m_advData.appearance_is_present = 1; + m_advDataSet = false; } // setAppearance +/** + * @brief Add the transmission power level to the advertisement packet. + */ +void NimBLEAdvertising::addTxPower() { + m_advData.tx_pwr_lvl_is_present = 1; + m_advDataSet = false; +} // addTxPower + + +/** + * @brief Set the advertised name of the device. + * @param [in] name The name to advertise. + */ +void NimBLEAdvertising::setName(const std::string &name) { + m_name.assign(name.begin(), name.end()); + m_advData.name = &m_name[0]; + m_advData.name_len = m_name.size(); + m_advDataSet = false; +} // setName + + +/** + * @brief Set the advertised manufacturer data. + * @param [in] name The data to advertise. + */ +void NimBLEAdvertising::setManufacturerData(const std::string &data) { + m_mfgData.assign(data.begin(), data.end()); + m_advData.mfg_data = &m_mfgData[0]; + m_advData.mfg_data_len = m_mfgData.size(); + m_advDataSet = false; +} // setManufacturerData + + +/** + * @brief Set the advertised URI. + * @param [in] name The URI to advertise. + */ +void NimBLEAdvertising::setURI(const std::string &uri) { + m_uri.assign(uri.begin(), uri.end()); + m_advData.uri = &m_uri[0]; + m_advData.uri_len = m_uri.size(); + m_advDataSet = false; +} // setURI + + +/** + * @brief Set the service data advertised for the UUID. + * @param [in] uuid The UUID the service data belongs to. + * @param [in] data The data to advertise. + * @note If data length is 0 the service data will not be advertised. + */ +void NimBLEAdvertising::setServiceData(const NimBLEUUID &uuid, const std::string &data) { + switch (uuid.bitSize()) { + case 16: { + m_svcData16.assign((uint8_t*)&uuid.getNative()->u16.value, (uint8_t*)&uuid.getNative()->u16.value + 2); + m_svcData16.insert(m_svcData16.end(), data.begin(), data.end()); + m_advData.svc_data_uuid16 = (uint8_t*)&m_svcData16[0]; + m_advData.svc_data_uuid16_len = (data.length() > 0) ? m_svcData16.size() : 0; + break; + } + + case 32: { + m_svcData32.assign((uint8_t*)&uuid.getNative()->u32.value, (uint8_t*)&uuid.getNative()->u32.value + 4); + m_svcData32.insert(m_svcData32.end(), data.begin(), data.end()); + m_advData.svc_data_uuid32 = (uint8_t*)&m_svcData32[0]; + m_advData.svc_data_uuid32_len = (data.length() > 0) ? m_svcData32.size() : 0; + break; + } + + case 128: { + m_svcData128.assign(uuid.getNative()->u128.value, uuid.getNative()->u128.value + 16); + m_svcData128.insert(m_svcData128.end(), data.begin(), data.end()); + m_advData.svc_data_uuid128 = (uint8_t*)&m_svcData128[0]; + m_advData.svc_data_uuid128_len = (data.length() > 0) ? m_svcData128.size() : 0; + break; + } + + default: + return; + } + + m_advDataSet = false; +} // setServiceData + + /** * @brief Set the type of advertisment to use. * @param [in] adv_type: @@ -172,6 +259,8 @@ void NimBLEAdvertising::setMinPreferred(uint16_t mininterval) { m_slaveItvl[2] = m_slaveItvl[0]; m_slaveItvl[3] = m_slaveItvl[1]; } + + m_advDataSet = false; } // setMinPreferred @@ -200,6 +289,8 @@ void NimBLEAdvertising::setMaxPreferred(uint16_t maxinterval) { m_slaveItvl[0] = m_slaveItvl[2]; m_slaveItvl[1] = m_slaveItvl[3]; } + + m_advDataSet = false; } // setMaxPreferred @@ -209,6 +300,7 @@ void NimBLEAdvertising::setMaxPreferred(uint16_t maxinterval) { */ void NimBLEAdvertising::setScanResponse(bool set) { m_scanResp = set; + m_advDataSet = false; } // setScanResponse @@ -344,12 +436,29 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv if (!m_customAdvData && !m_advDataSet) { //start with 3 bytes for the flags data uint8_t payloadLen = (2 + 1); + if(m_advData.mfg_data_len > 0) + payloadLen += (2 + m_advData.mfg_data_len); + + if(m_advData.svc_data_uuid16_len > 0) + payloadLen += (2 + m_advData.svc_data_uuid16_len); + + if(m_advData.svc_data_uuid32_len > 0) + payloadLen += (2 + m_advData.svc_data_uuid32_len); + + if(m_advData.svc_data_uuid128_len > 0) + payloadLen += (2 + m_advData.svc_data_uuid128_len); + + if(m_advData.uri_len > 0) + payloadLen += (2 + m_advData.uri_len); + if(m_advData.appearance_is_present) payloadLen += (2 + BLE_HS_ADV_APPEARANCE_LEN); + if(m_advData.tx_pwr_lvl_is_present) - payloadLen += (2 + 1); + payloadLen += (2 + BLE_HS_ADV_TX_PWR_LVL_LEN); + if(m_advData.slave_itvl_range != nullptr) - payloadLen += (2 + 4); + payloadLen += (2 + BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN); for(auto &it : m_serviceUUIDs) { if(it.getNative()->u.type == BLE_UUID_TYPE_16) { @@ -433,7 +542,6 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv m_advData.name_is_complete = 0; } else { if(m_advData.tx_pwr_lvl_is_present) { - m_advData.tx_pwr_lvl = 0; m_advData.tx_pwr_lvl_is_present = 0; payloadLen -= (2 + 1); } @@ -581,7 +689,7 @@ void NimBLEAdvertising::advCompleteCB() { if(m_advCompCB != nullptr) { m_advCompCB(this); } -} +} // advCompleteCB /** @@ -590,7 +698,7 @@ void NimBLEAdvertising::advCompleteCB() { */ bool NimBLEAdvertising::isAdvertising() { return ble_gap_adv_active(); -} +} // isAdvertising /* @@ -608,7 +716,7 @@ void NimBLEAdvertising::onHostSync() { // Otherwise we should tell the app that advertising stopped. advCompleteCB(); } -} +} // onHostSync /** @@ -706,6 +814,18 @@ void NimBLEAdvertisementData::setManufacturerData(const std::string &data) { } // setManufacturerData +/** + * @brief Set the URI to advertise. + * @param [in] uri The uri to advertise. + */ +void NimBLEAdvertisementData::setURI(const std::string &uri) { + char cdata[2]; + cdata[0] = uri.length() + 1; + cdata[1] = BLE_HS_ADV_TYPE_URI; + addData(std::string(cdata, 2) + uri); +} // setURI + + /** * @brief Set the complete name of this device. * @param [in] name The name to advertise. @@ -733,7 +853,7 @@ void NimBLEAdvertisementData::setCompleteServices(const NimBLEUUID &uuid) { */ void NimBLEAdvertisementData::setCompleteServices16(const std::vector& v_uuid) { setServices(true, 16, v_uuid); -} +} // setCompleteServices16 /** @@ -742,7 +862,7 @@ void NimBLEAdvertisementData::setCompleteServices16(const std::vector& v_uuid) { setServices(true, 32, v_uuid); -} +} // setCompleteServices32 /** @@ -760,7 +880,7 @@ void NimBLEAdvertisementData::setPartialServices(const NimBLEUUID &uuid) { */ void NimBLEAdvertisementData::setPartialServices16(const std::vector& v_uuid) { setServices(false, 16, v_uuid); -} +} // setPartialServices16 /** @@ -769,7 +889,7 @@ void NimBLEAdvertisementData::setPartialServices16(const std::vector */ void NimBLEAdvertisementData::setPartialServices32(const std::vector& v_uuid) { setServices(false, 32, v_uuid); -} +} // setPartialServices32 /** @@ -821,7 +941,7 @@ void NimBLEAdvertisementData::setServices(const bool complete, const uint8_t siz } addData(std::string(cdata, 2) + uuids); -} +} // setServices /** @@ -874,6 +994,35 @@ void NimBLEAdvertisementData::setShortName(const std::string &name) { } // setShortName +/** + * @brief Adds Tx power level to the advertisement data. + */ +void NimBLEAdvertisementData::addTxPower() { + char cdata[3]; + cdata[0] = BLE_HS_ADV_TX_PWR_LVL_LEN + 1; + cdata[1] = BLE_HS_ADV_TYPE_TX_PWR_LVL; + cdata[2] = NimBLEDevice::getPower(); + addData(cdata, 3); +} // addTxPower + + +/** + * @brief Set the preferred connection interval parameters. + * @param [in] min The minimum interval desired. + * @param [in] max The maximum interval desired. + */ +void NimBLEAdvertisementData::setPreferredParams(uint16_t min, uint16_t max) { + char cdata[6]; + cdata[0] = BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1; + cdata[1] = BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE; + cdata[2] = min; + cdata[3] = min >> 8; + cdata[4] = max; + cdata[5] = max >> 8; + addData(cdata, 6); +} // setPreferredParams + + /** * @brief Retrieve the payload that is to be advertised. * @return The payload that is to be advertised. diff --git a/src/NimBLEAdvertising.h b/src/NimBLEAdvertising.h index 82b096f..17a8665 100644 --- a/src/NimBLEAdvertising.h +++ b/src/NimBLEAdvertising.h @@ -54,6 +54,7 @@ public: void setCompleteServices32(const std::vector &v_uuid); void setFlags(uint8_t); void setManufacturerData(const std::string &data); + void setURI(const std::string &uri); void setName(const std::string &name); void setPartialServices(const NimBLEUUID &uuid); void setPartialServices16(const std::vector &v_uuid); @@ -62,6 +63,8 @@ public: void setShortName(const std::string &name); void addData(const std::string &data); // Add data to the payload. void addData(char * data, size_t length); + void addTxPower(); + void setPreferredParams(uint16_t min, uint16_t max); std::string getPayload(); // Retrieve the current advert payload. private: @@ -86,6 +89,10 @@ public: bool start(uint32_t duration = 0, void (*advCompleteCB)(NimBLEAdvertising *pAdv) = nullptr); void stop(); void setAppearance(uint16_t appearance); + void setName(const std::string &name); + void setManufacturerData(const std::string &data); + void setURI(const std::string &uri); + void setServiceData(const NimBLEUUID &uuid, const std::string &data); void setAdvertisementType(uint8_t adv_type); void setMaxInterval(uint16_t maxinterval); void setMinInterval(uint16_t mininterval); @@ -95,6 +102,8 @@ public: void setScanResponse(bool); void setMinPreferred(uint16_t); void setMaxPreferred(uint16_t); + void addTxPower(); + void reset(); void advCompleteCB(); bool isAdvertising(); @@ -115,6 +124,12 @@ private: void (*m_advCompCB)(NimBLEAdvertising *pAdv); uint8_t m_slaveItvl[4]; uint32_t m_duration; + std::vector m_svcData16; + std::vector m_svcData32; + std::vector m_svcData128; + std::vector m_name; + std::vector m_mfgData; + std::vector m_uri; }; #endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)