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)