2020-03-30 01:44:20 +02:00
|
|
|
/*
|
|
|
|
* NimBLEAdvertising.cpp
|
|
|
|
*
|
|
|
|
* Created: on March 3, 2020
|
|
|
|
* Author H2zero
|
2020-05-14 06:03:56 +02:00
|
|
|
*
|
2020-03-30 01:44:20 +02:00
|
|
|
* Originally:
|
|
|
|
*
|
|
|
|
* BLEAdvertising.cpp
|
|
|
|
*
|
|
|
|
* This class encapsulates advertising a BLE Server.
|
|
|
|
* Created on: Jun 21, 2017
|
|
|
|
* Author: kolban
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#include "sdkconfig.h"
|
|
|
|
#if defined(CONFIG_BT_ENABLED)
|
2020-05-14 06:03:56 +02:00
|
|
|
|
|
|
|
#include "nimconfig.h"
|
|
|
|
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
#include "services/gap/ble_svc_gap.h"
|
|
|
|
#include "NimBLEAdvertising.h"
|
|
|
|
#include "NimBLEDevice.h"
|
|
|
|
#include "NimBLEServer.h"
|
|
|
|
#include "NimBLEUtils.h"
|
|
|
|
#include "NimBLELog.h"
|
|
|
|
|
|
|
|
static const char* LOG_TAG = "NimBLEAdvertising";
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Construct a default advertising object.
|
|
|
|
*/
|
|
|
|
NimBLEAdvertising::NimBLEAdvertising() {
|
|
|
|
memset(&m_advData, 0, sizeof m_advData);
|
2020-05-14 06:03:56 +02:00
|
|
|
memset(&m_scanData, 0, sizeof m_scanData);
|
|
|
|
memset(&m_advParams, 0, sizeof m_advParams);
|
2020-03-30 01:44:20 +02:00
|
|
|
const char *name = ble_svc_gap_device_name();
|
2020-04-14 03:13:51 +02:00
|
|
|
|
2020-05-14 06:03:56 +02:00
|
|
|
m_advData.name = (uint8_t *)name;
|
2020-03-30 01:44:20 +02:00
|
|
|
m_advData.name_len = strlen(name);
|
|
|
|
m_advData.name_is_complete = 1;
|
|
|
|
m_scanData.tx_pwr_lvl_is_present = 1;
|
2020-04-14 03:13:51 +02:00
|
|
|
m_scanData.tx_pwr_lvl = NimBLEDevice::getPower();
|
2020-03-30 01:44:20 +02:00
|
|
|
m_advData.flags = (BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP);
|
2020-05-14 06:03:56 +02:00
|
|
|
m_advData.appearance = 0;
|
|
|
|
m_advData.appearance_is_present = 0;
|
|
|
|
m_advData.mfg_data_len = 0;
|
|
|
|
m_advData.mfg_data = nullptr;
|
|
|
|
|
|
|
|
m_advParams.conn_mode = BLE_GAP_CONN_MODE_UND;
|
2020-03-30 01:44:20 +02:00
|
|
|
m_advParams.disc_mode = BLE_GAP_DISC_MODE_GEN;
|
2020-05-14 06:03:56 +02:00
|
|
|
m_advParams.itvl_min = 0;
|
|
|
|
m_advParams.itvl_max = 0;
|
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
} // NimBLEAdvertising
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Add a service uuid to exposed list of services.
|
|
|
|
* @param [in] serviceUUID The UUID of the service to expose.
|
|
|
|
*/
|
2020-05-10 15:21:46 +02:00
|
|
|
void NimBLEAdvertising::addServiceUUID(const NimBLEUUID &serviceUUID) {
|
2020-05-14 06:03:56 +02:00
|
|
|
m_serviceUUIDs.push_back(serviceUUID);
|
2020-07-14 05:24:07 +02:00
|
|
|
m_advDataSet = false;
|
2020-03-30 01:44:20 +02:00
|
|
|
} // addServiceUUID
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Add a service uuid to exposed list of services.
|
|
|
|
* @param [in] serviceUUID The string representation of the service to expose.
|
|
|
|
*/
|
|
|
|
void NimBLEAdvertising::addServiceUUID(const char* serviceUUID) {
|
2020-05-14 06:03:56 +02:00
|
|
|
addServiceUUID(NimBLEUUID(serviceUUID));
|
2020-03-30 01:44:20 +02:00
|
|
|
} // addServiceUUID
|
|
|
|
|
|
|
|
|
2020-07-14 05:24:07 +02:00
|
|
|
/**
|
|
|
|
* @brief Add a service uuid to exposed list of services.
|
|
|
|
* @param [in] serviceUUID The UUID of the service to expose.
|
|
|
|
*/
|
|
|
|
void NimBLEAdvertising::removeServiceUUID(const NimBLEUUID &serviceUUID) {
|
|
|
|
//m_serviceUUIDs.erase(std::remove_if(m_serviceUUIDs.begin(), m_serviceUUIDs.end(),[serviceUUID](const NimBLEUUID &s) {return serviceUUID == s;}), m_serviceUUIDs.end());
|
|
|
|
for(auto it = m_serviceUUIDs.begin(); it != m_serviceUUIDs.end(); ++it) {
|
|
|
|
if((*it) == serviceUUID) {
|
|
|
|
m_serviceUUIDs.erase(it);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_advDataSet = false;
|
|
|
|
} // addServiceUUID
|
|
|
|
|
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
/**
|
|
|
|
* @brief Set the device appearance in the advertising data.
|
2020-07-09 03:27:26 +02:00
|
|
|
* The codes for distinct appearances can be found here:\n
|
2020-03-30 01:44:20 +02:00
|
|
|
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml.
|
|
|
|
* @param [in] appearance The appearance of the device in the advertising data.
|
|
|
|
*/
|
|
|
|
void NimBLEAdvertising::setAppearance(uint16_t appearance) {
|
2020-05-14 06:03:56 +02:00
|
|
|
m_advData.appearance = appearance;
|
|
|
|
m_advData.appearance_is_present = 1;
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setAppearance
|
|
|
|
|
2020-07-09 03:27:26 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the type of advertisment to use.
|
|
|
|
* @param [in] adv_type:
|
|
|
|
* * BLE_HCI_ADV_TYPE_ADV_IND (0) - indirect advertising
|
|
|
|
* * BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD (1) - direct advertisng - high duty cycle
|
|
|
|
* * BLE_HCI_ADV_TYPE_ADV_SCAN_IND (2) - indirect scan response
|
|
|
|
* * BLE_HCI_ADV_TYPE_ADV_NONCONN_IND (3) - indirect advertisng - not connectable
|
|
|
|
* * BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD (4) - direct advertising - low duty cycle
|
|
|
|
*/
|
2020-03-30 01:44:20 +02:00
|
|
|
void NimBLEAdvertising::setAdvertisementType(uint8_t adv_type){
|
2020-05-14 06:03:56 +02:00
|
|
|
m_advParams.conn_mode = adv_type;
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setAdvertisementType
|
|
|
|
|
2020-07-09 03:27:26 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the minimum advertising interval.
|
|
|
|
* @param [in] mininterval Minimum value for advertising interval in 0.625ms units, 0 = use default.
|
|
|
|
*/
|
2020-03-30 01:44:20 +02:00
|
|
|
void NimBLEAdvertising::setMinInterval(uint16_t mininterval) {
|
2020-05-14 06:03:56 +02:00
|
|
|
m_advParams.itvl_min = mininterval;
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setMinInterval
|
|
|
|
|
2020-07-09 03:27:26 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the maximum advertising interval.
|
|
|
|
* @param [in] maxinterval Maximum value for advertising interval in 0.625ms units, 0 = use default.
|
|
|
|
*/
|
2020-03-30 01:44:20 +02:00
|
|
|
void NimBLEAdvertising::setMaxInterval(uint16_t maxinterval) {
|
2020-05-14 06:03:56 +02:00
|
|
|
m_advParams.itvl_max = maxinterval;
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setMaxInterval
|
|
|
|
|
2020-06-08 02:42:28 +02:00
|
|
|
|
2020-07-09 03:27:26 +02:00
|
|
|
/**
|
|
|
|
* @brief Set if scan response is available.
|
|
|
|
* @param [in] set true = scan response available.
|
|
|
|
*/
|
2020-03-30 01:44:20 +02:00
|
|
|
void NimBLEAdvertising::setScanResponse(bool set) {
|
2020-05-14 06:03:56 +02:00
|
|
|
m_scanResp = set;
|
2020-07-09 03:27:26 +02:00
|
|
|
} // setScanResponse
|
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the filtering for the scan filter.
|
|
|
|
* @param [in] scanRequestWhitelistOnly If true, only allow scan requests from those on the white list.
|
|
|
|
* @param [in] connectWhitelistOnly If true, only allow connections from those on the white list.
|
|
|
|
*/
|
|
|
|
void NimBLEAdvertising::setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly) {
|
2020-05-14 06:03:56 +02:00
|
|
|
NIMBLE_LOGD(LOG_TAG, ">> setScanFilter: scanRequestWhitelistOnly: %d, connectWhitelistOnly: %d", scanRequestWhitelistOnly, connectWhitelistOnly);
|
|
|
|
if (!scanRequestWhitelistOnly && !connectWhitelistOnly) {
|
|
|
|
m_advParams.filter_policy = BLE_HCI_ADV_FILT_NONE;
|
|
|
|
NIMBLE_LOGD(LOG_TAG, "<< setScanFilter");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (scanRequestWhitelistOnly && !connectWhitelistOnly) {
|
|
|
|
m_advParams.filter_policy = BLE_HCI_ADV_FILT_SCAN;
|
|
|
|
NIMBLE_LOGD(LOG_TAG, "<< setScanFilter");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!scanRequestWhitelistOnly && connectWhitelistOnly) {
|
|
|
|
m_advParams.filter_policy = BLE_HCI_ADV_FILT_CONN;
|
|
|
|
NIMBLE_LOGD(LOG_TAG, "<< setScanFilter");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (scanRequestWhitelistOnly && connectWhitelistOnly) {
|
|
|
|
m_advParams.filter_policy = BLE_HCI_ADV_FILT_BOTH;
|
|
|
|
NIMBLE_LOGD(LOG_TAG, "<< setScanFilter");
|
|
|
|
return;
|
|
|
|
}
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setScanFilter
|
|
|
|
|
2020-07-09 03:27:26 +02:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
/**
|
|
|
|
* @brief Set the advertisement data that is to be published in a regular advertisement.
|
|
|
|
* @param [in] advertisementData The data to be advertised.
|
|
|
|
*/
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
void NimBLEAdvertising::setAdvertisementData(NimBLEAdvertisementData& advertisementData) {
|
2020-05-14 06:03:56 +02:00
|
|
|
NIMBLE_LOGD(LOG_TAG, ">> setAdvertisementData");
|
|
|
|
int rc = ble_gap_adv_set_data(
|
|
|
|
(uint8_t*)advertisementData.getPayload().data(),
|
|
|
|
advertisementData.getPayload().length());
|
|
|
|
if (rc != 0) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "ble_gap_adv_set_data: %d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
|
|
}
|
|
|
|
m_customAdvData = true; // Set the flag that indicates we are using custom advertising data.
|
|
|
|
NIMBLE_LOGD(LOG_TAG, "<< setAdvertisementData");
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setAdvertisementData
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the advertisement data that is to be published in a scan response.
|
|
|
|
* @param [in] advertisementData The data to be advertised.
|
|
|
|
*/
|
|
|
|
void NimBLEAdvertising::setScanResponseData(NimBLEAdvertisementData& advertisementData) {
|
2020-05-14 06:03:56 +02:00
|
|
|
NIMBLE_LOGD(LOG_TAG, ">> setScanResponseData");
|
|
|
|
int rc = ble_gap_adv_rsp_set_data(
|
|
|
|
(uint8_t*)advertisementData.getPayload().data(),
|
|
|
|
advertisementData.getPayload().length());
|
|
|
|
if (rc != 0) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "ble_gap_adv_rsp_set_data: %d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
|
|
}
|
|
|
|
m_customScanResponseData = true; // Set the flag that indicates we are using custom scan response data.
|
|
|
|
NIMBLE_LOGD(LOG_TAG, "<< setScanResponseData");
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setScanResponseData
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Start advertising.
|
|
|
|
*/
|
|
|
|
void NimBLEAdvertising::start() {
|
2020-05-14 06:03:56 +02:00
|
|
|
NIMBLE_LOGD(LOG_TAG, ">> Advertising start: customAdvData: %d, customScanResponseData: %d", m_customAdvData, m_customScanResponseData);
|
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
// If Host is not synced we cannot start advertising.
|
|
|
|
if(!NimBLEDevice::m_synced) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Host reset, wait for sync.");
|
|
|
|
return;
|
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
|
|
|
|
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
2020-05-14 20:59:35 +02:00
|
|
|
NimBLEServer* pServer = NimBLEDevice::getServer();
|
|
|
|
if(pServer != nullptr) {
|
|
|
|
if(!pServer->m_gattsStarted){
|
|
|
|
pServer->start();
|
|
|
|
} else if(pServer->getConnectedCount() >= NIMBLE_MAX_CONNECTIONS) {
|
|
|
|
NIMBLE_LOGW(LOG_TAG, "Max connections reached - not advertising");
|
|
|
|
return;
|
|
|
|
}
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
#endif
|
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
// If already advertising just return
|
|
|
|
if(ble_gap_adv_active()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2020-06-08 02:42:28 +02:00
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
if (!m_customAdvData && !m_advDataSet) {
|
|
|
|
//start with 3 bytes for the flags data
|
|
|
|
uint8_t payloadLen = 3;
|
|
|
|
|
|
|
|
for(auto &it : m_serviceUUIDs) {
|
|
|
|
if(it.getNative()->u.type == BLE_UUID_TYPE_16) {
|
2020-05-14 06:03:56 +02:00
|
|
|
int add = (m_advData.num_uuids16 > 0) ? 2 : 4;
|
|
|
|
if((payloadLen + add) > 31){
|
|
|
|
m_advData.uuids16_is_complete = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
payloadLen += add;
|
|
|
|
|
|
|
|
if(nullptr == (m_advData.uuids16 = (ble_uuid16_t*)realloc(m_advData.uuids16,
|
2020-06-08 02:42:28 +02:00
|
|
|
(m_advData.num_uuids16 + 1) * sizeof(ble_uuid16_t))))
|
2020-03-30 01:44:20 +02:00
|
|
|
{
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Error, no mem");
|
|
|
|
abort();
|
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
memcpy(&m_advData.uuids16[m_advData.num_uuids16].value,
|
2020-06-08 02:42:28 +02:00
|
|
|
&it.getNative()->u16.value, 2);
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
m_advData.uuids16[m_advData.num_uuids16].u.type = BLE_UUID_TYPE_16;
|
|
|
|
m_advData.uuids16_is_complete = 1;
|
|
|
|
m_advData.num_uuids16++;
|
2020-05-14 06:03:56 +02:00
|
|
|
}
|
2020-06-08 02:42:28 +02:00
|
|
|
if(it.getNative()->u.type == BLE_UUID_TYPE_32) {
|
2020-05-14 06:03:56 +02:00
|
|
|
int add = (m_advData.num_uuids32 > 0) ? 4 : 6;
|
|
|
|
if((payloadLen + add) > 31){
|
|
|
|
m_advData.uuids32_is_complete = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
payloadLen += add;
|
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
if(nullptr == (m_advData.uuids32 = (ble_uuid32_t*)realloc(m_advData.uuids32,
|
2020-06-08 02:42:28 +02:00
|
|
|
(m_advData.num_uuids32 + 1) * sizeof(ble_uuid32_t))))
|
2020-03-30 01:44:20 +02:00
|
|
|
{
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Error, no mem");
|
|
|
|
abort();
|
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
memcpy(&m_advData.uuids32[m_advData.num_uuids32].value,
|
2020-06-08 02:42:28 +02:00
|
|
|
&it.getNative()->u32.value, 4);
|
2020-05-14 06:03:56 +02:00
|
|
|
|
|
|
|
m_advData.uuids32[m_advData.num_uuids32].u.type = BLE_UUID_TYPE_32;
|
2020-03-30 01:44:20 +02:00
|
|
|
m_advData.uuids32_is_complete = 1;
|
|
|
|
m_advData.num_uuids32++;
|
2020-05-14 06:03:56 +02:00
|
|
|
}
|
2020-06-08 02:42:28 +02:00
|
|
|
if(it.getNative()->u.type == BLE_UUID_TYPE_128){
|
2020-05-14 06:03:56 +02:00
|
|
|
int add = (m_advData.num_uuids128 > 0) ? 16 : 18;
|
|
|
|
if((payloadLen + add) > 31){
|
|
|
|
m_advData.uuids128_is_complete = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
payloadLen += add;
|
|
|
|
|
|
|
|
if(nullptr == (m_advData.uuids128 = (ble_uuid128_t*)realloc(m_advData.uuids128,
|
2020-06-08 02:42:28 +02:00
|
|
|
(m_advData.num_uuids128 + 1) * sizeof(ble_uuid128_t))))
|
|
|
|
{
|
2020-03-30 01:44:20 +02:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "Error, no mem");
|
|
|
|
abort();
|
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
memcpy(&m_advData.uuids128[m_advData.num_uuids128].value,
|
2020-06-08 02:42:28 +02:00
|
|
|
&it.getNative()->u128.value, 16);
|
2020-05-14 06:03:56 +02:00
|
|
|
|
|
|
|
m_advData.uuids128[m_advData.num_uuids128].u.type = BLE_UUID_TYPE_128;
|
2020-03-30 01:44:20 +02:00
|
|
|
m_advData.uuids128_is_complete = 1;
|
|
|
|
m_advData.num_uuids128++;
|
2020-05-14 06:03:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if there is room for the name, if not put it in scan data
|
|
|
|
if((payloadLen + m_advData.name_len) > 29) {
|
|
|
|
if(m_scanResp){
|
|
|
|
m_scanData.name = m_advData.name;
|
|
|
|
m_scanData.name_len = m_advData.name_len;
|
|
|
|
m_scanData.name_is_complete = m_advData.name_is_complete;
|
|
|
|
m_advData.name = nullptr;
|
|
|
|
m_advData.name_len = 0;
|
|
|
|
} else {
|
|
|
|
// if not using scan response just cut the name down
|
|
|
|
// leaving 2 bytes for the data specifier.
|
|
|
|
m_advData.name_len = (29 - payloadLen);
|
|
|
|
}
|
|
|
|
m_advData.name_is_complete = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m_advData.name_len > 0) {
|
|
|
|
payloadLen += (m_advData.name_len + 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m_scanResp) {
|
|
|
|
// name length + type byte + length byte + tx power type + length + data
|
|
|
|
if((m_scanData.name_len + 5) > 31) {
|
|
|
|
// prioritize name data over tx power
|
|
|
|
m_scanData.tx_pwr_lvl_is_present = 0;
|
|
|
|
m_scanData.tx_pwr_lvl = 0;
|
|
|
|
// limit name to 29 to leave room for the data specifiers
|
|
|
|
if(m_scanData.name_len > 29) {
|
|
|
|
m_scanData.name_len = 29;
|
|
|
|
m_scanData.name_is_complete = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = ble_gap_adv_rsp_set_fields(&m_scanData);
|
|
|
|
if (rc != 0) {
|
2020-06-08 02:42:28 +02:00
|
|
|
NIMBLE_LOGC(LOG_TAG, "error setting scan response data; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
2020-05-14 06:03:56 +02:00
|
|
|
abort();
|
|
|
|
}
|
|
|
|
// if not using scan response and there is room,
|
2020-06-08 02:42:28 +02:00
|
|
|
// put the tx power data into the advertisment
|
2020-03-30 01:44:20 +02:00
|
|
|
} else if (payloadLen < 29) {
|
2020-05-14 06:03:56 +02:00
|
|
|
m_advData.tx_pwr_lvl_is_present = 1;
|
|
|
|
m_advData.tx_pwr_lvl = NimBLEDevice::getPower();
|
|
|
|
}
|
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
rc = ble_gap_adv_set_fields(&m_advData);
|
|
|
|
if (rc != 0) {
|
2020-06-08 02:42:28 +02:00
|
|
|
NIMBLE_LOGC(LOG_TAG, "error setting advertisement data; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
2020-03-30 01:44:20 +02:00
|
|
|
abort();
|
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
if(m_advData.num_uuids128 > 0) {
|
|
|
|
free(m_advData.uuids128);
|
|
|
|
m_advData.uuids128 = nullptr;
|
|
|
|
m_advData.num_uuids128 = 0;
|
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
if(m_advData.num_uuids32 > 0) {
|
|
|
|
free(m_advData.uuids32);
|
|
|
|
m_advData.uuids32 = nullptr;
|
|
|
|
m_advData.num_uuids32 = 0;
|
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
if(m_advData.num_uuids16 > 0) {
|
|
|
|
free(m_advData.uuids16);
|
|
|
|
m_advData.uuids16 = nullptr;
|
|
|
|
m_advData.num_uuids16 = 0;
|
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2020-06-08 02:42:28 +02:00
|
|
|
m_advDataSet = true;
|
2020-05-14 06:03:56 +02:00
|
|
|
}
|
2020-03-30 01:44:20 +02:00
|
|
|
|
2020-05-14 06:03:56 +02:00
|
|
|
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
2020-06-08 02:42:28 +02:00
|
|
|
rc = ble_gap_adv_start(0, NULL, BLE_HS_FOREVER,
|
2020-05-14 20:59:35 +02:00
|
|
|
&m_advParams,
|
|
|
|
(pServer != nullptr) ? NimBLEServer::handleGapEvent : NULL,
|
|
|
|
pServer);
|
2020-05-14 06:03:56 +02:00
|
|
|
#else
|
2020-06-08 02:42:28 +02:00
|
|
|
rc = ble_gap_adv_start(0, NULL, BLE_HS_FOREVER,
|
2020-05-14 20:59:35 +02:00
|
|
|
&m_advParams, NULL,NULL);
|
2020-05-14 06:03:56 +02:00
|
|
|
#endif
|
2020-03-30 01:44:20 +02:00
|
|
|
if (rc != 0) {
|
|
|
|
NIMBLE_LOGC(LOG_TAG, "Error enabling advertising; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
|
|
abort();
|
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
|
|
|
|
NIMBLE_LOGD(LOG_TAG, "<< Advertising start");
|
2020-03-30 01:44:20 +02:00
|
|
|
} // start
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Stop advertising.
|
|
|
|
*/
|
|
|
|
void NimBLEAdvertising::stop() {
|
2020-05-14 06:03:56 +02:00
|
|
|
NIMBLE_LOGD(LOG_TAG, ">> stop");
|
|
|
|
int rc = ble_gap_adv_stop();
|
|
|
|
if (rc != 0 && rc != BLE_HS_EALREADY) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "ble_gap_adv_stop rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
NIMBLE_LOGD(LOG_TAG, "<< stop");
|
2020-03-30 01:44:20 +02:00
|
|
|
} // stop
|
|
|
|
|
2020-04-14 03:13:51 +02:00
|
|
|
|
2020-07-09 03:27:26 +02:00
|
|
|
/*
|
2020-05-14 06:03:56 +02:00
|
|
|
* Host reset seems to clear advertising data,
|
2020-04-14 03:13:51 +02:00
|
|
|
* we need clear the flag so it reloads it.
|
2020-05-14 06:03:56 +02:00
|
|
|
*/
|
2020-03-30 01:44:20 +02:00
|
|
|
void NimBLEAdvertising::onHostReset() {
|
2020-06-08 02:42:28 +02:00
|
|
|
m_advDataSet = false;
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Add data to the payload to be advertised.
|
|
|
|
* @param [in] data The data to be added to the payload.
|
|
|
|
*/
|
2020-05-10 15:21:46 +02:00
|
|
|
void NimBLEAdvertisementData::addData(const std::string &data) {
|
2020-05-14 06:03:56 +02:00
|
|
|
if ((m_payload.length() + data.length()) > BLE_HS_ADV_MAX_SZ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_payload.append(data);
|
2020-03-30 01:44:20 +02:00
|
|
|
} // addData
|
|
|
|
|
|
|
|
|
2020-07-28 05:38:22 +02:00
|
|
|
/**
|
|
|
|
* @brief Add data to the payload to be advertised.
|
|
|
|
* @param [in] data The data to be added to the payload.
|
|
|
|
* @param [in] length The size of data to be added to the payload.
|
|
|
|
*/
|
|
|
|
void NimBLEAdvertisementData::addData(char * data, size_t length){
|
|
|
|
if ((m_payload.length() + length) > BLE_HS_ADV_MAX_SZ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_payload.append(data,length);
|
|
|
|
} // addData
|
|
|
|
|
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
/**
|
|
|
|
* @brief Set the appearance.
|
|
|
|
* @param [in] appearance The appearance code value.
|
|
|
|
*
|
|
|
|
* See also:
|
|
|
|
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml
|
|
|
|
*/
|
|
|
|
void NimBLEAdvertisementData::setAppearance(uint16_t appearance) {
|
2020-05-14 06:03:56 +02:00
|
|
|
char cdata[2];
|
|
|
|
cdata[0] = 3;
|
|
|
|
cdata[1] = BLE_HS_ADV_TYPE_APPEARANCE; // 0x19
|
|
|
|
addData(std::string(cdata, 2) + std::string((char*) &appearance, 2));
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setAppearance
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2020-07-09 03:27:26 +02:00
|
|
|
* @brief Set the complete services to advertise.
|
|
|
|
* @param [in] uuid The UUID of the service.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2020-05-10 15:21:46 +02:00
|
|
|
void NimBLEAdvertisementData::setCompleteServices(const NimBLEUUID &uuid) {
|
2020-05-14 06:03:56 +02:00
|
|
|
char cdata[2];
|
|
|
|
switch (uuid.bitSize()) {
|
|
|
|
case 16: {
|
|
|
|
// [Len] [0x02] [LL] [HH]
|
|
|
|
cdata[0] = 3;
|
|
|
|
cdata[1] = BLE_HS_ADV_TYPE_COMP_UUIDS16; // 0x03
|
|
|
|
addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u16.value, 2));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 32: {
|
|
|
|
// [Len] [0x04] [LL] [LL] [HH] [HH]
|
|
|
|
cdata[0] = 5;
|
|
|
|
cdata[1] = BLE_HS_ADV_TYPE_COMP_UUIDS32; // 0x05
|
|
|
|
addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u32.value, 4));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 128: {
|
|
|
|
// [Len] [0x04] [0] [1] ... [15]
|
|
|
|
cdata[0] = 17;
|
|
|
|
cdata[1] = BLE_HS_ADV_TYPE_COMP_UUIDS128; // 0x07
|
|
|
|
addData(std::string(cdata, 2) + std::string((char*) uuid.getNative()->u128.value, 16));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setCompleteServices
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the advertisement flags.
|
2020-07-09 03:27:26 +02:00
|
|
|
* @param [in] flag The flags to be set in the advertisement.
|
2020-03-30 01:44:20 +02:00
|
|
|
* * BLE_HS_ADV_F_DISC_LTD
|
|
|
|
* * BLE_HS_ADV_F_DISC_GEN
|
|
|
|
* * BLE_HS_ADV_F_BREDR_UNSUP - must always use with NimBLE
|
|
|
|
*/
|
|
|
|
void NimBLEAdvertisementData::setFlags(uint8_t flag) {
|
2020-05-14 06:03:56 +02:00
|
|
|
char cdata[3];
|
|
|
|
cdata[0] = 2;
|
|
|
|
cdata[1] = BLE_HS_ADV_TYPE_FLAGS; // 0x01
|
|
|
|
cdata[2] = flag | BLE_HS_ADV_F_BREDR_UNSUP;
|
|
|
|
addData(std::string(cdata, 3));
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setFlag
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set manufacturer specific data.
|
2020-07-09 03:27:26 +02:00
|
|
|
* @param [in] data The manufacturer data to advertise.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2020-05-10 15:21:46 +02:00
|
|
|
void NimBLEAdvertisementData::setManufacturerData(const std::string &data) {
|
2020-05-14 06:03:56 +02:00
|
|
|
NIMBLE_LOGD("NimBLEAdvertisementData", ">> setManufacturerData");
|
|
|
|
char cdata[2];
|
|
|
|
cdata[0] = data.length() + 1;
|
|
|
|
cdata[1] = BLE_HS_ADV_TYPE_MFG_DATA ; // 0xff
|
|
|
|
addData(std::string(cdata, 2) + data);
|
|
|
|
NIMBLE_LOGD("NimBLEAdvertisementData", "<< setManufacturerData");
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setManufacturerData
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2020-07-09 03:27:26 +02:00
|
|
|
* @brief Set the complete name of this device.
|
|
|
|
* @param [in] name The name to advertise.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2020-05-10 15:21:46 +02:00
|
|
|
void NimBLEAdvertisementData::setName(const std::string &name) {
|
2020-05-14 06:03:56 +02:00
|
|
|
NIMBLE_LOGD("NimBLEAdvertisementData", ">> setName: %s", name.c_str());
|
|
|
|
char cdata[2];
|
|
|
|
cdata[0] = name.length() + 1;
|
|
|
|
cdata[1] = BLE_HS_ADV_TYPE_COMP_NAME; // 0x09
|
|
|
|
addData(std::string(cdata, 2) + name);
|
|
|
|
NIMBLE_LOGD("NimBLEAdvertisementData", "<< setName");
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setName
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2020-07-09 03:27:26 +02:00
|
|
|
* @brief Set the partial services to advertise.
|
2020-03-30 01:44:20 +02:00
|
|
|
* @param [in] uuid The single service to advertise.
|
|
|
|
*/
|
2020-05-10 15:21:46 +02:00
|
|
|
void NimBLEAdvertisementData::setPartialServices(const NimBLEUUID &uuid) {
|
2020-05-14 06:03:56 +02:00
|
|
|
char cdata[2];
|
|
|
|
switch (uuid.bitSize()) {
|
|
|
|
case 16: {
|
|
|
|
// [Len] [0x02] [LL] [HH]
|
|
|
|
cdata[0] = 3;
|
|
|
|
cdata[1] = BLE_HS_ADV_TYPE_INCOMP_UUIDS16; // 0x02
|
|
|
|
addData(std::string(cdata, 2) + std::string((char *) &uuid.getNative()->u16.value, 2));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 32: {
|
|
|
|
// [Len] [0x04] [LL] [LL] [HH] [HH]
|
|
|
|
cdata[0] = 5;
|
|
|
|
cdata[1] = BLE_HS_ADV_TYPE_INCOMP_UUIDS32; // 0x04
|
|
|
|
addData(std::string(cdata, 2) + std::string((char *) &uuid.getNative()->u32.value, 4));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 128: {
|
|
|
|
// [Len] [0x04] [0] [1] ... [15]
|
|
|
|
cdata[0] = 17;
|
|
|
|
cdata[1] = BLE_HS_ADV_TYPE_INCOMP_UUIDS128; // 0x06
|
|
|
|
addData(std::string(cdata, 2) + std::string((char *) &uuid.getNative()->u128.value, 16));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setPartialServices
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the service data (UUID + data)
|
2020-07-09 03:27:26 +02:00
|
|
|
* @param [in] uuid The UUID to set with the service data.
|
|
|
|
* @param [in] data The data to be associated with the service data advertised.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2020-05-10 15:21:46 +02:00
|
|
|
void NimBLEAdvertisementData::setServiceData(const NimBLEUUID &uuid, const std::string &data) {
|
2020-05-14 06:03:56 +02:00
|
|
|
char cdata[2];
|
|
|
|
switch (uuid.bitSize()) {
|
|
|
|
case 16: {
|
|
|
|
// [Len] [0x16] [UUID16] data
|
|
|
|
cdata[0] = data.length() + 3;
|
|
|
|
cdata[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID16; // 0x16
|
|
|
|
addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u16.value, 2) + data);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 32: {
|
|
|
|
// [Len] [0x20] [UUID32] data
|
|
|
|
cdata[0] = data.length() + 5;
|
|
|
|
cdata[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID32; // 0x20
|
|
|
|
addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u32.value, 4) + data);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 128: {
|
|
|
|
// [Len] [0x21] [UUID128] data
|
|
|
|
cdata[0] = data.length() + 17;
|
|
|
|
cdata[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID128; // 0x21
|
|
|
|
addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u128.value, 16) + data);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setServiceData
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the short name.
|
2020-07-09 03:27:26 +02:00
|
|
|
* @param [in] name The short name of the device.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2020-05-10 15:21:46 +02:00
|
|
|
void NimBLEAdvertisementData::setShortName(const std::string &name) {
|
2020-05-14 06:03:56 +02:00
|
|
|
NIMBLE_LOGD("NimBLEAdvertisementData", ">> setShortName: %s", name.c_str());
|
|
|
|
char cdata[2];
|
|
|
|
cdata[0] = name.length() + 1;
|
|
|
|
cdata[1] = BLE_HS_ADV_TYPE_INCOMP_NAME; // 0x08
|
|
|
|
addData(std::string(cdata, 2) + name);
|
|
|
|
NIMBLE_LOGD("NimBLEAdvertisementData", "<< setShortName");
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setShortName
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Retrieve the payload that is to be advertised.
|
|
|
|
* @return The payload that is to be advertised.
|
|
|
|
*/
|
|
|
|
std::string NimBLEAdvertisementData::getPayload() {
|
2020-05-14 06:03:56 +02:00
|
|
|
return m_payload;
|
2020-03-30 01:44:20 +02:00
|
|
|
} // getPayload
|
|
|
|
|
2020-05-14 06:03:56 +02:00
|
|
|
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
2020-05-10 15:21:46 +02:00
|
|
|
#endif /* CONFIG_BT_ENABLED */
|