mirror of
https://github.com/h2zero/esp-nimble-cpp.git
synced 2024-11-23 13:40:55 +01:00
WIP
This commit is contained in:
parent
34fb6b8b87
commit
53ecdc889d
2 changed files with 440 additions and 382 deletions
|
@ -37,27 +37,21 @@ NimBLEAdvertising::NimBLEAdvertising()
|
||||||
: m_advData{},
|
: m_advData{},
|
||||||
m_scanData{},
|
m_scanData{},
|
||||||
m_advParams{},
|
m_advParams{},
|
||||||
m_serviceUUIDs{},
|
|
||||||
m_customAdvData{false},
|
|
||||||
m_customScanResponseData{false},
|
|
||||||
m_scanResp{true},
|
|
||||||
m_advDataSet{false},
|
|
||||||
m_advCompCb{nullptr},
|
m_advCompCb{nullptr},
|
||||||
m_slaveItvl{0},
|
m_slaveItvl{0},
|
||||||
m_duration{BLE_HS_FOREVER},
|
m_duration{BLE_HS_FOREVER},
|
||||||
m_svcData16{},
|
m_customAdvData{false},
|
||||||
m_svcData32{},
|
m_customScanResponseData{false},
|
||||||
m_svcData128{},
|
m_scanResp{true},
|
||||||
m_name{},
|
m_advDataSet{false} {
|
||||||
m_mfgData{},
|
|
||||||
m_uri{} {
|
|
||||||
# if !defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
# if !defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
m_advParams.conn_mode = BLE_GAP_CONN_MODE_NON;
|
m_advParams.conn_mode = BLE_GAP_CONN_MODE_NON;
|
||||||
# else
|
# else
|
||||||
m_advParams.conn_mode = BLE_GAP_CONN_MODE_UND;
|
m_advParams.conn_mode = BLE_GAP_CONN_MODE_UND;
|
||||||
m_advData.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
|
m_advData.setFlags(BLE_HS_ADV_F_DISC_GEN);
|
||||||
# endif
|
# endif
|
||||||
m_advParams.disc_mode = BLE_GAP_DISC_MODE_GEN;
|
m_advParams.disc_mode = BLE_GAP_DISC_MODE_GEN;
|
||||||
|
|
||||||
} // NimBLEAdvertising
|
} // NimBLEAdvertising
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,7 +72,11 @@ bool NimBLEAdvertising::reset() {
|
||||||
* @param [in] serviceUUID The UUID of the service to expose.
|
* @param [in] serviceUUID The UUID of the service to expose.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertising::addServiceUUID(const NimBLEUUID& serviceUUID) {
|
void NimBLEAdvertising::addServiceUUID(const NimBLEUUID& serviceUUID) {
|
||||||
m_serviceUUIDs.push_back(serviceUUID);
|
if (!m_advData.addServiceUUID(serviceUUID) && m_scanResp) {
|
||||||
|
m_advDataSet = m_scanData.addServiceUUID(serviceUUID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_advDataSet = false;
|
m_advDataSet = false;
|
||||||
} // addServiceUUID
|
} // addServiceUUID
|
||||||
|
|
||||||
|
@ -96,15 +94,11 @@ void NimBLEAdvertising::addServiceUUID(const char* serviceUUID) {
|
||||||
* @param [in] serviceUUID The UUID of the service to remove.
|
* @param [in] serviceUUID The UUID of the service to remove.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertising::removeServiceUUID(const NimBLEUUID& serviceUUID) {
|
void NimBLEAdvertising::removeServiceUUID(const NimBLEUUID& serviceUUID) {
|
||||||
std::vector<NimBLEUUID> sVec;
|
if (!m_advData.removeServiceUUID(serviceUUID) && m_scanResp) {
|
||||||
for (const auto& uuid : m_serviceUUIDs) {
|
m_advDataSet = m_scanData.removeServiceUUID(serviceUUID);
|
||||||
if (uuid == serviceUUID) {
|
return;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
sVec.push_back(uuid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sVec.swap(m_serviceUUIDs);
|
|
||||||
m_advDataSet = false;
|
m_advDataSet = false;
|
||||||
} // removeServiceUUID
|
} // removeServiceUUID
|
||||||
|
|
||||||
|
@ -112,7 +106,11 @@ void NimBLEAdvertising::removeServiceUUID(const NimBLEUUID& serviceUUID) {
|
||||||
* @brief Remove all service UUIDs from the advertisement.
|
* @brief Remove all service UUIDs from the advertisement.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertising::removeServices() {
|
void NimBLEAdvertising::removeServices() {
|
||||||
std::vector<NimBLEUUID>().swap(m_serviceUUIDs);
|
if (!m_advData.removeServices() && m_scanResp) {
|
||||||
|
m_advDataSet = m_scanData.removeServices();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_advDataSet = false;
|
m_advDataSet = false;
|
||||||
} // removeServices
|
} // removeServices
|
||||||
|
|
||||||
|
@ -122,18 +120,24 @@ void NimBLEAdvertising::removeServices() {
|
||||||
* If the appearance value is 0 then the appearance will not be in the advertisement.
|
* If the appearance value is 0 then the appearance will not be in the advertisement.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertising::setAppearance(uint16_t appearance) {
|
void NimBLEAdvertising::setAppearance(uint16_t appearance) {
|
||||||
m_advData.appearance = appearance;
|
if (!m_advData.setAppearance(appearance) && m_scanResp) {
|
||||||
m_advData.appearance_is_present = appearance > 0;
|
m_advDataSet = m_scanData.setAppearance(appearance);
|
||||||
m_advDataSet = false;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_advDataSet = false;
|
||||||
} // setAppearance
|
} // setAppearance
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Add the transmission power level to the advertisement packet.
|
* @brief Add the transmission power level to the advertisement packet.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertising::addTxPower() {
|
void NimBLEAdvertising::addTxPower() {
|
||||||
m_advData.tx_pwr_lvl_is_present = true;
|
if (!m_advData.addTxPower() && m_scanResp) {
|
||||||
m_advData.tx_pwr_lvl = NimBLEDevice::getPower();
|
m_advDataSet = m_scanData.addTxPower();
|
||||||
m_advDataSet = false;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_advDataSet = false;
|
||||||
} // addTxPower
|
} // addTxPower
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -141,11 +145,12 @@ void NimBLEAdvertising::addTxPower() {
|
||||||
* @param [in] name The name to advertise.
|
* @param [in] name The name to advertise.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertising::setName(const std::string& name) {
|
void NimBLEAdvertising::setName(const std::string& name) {
|
||||||
std::vector<uint8_t>(name.begin(), name.end()).swap(m_name);
|
if (!m_advData.setName(name) && m_scanResp) {
|
||||||
m_advData.name = &m_name[0];
|
m_advDataSet = m_scanData.setName(name);
|
||||||
m_advData.name_len = m_name.size();
|
return;
|
||||||
m_advData.name_is_complete = true;
|
}
|
||||||
m_advDataSet = false;
|
|
||||||
|
m_advDataSet = false;
|
||||||
} // setName
|
} // setName
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -154,10 +159,12 @@ void NimBLEAdvertising::setName(const std::string& name) {
|
||||||
* @param [in] length The length of the data.
|
* @param [in] length The length of the data.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertising::setManufacturerData(const uint8_t* data, size_t length) {
|
void NimBLEAdvertising::setManufacturerData(const uint8_t* data, size_t length) {
|
||||||
std::vector<uint8_t>(data, data + length).swap(m_mfgData);
|
if (!m_advData.setManufacturerData(data, length) && m_scanResp) {
|
||||||
m_advData.mfg_data = &m_mfgData[0];
|
m_advDataSet = m_scanData.setManufacturerData(data, length);
|
||||||
m_advData.mfg_data_len = m_mfgData.size();
|
return;
|
||||||
m_advDataSet = false;
|
}
|
||||||
|
|
||||||
|
m_advDataSet = false;
|
||||||
} // setManufacturerData
|
} // setManufacturerData
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -181,10 +188,12 @@ void NimBLEAdvertising::setManufacturerData(const std::vector<uint8_t>& data) {
|
||||||
* @param [in] uri The URI to advertise.
|
* @param [in] uri The URI to advertise.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertising::setURI(const std::string& uri) {
|
void NimBLEAdvertising::setURI(const std::string& uri) {
|
||||||
std::vector<uint8_t>(uri.begin(), uri.end()).swap(m_uri);
|
if (!m_advData.setURI(uri) && m_scanResp) {
|
||||||
m_advData.uri = &m_uri[0];
|
m_advDataSet = m_scanData.setURI(uri);
|
||||||
m_advData.uri_len = m_uri.size();
|
return;
|
||||||
m_advDataSet = false;
|
}
|
||||||
|
|
||||||
|
m_advDataSet = false;
|
||||||
} // setURI
|
} // setURI
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -195,35 +204,40 @@ void NimBLEAdvertising::setURI(const std::string& uri) {
|
||||||
* @note If data length is 0 the service data will not be advertised.
|
* @note If data length is 0 the service data will not be advertised.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertising::setServiceData(const NimBLEUUID& uuid, const uint8_t* data, size_t length) {
|
void NimBLEAdvertising::setServiceData(const NimBLEUUID& uuid, const uint8_t* data, size_t length) {
|
||||||
switch (uuid.bitSize()) {
|
if (!m_advData.setServiceData(uuid, data, length) && m_scanResp) {
|
||||||
case 16: {
|
m_advDataSet = m_scanData.setServiceData(uuid, data, length);
|
||||||
std::vector<uint8_t>(uuid.getValue(), uuid.getValue() + 2).swap(m_svcData16);
|
return;
|
||||||
m_svcData16.insert(m_svcData16.end(), data, data + length);
|
|
||||||
m_advData.svc_data_uuid16 = &m_svcData16[0];
|
|
||||||
m_advData.svc_data_uuid16_len = (length > 0) ? m_svcData16.size() : 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 32: {
|
|
||||||
std::vector<uint8_t>(uuid.getValue(), uuid.getValue() + 4).swap(m_svcData32);
|
|
||||||
m_svcData32.insert(m_svcData32.end(), data, data + length);
|
|
||||||
m_advData.svc_data_uuid32 = &m_svcData32[0];
|
|
||||||
m_advData.svc_data_uuid32_len = (length > 0) ? m_svcData32.size() : 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 128: {
|
|
||||||
std::vector<uint8_t>(uuid.getValue(), uuid.getValue() + 16).swap(m_svcData128);
|
|
||||||
m_svcData128.insert(m_svcData128.end(), data, data + length);
|
|
||||||
m_advData.svc_data_uuid128 = &m_svcData128[0];
|
|
||||||
m_advData.svc_data_uuid128_len = (length > 0) ? m_svcData128.size() : 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
switch (uuid.bitSize()) {
|
||||||
|
case 16: {
|
||||||
|
std::vector<uint8_t>(uuid.getValue(), uuid.getValue() + 2).swap(m_svcData16);
|
||||||
|
m_svcData16.insert(m_svcData16.end(), data, data + length);
|
||||||
|
m_advData.svc_data_uuid16 = &m_svcData16[0];
|
||||||
|
m_advData.svc_data_uuid16_len = (length > 0) ? m_svcData16.size() : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 32: {
|
||||||
|
std::vector<uint8_t>(uuid.getValue(), uuid.getValue() + 4).swap(m_svcData32);
|
||||||
|
m_svcData32.insert(m_svcData32.end(), data, data + length);
|
||||||
|
m_advData.svc_data_uuid32 = &m_svcData32[0];
|
||||||
|
m_advData.svc_data_uuid32_len = (length > 0) ? m_svcData32.size() : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 128: {
|
||||||
|
std::vector<uint8_t>(uuid.getValue(), uuid.getValue() + 16).swap(m_svcData128);
|
||||||
|
m_svcData128.insert(m_svcData128.end(), data, data + length);
|
||||||
|
m_advData.svc_data_uuid128 = &m_svcData128[0];
|
||||||
|
m_advData.svc_data_uuid128_len = (length > 0) ? m_svcData128.size() : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*/
|
||||||
m_advDataSet = false;
|
m_advDataSet = false;
|
||||||
} // setServiceData
|
} // setServiceData
|
||||||
|
|
||||||
|
@ -271,21 +285,22 @@ void NimBLEAdvertising::setConnectableMode(uint8_t mode) {
|
||||||
* * BLE_GAP_DISC_MODE_GEN (2) - general discoverable
|
* * BLE_GAP_DISC_MODE_GEN (2) - general discoverable
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertising::setDiscoverableMode(uint8_t mode) {
|
void NimBLEAdvertising::setDiscoverableMode(uint8_t mode) {
|
||||||
switch (mode) {
|
/*
|
||||||
case BLE_GAP_DISC_MODE_NON:
|
switch (mode) {
|
||||||
m_advData.flags = 0;
|
case BLE_GAP_DISC_MODE_NON:
|
||||||
break;
|
m_advData.flags = 0;
|
||||||
case BLE_GAP_DISC_MODE_LTD:
|
break;
|
||||||
m_advData.flags = (BLE_HS_ADV_F_DISC_LTD | BLE_HS_ADV_F_BREDR_UNSUP);
|
case BLE_GAP_DISC_MODE_LTD:
|
||||||
break;
|
m_advData.flags = (BLE_HS_ADV_F_DISC_LTD | BLE_HS_ADV_F_BREDR_UNSUP);
|
||||||
case BLE_GAP_DISC_MODE_GEN:
|
break;
|
||||||
m_advData.flags = (BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP);
|
case BLE_GAP_DISC_MODE_GEN:
|
||||||
break;
|
m_advData.flags = (BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP);
|
||||||
default:
|
break;
|
||||||
NIMBLE_LOGE(LOG_TAG, "Invalid discoverable mode: %u", mode);
|
default:
|
||||||
return;
|
NIMBLE_LOGE(LOG_TAG, "Invalid discoverable mode: %u", mode);
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
*/
|
||||||
m_advParams.disc_mode = mode;
|
m_advParams.disc_mode = mode;
|
||||||
} // setDiscoverableMode
|
} // setDiscoverableMode
|
||||||
|
|
||||||
|
@ -321,25 +336,11 @@ void NimBLEAdvertising::setMaxInterval(uint16_t maxInterval) {
|
||||||
* @details Range = 0x0006(7.5ms) to 0x0C80(4000ms), values not within the range will be limited to this range.
|
* @details Range = 0x0006(7.5ms) to 0x0C80(4000ms), values not within the range will be limited to this range.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertising::setPreferredConnectionInterval(uint16_t minInterval, uint16_t maxInterval) {
|
void NimBLEAdvertising::setPreferredConnectionInterval(uint16_t minInterval, uint16_t maxInterval) {
|
||||||
if (!minInterval) {
|
if (!m_advData.setPreferredConnectionInterval(minInterval, maxInterval) && m_scanResp) {
|
||||||
minInterval = *reinterpret_cast<const uint16_t*>(m_advData.slave_itvl_range);
|
m_advDataSet = m_scanData.setPreferredConnectionInterval(minInterval, maxInterval);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!maxInterval) {
|
|
||||||
maxInterval = *reinterpret_cast<const uint16_t*>(m_advData.slave_itvl_range + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
minInterval = std::max<uint16_t>(minInterval, 0x6);
|
|
||||||
minInterval = std::min<uint16_t>(minInterval, 0xC80);
|
|
||||||
maxInterval = std::max<uint16_t>(maxInterval, 0x6);
|
|
||||||
maxInterval = std::min<uint16_t>(maxInterval, 0xC80);
|
|
||||||
maxInterval = std::max<uint16_t>(maxInterval, minInterval); // Max must be greater than or equal to min.
|
|
||||||
|
|
||||||
m_slaveItvl[0] = minInterval;
|
|
||||||
m_slaveItvl[1] = minInterval >> 8;
|
|
||||||
m_slaveItvl[2] = maxInterval;
|
|
||||||
m_slaveItvl[3] = maxInterval >> 8;
|
|
||||||
|
|
||||||
m_advDataSet = false;
|
m_advDataSet = false;
|
||||||
} // setPreferredConnectionInterval
|
} // setPreferredConnectionInterval
|
||||||
|
|
||||||
|
@ -466,164 +467,6 @@ bool NimBLEAdvertising::start(uint32_t duration, const NimBLEAddress* dirAddr) {
|
||||||
duration = BLE_HS_FOREVER;
|
duration = BLE_HS_FOREVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_advParams.conn_mode == BLE_GAP_CONN_MODE_NON) {
|
|
||||||
m_advData.flags = 0; // non-connectable advertising does not require AD flags.
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_customAdvData && !m_advDataSet) {
|
|
||||||
// start with 3 bytes for the flags data if required
|
|
||||||
uint8_t payloadLen = (m_advData.flags > 0) ? (2 + 1) : 0;
|
|
||||||
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 + BLE_HS_ADV_TX_PWR_LVL_LEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_advData.slave_itvl_range != nullptr) {
|
|
||||||
payloadLen += (2 + BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& uuid : m_serviceUUIDs) {
|
|
||||||
int payloadAdd = 0;
|
|
||||||
if (uuid.bitSize() == BLE_UUID_TYPE_16) {
|
|
||||||
payloadAdd = (m_advData.num_uuids16 > 0) ? 2 : 4; // 2 bytes more if this is the first of the type
|
|
||||||
if ((payloadLen + payloadAdd) > BLE_HS_ADV_MAX_SZ) {
|
|
||||||
m_advData.uuids16_is_complete = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_advData.uuids16 = reinterpret_cast<ble_uuid16_t*>(
|
|
||||||
realloc((void*)m_advData.uuids16, (m_advData.num_uuids16 + 1) * sizeof(ble_uuid16_t)));
|
|
||||||
if (!m_advData.uuids16) {
|
|
||||||
NIMBLE_LOGE(LOG_TAG, "Error, no mem");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy((void*)&m_advData.uuids16[m_advData.num_uuids16], uuid.getBase(), sizeof(ble_uuid16_t));
|
|
||||||
m_advData.uuids16_is_complete = 1;
|
|
||||||
m_advData.num_uuids16++;
|
|
||||||
} else if (uuid.bitSize() == BLE_UUID_TYPE_32) {
|
|
||||||
payloadAdd = (m_advData.num_uuids32 > 0) ? 4 : 6; // 2 bytes more if this is the first of the type
|
|
||||||
if ((payloadLen + payloadAdd) > BLE_HS_ADV_MAX_SZ) {
|
|
||||||
m_advData.uuids32_is_complete = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_advData.uuids32 = reinterpret_cast<ble_uuid32_t*>(
|
|
||||||
realloc((void*)m_advData.uuids32, (m_advData.num_uuids32 + 1) * sizeof(ble_uuid32_t)));
|
|
||||||
if (!m_advData.uuids32) {
|
|
||||||
NIMBLE_LOGE(LOG_TAG, "Error, no mem");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy((void*)&m_advData.uuids32[m_advData.num_uuids32], uuid.getBase(), sizeof(ble_uuid32_t));
|
|
||||||
m_advData.uuids32_is_complete = 1;
|
|
||||||
m_advData.num_uuids32++;
|
|
||||||
} else if (uuid.bitSize() == BLE_UUID_TYPE_128) {
|
|
||||||
payloadAdd = (m_advData.num_uuids128 > 0) ? 16 : 18; // 2 bytes more if this is the first of the type
|
|
||||||
if ((payloadLen + payloadAdd) > BLE_HS_ADV_MAX_SZ) {
|
|
||||||
m_advData.uuids128_is_complete = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_advData.uuids128 = reinterpret_cast<ble_uuid128_t*>(
|
|
||||||
realloc((void*)m_advData.uuids128, (m_advData.num_uuids128 + 1) * sizeof(ble_uuid128_t)));
|
|
||||||
if (!m_advData.uuids128) {
|
|
||||||
NIMBLE_LOGE(LOG_TAG, "Error, no mem");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy((void*)&m_advData.uuids128[m_advData.num_uuids128], uuid.getBase(), sizeof(ble_uuid128_t));
|
|
||||||
m_advData.uuids128_is_complete = 1;
|
|
||||||
m_advData.num_uuids128++;
|
|
||||||
}
|
|
||||||
|
|
||||||
payloadLen += payloadAdd;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if there is room for the name, if not put it in scan data
|
|
||||||
if (m_advData.name_len && (payloadLen + 2 + m_advData.name_len) > BLE_HS_ADV_MAX_SZ) {
|
|
||||||
if (m_scanResp && !m_customScanResponseData) {
|
|
||||||
m_scanData.name = m_advData.name;
|
|
||||||
m_scanData.name_len = m_advData.name_len;
|
|
||||||
if (m_scanData.name_len > BLE_HS_ADV_MAX_SZ - 2) {
|
|
||||||
m_scanData.name_len = BLE_HS_ADV_MAX_SZ - 2;
|
|
||||||
m_scanData.name_is_complete = 0;
|
|
||||||
} else {
|
|
||||||
m_scanData.name_is_complete = 1;
|
|
||||||
}
|
|
||||||
m_advData.name = nullptr;
|
|
||||||
m_advData.name_len = 0;
|
|
||||||
m_advData.name_is_complete = 0;
|
|
||||||
} else {
|
|
||||||
// if not using scan response truncate the name
|
|
||||||
if (m_advData.name_len > (BLE_HS_ADV_MAX_SZ - payloadLen - 2)) {
|
|
||||||
m_advData.name_len = (BLE_HS_ADV_MAX_SZ - payloadLen - 2);
|
|
||||||
m_advData.name_is_complete = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = ble_gap_adv_set_fields(&m_advData);
|
|
||||||
if (rc != 0) {
|
|
||||||
NIMBLE_LOGE(LOG_TAG, "Error setting advertisement data rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_scanResp && !m_customScanResponseData) {
|
|
||||||
rc = ble_gap_adv_rsp_set_fields(&m_scanData);
|
|
||||||
if (rc != 0) {
|
|
||||||
NIMBLE_LOGE(LOG_TAG, "Error setting scan response data rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// free the memory used for the UUIDs as they are now copied into the advertisement data.
|
|
||||||
if (m_advData.num_uuids128 > 0) {
|
|
||||||
free((void*)m_advData.uuids128);
|
|
||||||
m_advData.uuids128 = nullptr;
|
|
||||||
m_advData.num_uuids128 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_advData.num_uuids32 > 0) {
|
|
||||||
free((void*)m_advData.uuids32);
|
|
||||||
m_advData.uuids32 = nullptr;
|
|
||||||
m_advData.num_uuids32 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_advData.num_uuids16 > 0) {
|
|
||||||
free((void*)m_advData.uuids16);
|
|
||||||
m_advData.uuids16 = nullptr;
|
|
||||||
m_advData.num_uuids16 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_advDataSet = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
rc = ble_gap_adv_start(NimBLEDevice::m_ownAddrType,
|
rc = ble_gap_adv_start(NimBLEDevice::m_ownAddrType,
|
||||||
(dirAddr != nullptr) ? dirAddr->getBase() : NULL,
|
(dirAddr != nullptr) ? dirAddr->getBase() : NULL,
|
||||||
|
@ -729,34 +572,157 @@ int NimBLEAdvertising::handleGapEvent(struct ble_gap_event* event, void* arg) {
|
||||||
* @param [in] data The data to be added to the payload.
|
* @param [in] data The data to be added to the payload.
|
||||||
* @param [in] length The size of data to be added to the payload.
|
* @param [in] length The size of data to be added to the payload.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertisementData::addData(const uint8_t* data, size_t length) {
|
bool NimBLEAdvertisementData::addData(const uint8_t* data, size_t length) {
|
||||||
if ((m_payload.size() + length) > BLE_HS_ADV_MAX_SZ) {
|
if ((m_payload.size() + length) > BLE_HS_ADV_MAX_SZ) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Advertisement data length exceeded");
|
NIMBLE_LOGE(LOG_TAG, "Data length exceeded");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_payload.insert(m_payload.end(), data, data + length);
|
m_payload.insert(m_payload.end(), data, data + length);
|
||||||
|
return true;
|
||||||
} // addData
|
} // addData
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Add data to the payload to be advertised.
|
* @brief Add data to the payload to be advertised.
|
||||||
* @param [in] data The data to be added to the payload.
|
* @param [in] data The data to be added to the payload.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertisementData::addData(const std::vector<uint8_t>& data) {
|
bool NimBLEAdvertisementData::addData(const std::vector<uint8_t>& data) {
|
||||||
addData(&data[0], data.size());
|
return addData(&data[0], data.size());
|
||||||
} // addData
|
} // addData
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add a service uuid to exposed list of services.
|
||||||
|
* @param [in] serviceUUID The UUID of the service to expose.
|
||||||
|
*/
|
||||||
|
bool NimBLEAdvertisementData::addServiceUUID(const NimBLEUUID& serviceUUID) {
|
||||||
|
uint8_t bytes = serviceUUID.bitSize() / 8;
|
||||||
|
int type;
|
||||||
|
switch (bytes) {
|
||||||
|
case 2:
|
||||||
|
type = BLE_HS_ADV_TYPE_COMP_UUIDS16;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
type = BLE_HS_ADV_TYPE_COMP_UUIDS32;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
type = BLE_HS_ADV_TYPE_COMP_UUIDS128;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dataLoc = getDataLocation(type);
|
||||||
|
uint8_t length = bytes;
|
||||||
|
if (dataLoc == -1) {
|
||||||
|
length += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length + getPayload().size() > BLE_HS_ADV_MAX_SZ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t data[31];
|
||||||
|
if (dataLoc < 0) {
|
||||||
|
data[0] = 2 + bytes;
|
||||||
|
data[1] = type;
|
||||||
|
memcpy(&data[2], serviceUUID.getValue(), bytes);
|
||||||
|
} else {
|
||||||
|
auto payload = m_payload.data();
|
||||||
|
auto nextData = dataLoc + payload[dataLoc];
|
||||||
|
memcpy(data, payload, nextData);
|
||||||
|
data[dataLoc] += bytes;
|
||||||
|
memcpy(&data[nextData], serviceUUID.getValue(), bytes);
|
||||||
|
memcpy(&data[nextData + bytes], payload + nextData, m_payload.size() - nextData);
|
||||||
|
length += getPayload().size();
|
||||||
|
clearData();
|
||||||
|
}
|
||||||
|
|
||||||
|
return addData(data, length);
|
||||||
|
} // addServiceUUID
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add a service uuid to exposed list of services.
|
||||||
|
* @param [in] serviceUUID The string representation of the service to expose.
|
||||||
|
* @return True if successful.
|
||||||
|
*/
|
||||||
|
bool NimBLEAdvertisementData::addServiceUUID(const char* serviceUUID) {
|
||||||
|
return addServiceUUID(NimBLEUUID(serviceUUID));
|
||||||
|
} // addServiceUUID
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Remove a service UUID from the advertisement.
|
||||||
|
* @param [in] serviceUUID The UUID of the service to remove.
|
||||||
|
* @return True if successful.
|
||||||
|
*/
|
||||||
|
bool NimBLEAdvertisementData::removeServiceUUID(const NimBLEUUID& serviceUUID) {
|
||||||
|
uint8_t bytes = serviceUUID.bitSize() / 8;
|
||||||
|
int type;
|
||||||
|
switch (bytes) {
|
||||||
|
case 2:
|
||||||
|
type = BLE_HS_ADV_TYPE_COMP_UUIDS16;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
type = BLE_HS_ADV_TYPE_COMP_UUIDS32;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
type = BLE_HS_ADV_TYPE_COMP_UUIDS128;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dataLoc = getDataLocation(type);
|
||||||
|
if (dataLoc == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int uuidLoc = -1;
|
||||||
|
for (int i = dataLoc + 2; i < m_payload.size(); i += bytes) {
|
||||||
|
if (memcmp(&m_payload[i], serviceUUID.getValue(), bytes) == 0) {
|
||||||
|
uuidLoc = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uuidLoc == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto payload = m_payload.data();
|
||||||
|
auto nextData = dataLoc + payload[dataLoc];
|
||||||
|
uint8_t length = m_payload.size() - bytes;
|
||||||
|
uint8_t data[31];
|
||||||
|
memcpy(data, payload, uuidLoc);
|
||||||
|
if (payload[dataLoc] - bytes == 2) {
|
||||||
|
length -= 2;
|
||||||
|
memcpy(&data[dataLoc], payload + nextData, m_payload.size() - nextData);
|
||||||
|
} else {
|
||||||
|
data[dataLoc] -= bytes;
|
||||||
|
memcpy(&data[uuidLoc], payload + uuidLoc + bytes, m_payload.size() - uuidLoc - bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearData();
|
||||||
|
return addData(data, length);
|
||||||
|
} // removeServiceUUID
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Remove all service UUIDs from the advertisement.
|
||||||
|
*/
|
||||||
|
bool NimBLEAdvertisementData::removeServices() {
|
||||||
|
return true;
|
||||||
|
} // removeServices
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the appearance.
|
* @brief Set the appearance.
|
||||||
* @param [in] appearance The appearance code value.
|
* @param [in] appearance The appearance code value.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertisementData::setAppearance(uint16_t appearance) {
|
bool NimBLEAdvertisementData::setAppearance(uint16_t appearance) {
|
||||||
uint8_t data[4];
|
uint8_t data[4];
|
||||||
data[0] = 3;
|
data[0] = 3;
|
||||||
data[1] = BLE_HS_ADV_TYPE_APPEARANCE;
|
data[1] = BLE_HS_ADV_TYPE_APPEARANCE;
|
||||||
data[2] = appearance;
|
data[2] = appearance;
|
||||||
data[3] = (appearance >> 8) & 0xFF;
|
data[3] = (appearance >> 8) & 0xFF;
|
||||||
addData(data, 4);
|
return addData(data, 4);
|
||||||
} // setAppearance
|
} // setAppearance
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -766,121 +732,137 @@ void NimBLEAdvertisementData::setAppearance(uint16_t appearance) {
|
||||||
* * BLE_HS_ADV_F_DISC_GEN
|
* * BLE_HS_ADV_F_DISC_GEN
|
||||||
* * BLE_HS_ADV_F_BREDR_UNSUP - must always use with NimBLE
|
* * BLE_HS_ADV_F_BREDR_UNSUP - must always use with NimBLE
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertisementData::setFlags(uint8_t flag) {
|
bool NimBLEAdvertisementData::setFlags(uint8_t flag) {
|
||||||
uint8_t data[3];
|
uint8_t data[3];
|
||||||
data[0] = 2;
|
data[0] = 2;
|
||||||
data[1] = BLE_HS_ADV_TYPE_FLAGS;
|
data[1] = BLE_HS_ADV_TYPE_FLAGS;
|
||||||
data[2] = flag | BLE_HS_ADV_F_BREDR_UNSUP;
|
data[2] = flag | BLE_HS_ADV_F_BREDR_UNSUP;
|
||||||
addData(data, 3);
|
return addData(data, 3);
|
||||||
} // setFlag
|
} // setFlag
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set manufacturer specific data.
|
* @brief Set manufacturer specific data.
|
||||||
* @param [in] data The manufacturer data to advertise.
|
* @param [in] data The manufacturer data to advertise.
|
||||||
|
* @param [in] length The length of the data.
|
||||||
|
* @return True if successful.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertisementData::setManufacturerData(const std::string& data) {
|
bool NimBLEAdvertisementData::setManufacturerData(const uint8_t* data, size_t length) {
|
||||||
uint8_t mdata[31];
|
uint8_t mdata[31];
|
||||||
uint8_t length = 2 + std::min<uint8_t>(data.length(), 29);
|
uint8_t mlen = 2 + std::min<uint8_t>(length, 29);
|
||||||
mdata[0] = length - 1;
|
mdata[0] = mlen - 1;
|
||||||
mdata[1] = BLE_HS_ADV_TYPE_MFG_DATA;
|
mdata[1] = BLE_HS_ADV_TYPE_MFG_DATA;
|
||||||
memcpy(&mdata[2], data.c_str(), std::min<uint8_t>(data.length(), 29));
|
memcpy(&mdata[2], data, mlen - 2);
|
||||||
addData(mdata, length);
|
return addData(mdata, mlen);
|
||||||
} // setManufacturerData
|
} // setManufacturerData
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set manufacturer specific data.
|
* @brief Set manufacturer specific data.
|
||||||
* @param [in] data The manufacturer data to advertise.
|
* @param [in] data The manufacturer data to advertise.
|
||||||
|
* @return True if successful.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertisementData::setManufacturerData(const std::vector<uint8_t>& data) {
|
bool NimBLEAdvertisementData::setManufacturerData(const std::string& data) {
|
||||||
uint8_t mdata[31];
|
return setManufacturerData(reinterpret_cast<const uint8_t*>(data.data()), data.length());
|
||||||
uint8_t length = 2 + std::min<uint8_t>(data.size(), 29);
|
} // setManufacturerData
|
||||||
mdata[0] = length - 1;
|
|
||||||
mdata[1] = BLE_HS_ADV_TYPE_MFG_DATA;
|
/**
|
||||||
memcpy(&mdata[2], data.data(), std::min<uint8_t>(data.size(), 29));
|
* @brief Set manufacturer specific data.
|
||||||
addData(mdata, length);
|
* @param [in] data The manufacturer data to advertise.
|
||||||
|
* @return True if successful.
|
||||||
|
*/
|
||||||
|
bool NimBLEAdvertisementData::setManufacturerData(const std::vector<uint8_t>& data) {
|
||||||
|
return setManufacturerData(&data[0], data.size());
|
||||||
} // setManufacturerData
|
} // setManufacturerData
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the URI to advertise.
|
* @brief Set the URI to advertise.
|
||||||
* @param [in] uri The uri to advertise.
|
* @param [in] uri The uri to advertise.
|
||||||
|
* @return True if successful.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertisementData::setURI(const std::string& uri) {
|
bool NimBLEAdvertisementData::setURI(const std::string& uri) {
|
||||||
uint8_t data[31];
|
uint8_t data[31];
|
||||||
uint8_t length = 2 + std::min<uint8_t>(uri.length(), 29);
|
uint8_t length = 2 + std::min<uint8_t>(uri.length(), 29);
|
||||||
data[0] = length - 1;
|
data[0] = length - 1;
|
||||||
data[1] = BLE_HS_ADV_TYPE_URI;
|
data[1] = BLE_HS_ADV_TYPE_URI;
|
||||||
memcpy(&data[2], uri.c_str(), std::min<uint8_t>(uri.length(), 29));
|
memcpy(&data[2], uri.c_str(), length - 2);
|
||||||
addData(data, length);
|
return addData(data, length);
|
||||||
} // setURI
|
} // setURI
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the complete name of this device.
|
* @brief Set the complete name of this device.
|
||||||
* @param [in] name The name to advertise.
|
* @param [in] name The name to advertise.
|
||||||
* @param [in] isComplete If true the name is complete, otherwise it is shortened.
|
* @param [in] isComplete If true the name is complete, otherwise it is shortened.
|
||||||
|
* @return True if successful.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertisementData::setName(const std::string& name, bool isComplete) {
|
bool NimBLEAdvertisementData::setName(const std::string& name, bool isComplete) {
|
||||||
uint8_t data[31];
|
uint8_t data[31];
|
||||||
uint8_t length = 2 + std::min<uint8_t>(name.length(), 29);
|
uint8_t length = 2 + std::min<uint8_t>(name.length(), 29);
|
||||||
data[0] = length - 1;
|
data[0] = length - 1;
|
||||||
data[1] = isComplete ? BLE_HS_ADV_TYPE_COMP_NAME : BLE_HS_ADV_TYPE_INCOMP_NAME;
|
data[1] = isComplete ? BLE_HS_ADV_TYPE_COMP_NAME : BLE_HS_ADV_TYPE_INCOMP_NAME;
|
||||||
memcpy(&data[2], name.c_str(), std::min<uint8_t>(name.length(), 29));
|
memcpy(&data[2], name.c_str(), std::min<uint8_t>(name.length(), 29));
|
||||||
addData(data, length);
|
return addData(data, length);
|
||||||
} // setName
|
} // setName
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the short name.
|
* @brief Set the short name.
|
||||||
* @param [in] name The short name of the device.
|
* @param [in] name The short name of the device.
|
||||||
|
* @return True if successful.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertisementData::setShortName(const std::string& name) {
|
bool NimBLEAdvertisementData::setShortName(const std::string& name) {
|
||||||
setName(name, false);
|
return setName(name, false);
|
||||||
} // setShortName
|
} // setShortName
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set a single service to advertise as a complete list of services.
|
* @brief Set a single service to advertise as a complete list of services.
|
||||||
* @param [in] uuid The service to advertise.
|
* @param [in] uuid The service to advertise.
|
||||||
|
* @return True if successful.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertisementData::setCompleteServices(const NimBLEUUID& uuid) {
|
bool NimBLEAdvertisementData::setCompleteServices(const NimBLEUUID& uuid) {
|
||||||
setServices(true, uuid.bitSize(), {uuid});
|
return setServices(true, uuid.bitSize(), {uuid});
|
||||||
} // setCompleteServices
|
} // setCompleteServices
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the complete list of 16 bit services to advertise.
|
* @brief Set the complete list of 16 bit services to advertise.
|
||||||
* @param [in] uuids A vector of 16 bit UUID's to advertise.
|
* @param [in] uuids A vector of 16 bit UUID's to advertise.
|
||||||
|
* @return True if successful.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertisementData::setCompleteServices16(const std::vector<NimBLEUUID>& uuids) {
|
bool NimBLEAdvertisementData::setCompleteServices16(const std::vector<NimBLEUUID>& uuids) {
|
||||||
setServices(true, 16, uuids);
|
return setServices(true, 16, uuids);
|
||||||
} // setCompleteServices16
|
} // setCompleteServices16
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the complete list of 32 bit services to advertise.
|
* @brief Set the complete list of 32 bit services to advertise.
|
||||||
* @param [in] uuids A vector of 32 bit UUID's to advertise.
|
* @param [in] uuids A vector of 32 bit UUID's to advertise.
|
||||||
|
* @return True if successful.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertisementData::setCompleteServices32(const std::vector<NimBLEUUID>& uuids) {
|
bool NimBLEAdvertisementData::setCompleteServices32(const std::vector<NimBLEUUID>& uuids) {
|
||||||
setServices(true, 32, uuids);
|
return setServices(true, 32, uuids);
|
||||||
} // setCompleteServices32
|
} // setCompleteServices32
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set a single service to advertise as a partial list of services.
|
* @brief Set a single service to advertise as a partial list of services.
|
||||||
* @param [in] uuid The service to advertise.
|
* @param [in] uuid The service to advertise.
|
||||||
|
* @return True if successful.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertisementData::setPartialServices(const NimBLEUUID& uuid) {
|
bool NimBLEAdvertisementData::setPartialServices(const NimBLEUUID& uuid) {
|
||||||
setServices(false, uuid.bitSize(), {uuid});
|
return setServices(false, uuid.bitSize(), {uuid});
|
||||||
} // setPartialServices
|
} // setPartialServices
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the partial list of services to advertise.
|
* @brief Set the partial list of services to advertise.
|
||||||
* @param [in] uuids A vector of 16 bit UUID's to advertise.
|
* @param [in] uuids A vector of 16 bit UUID's to advertise.
|
||||||
|
* @return True if successful.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertisementData::setPartialServices16(const std::vector<NimBLEUUID>& uuids) {
|
bool NimBLEAdvertisementData::setPartialServices16(const std::vector<NimBLEUUID>& uuids) {
|
||||||
setServices(false, 16, uuids);
|
return setServices(false, 16, uuids);
|
||||||
} // setPartialServices16
|
} // setPartialServices16
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the partial list of services to advertise.
|
* @brief Set the partial list of services to advertise.
|
||||||
* @param [in] uuids A vector of 32 bit UUID's to advertise.
|
* @param [in] uuids A vector of 32 bit UUID's to advertise.
|
||||||
|
* @return True if successful.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertisementData::setPartialServices32(const std::vector<NimBLEUUID>& uuids) {
|
bool NimBLEAdvertisementData::setPartialServices32(const std::vector<NimBLEUUID>& uuids) {
|
||||||
setServices(false, 32, uuids);
|
return setServices(false, 32, uuids);
|
||||||
} // setPartialServices32
|
} // setPartialServices32
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -888,8 +870,9 @@ void NimBLEAdvertisementData::setPartialServices32(const std::vector<NimBLEUUID>
|
||||||
* @param [in] complete If true the vector is the complete set of services.
|
* @param [in] complete If true the vector is the complete set of services.
|
||||||
* @param [in] size The bit size of the UUID's in the vector. (16, 32, or 128).
|
* @param [in] size The bit size of the UUID's in the vector. (16, 32, or 128).
|
||||||
* @param [in] uuids The vector of service UUID's to advertise.
|
* @param [in] uuids The vector of service UUID's to advertise.
|
||||||
|
* @return True if successful.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertisementData::setServices(bool complete, uint8_t size, const std::vector<NimBLEUUID>& uuids) {
|
bool NimBLEAdvertisementData::setServices(bool complete, uint8_t size, const std::vector<NimBLEUUID>& uuids) {
|
||||||
uint8_t bytes = size / 8;
|
uint8_t bytes = size / 8;
|
||||||
uint8_t length = 2; // start with 2 for length + type bytes
|
uint8_t length = 2; // start with 2 for length + type bytes
|
||||||
uint8_t data[31];
|
uint8_t data[31];
|
||||||
|
@ -922,53 +905,74 @@ void NimBLEAdvertisementData::setServices(bool complete, uint8_t size, const std
|
||||||
data[1] = (complete ? BLE_HS_ADV_TYPE_COMP_UUIDS128 : BLE_HS_ADV_TYPE_INCOMP_UUIDS128);
|
data[1] = (complete ? BLE_HS_ADV_TYPE_COMP_UUIDS128 : BLE_HS_ADV_TYPE_INCOMP_UUIDS128);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
addData(data, length);
|
return addData(data, length);
|
||||||
} // setServices
|
} // setServices
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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.
|
||||||
|
* @param [in] length The length of the data.
|
||||||
|
* @note If data length is 0 the service data will not be advertised.
|
||||||
|
*/
|
||||||
|
bool NimBLEAdvertisementData::setServiceData(const NimBLEUUID& uuid, const uint8_t* data, size_t length) {
|
||||||
|
uint8_t uuidBytes = uuid.bitSize() / 8;
|
||||||
|
uint8_t sDataLen = 2 + uuidBytes + length;
|
||||||
|
if (sDataLen > 31) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Data too long");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t sData[31];
|
||||||
|
sData[0] = uuidBytes + length + 1;
|
||||||
|
|
||||||
|
switch (uuidBytes) {
|
||||||
|
case 2:
|
||||||
|
sData[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID16;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
sData[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID32;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
sData[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID128;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&sData[2], uuid.getValue(), uuidBytes);
|
||||||
|
memcpy(&sData[uuidBytes], data, length);
|
||||||
|
return addData(sData, sDataLen);
|
||||||
|
} // setServiceData
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the service data (UUID + data)
|
* @brief Set the service data (UUID + data)
|
||||||
* @param [in] uuid The UUID to set with the service data.
|
* @param [in] uuid The UUID to set with the service data.
|
||||||
* @param [in] data The data to be associated with the service data advertised.
|
* @param [in] data The data to be associated with the service data advertised.
|
||||||
|
* @return True if successful.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertisementData::setServiceData(const NimBLEUUID& uuid, const std::string& data) {
|
bool NimBLEAdvertisementData::setServiceData(const NimBLEUUID& uuid, const std::string& data) {
|
||||||
uint8_t sData[31];
|
return setServiceData(uuid, reinterpret_cast<const uint8_t*>(data.data()), data.length());
|
||||||
uint8_t uuidBytes = uuid.bitSize() / 8;
|
} // setServiceData
|
||||||
uint8_t length = 2 + uuidBytes + data.length(); // 2 bytes for header + uuid bytes + data
|
|
||||||
if (length > 31) {
|
|
||||||
NIMBLE_LOGE(LOG_TAG, "Service data too long");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&sData[2], uuid.getValue(), uuidBytes);
|
/**
|
||||||
memcpy(&sData[2 + uuidBytes], data.c_str(), data.length());
|
* @brief Set the service data advertised for the UUID.
|
||||||
|
* @param [in] uuid The UUID the service data belongs to.
|
||||||
switch (uuidBytes) {
|
* @param [in] data The data to advertise.
|
||||||
case 2: {
|
* @note If data length is 0 the service data will not be advertised.
|
||||||
sData[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID16;
|
*/
|
||||||
break;
|
bool NimBLEAdvertisementData::setServiceData(const NimBLEUUID& uuid, const std::vector<uint8_t>& data) {
|
||||||
}
|
return setServiceData(uuid, &data[0], data.size());
|
||||||
case 16: {
|
|
||||||
sData[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID128;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 4: {
|
|
||||||
sData[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID32;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
addData(sData, length);
|
|
||||||
} // setServiceData
|
} // setServiceData
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Adds Tx power level to the advertisement data.
|
* @brief Adds Tx power level to the advertisement data.
|
||||||
|
* @return True if successful.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertisementData::addTxPower() {
|
bool NimBLEAdvertisementData::addTxPower() {
|
||||||
uint8_t data[3];
|
uint8_t data[3];
|
||||||
data[0] = BLE_HS_ADV_TX_PWR_LVL_LEN + 1;
|
data[0] = BLE_HS_ADV_TX_PWR_LVL_LEN + 1;
|
||||||
data[1] = BLE_HS_ADV_TYPE_TX_PWR_LVL;
|
data[1] = BLE_HS_ADV_TYPE_TX_PWR_LVL;
|
||||||
|
@ -977,15 +981,16 @@ void NimBLEAdvertisementData::addTxPower() {
|
||||||
# else
|
# else
|
||||||
data[2] = 0;
|
data[2] = 0;
|
||||||
# endif
|
# endif
|
||||||
addData(data, 3);
|
return addData(data, 3);
|
||||||
} // addTxPower
|
} // addTxPower
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the preferred connection interval parameters.
|
* @brief Set the preferred connection interval parameters.
|
||||||
* @param [in] min The minimum interval desired.
|
* @param [in] min The minimum interval desired.
|
||||||
* @param [in] max The maximum interval desired.
|
* @param [in] max The maximum interval desired.
|
||||||
|
* @return True if successful.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertisementData::setPreferredParams(uint16_t min, uint16_t max) {
|
bool NimBLEAdvertisementData::setPreferredParams(uint16_t min, uint16_t max) {
|
||||||
uint8_t data[6];
|
uint8_t data[6];
|
||||||
data[0] = BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1;
|
data[0] = BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1;
|
||||||
data[1] = BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE;
|
data[1] = BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE;
|
||||||
|
@ -993,9 +998,56 @@ void NimBLEAdvertisementData::setPreferredParams(uint16_t min, uint16_t max) {
|
||||||
data[3] = min >> 8;
|
data[3] = min >> 8;
|
||||||
data[4] = max;
|
data[4] = max;
|
||||||
data[5] = max >> 8;
|
data[5] = max >> 8;
|
||||||
addData(data, 6);
|
return addData(data, 6);
|
||||||
} // setPreferredParams
|
} // setPreferredParams
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the preferred min and max connection intervals to advertise.
|
||||||
|
* @param [in] minInterval The minimum preferred connection interval.
|
||||||
|
* @param [in] maxInterval The Maximum preferred connection interval.
|
||||||
|
* @details Range = 0x0006(7.5ms) to 0x0C80(4000ms), values not within the range will be limited to this range.
|
||||||
|
*/
|
||||||
|
bool NimBLEAdvertisementData::setPreferredConnectionInterval(uint16_t minInterval, uint16_t maxInterval) {
|
||||||
|
/*
|
||||||
|
if (!minInterval) {
|
||||||
|
minInterval = *reinterpret_cast<const uint16_t*>(m_advData.slave_itvl_range);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!maxInterval) {
|
||||||
|
maxInterval = *reinterpret_cast<const uint16_t*>(m_advData.slave_itvl_range + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
minInterval = std::max<uint16_t>(minInterval, 0x6);
|
||||||
|
minInterval = std::min<uint16_t>(minInterval, 0xC80);
|
||||||
|
maxInterval = std::max<uint16_t>(maxInterval, 0x6);
|
||||||
|
maxInterval = std::min<uint16_t>(maxInterval, 0xC80);
|
||||||
|
maxInterval = std::max<uint16_t>(maxInterval, minInterval); // Max must be greater than or equal to min.
|
||||||
|
|
||||||
|
m_slaveItvl[0] = minInterval;
|
||||||
|
m_slaveItvl[1] = minInterval >> 8;
|
||||||
|
m_slaveItvl[2] = maxInterval;
|
||||||
|
m_slaveItvl[3] = maxInterval >> 8;
|
||||||
|
*/
|
||||||
|
return true;
|
||||||
|
} // setPreferredConnectionInterval
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the location of the data in the payload.
|
||||||
|
* @param [in] type The type of data to search for.
|
||||||
|
* @return The index of the data in the payload.
|
||||||
|
* @return -1 if the data is not found, otherwise the index of the data in the payload.
|
||||||
|
*/
|
||||||
|
int NimBLEAdvertisementData::getDataLocation(uint8_t type) const {
|
||||||
|
int index = 0;
|
||||||
|
while (index < m_payload.size()) {
|
||||||
|
if (m_payload[index + 1] == type) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
index += m_payload[index] + 1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieve the payload that is to be advertised.
|
* @brief Retrieve the payload that is to be advertised.
|
||||||
* @return The payload that is to be advertised.
|
* @return The payload that is to be advertised.
|
||||||
|
|
|
@ -42,56 +42,78 @@ class NimBLEAdvertising;
|
||||||
typedef std::function<void(NimBLEAdvertising*)> advCompleteCB_t;
|
typedef std::function<void(NimBLEAdvertising*)> advCompleteCB_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Advertisement data set by the programmer to be published by the %BLE server.
|
* @brief Advertisement data set by the programmer to be published by the BLE server.
|
||||||
*/
|
*/
|
||||||
class NimBLEAdvertisementData {
|
class NimBLEAdvertisementData {
|
||||||
// Only a subset of the possible BLE architected advertisement fields are currently exposed. Others will
|
// Only a subset of the possible BLE architected advertisement fields are currently exposed. Others will
|
||||||
// be exposed on demand/request or as time permits.
|
// be exposed on demand/request or as time permits.
|
||||||
//
|
//
|
||||||
public:
|
public:
|
||||||
void setAppearance(uint16_t appearance);
|
NimBLEAdvertisementData() : m_payload({31, 0}) {} // Reserve space for the maximum payload size.
|
||||||
void setCompleteServices(const NimBLEUUID& uuid);
|
|
||||||
void setCompleteServices16(const std::vector<NimBLEUUID>& uuids);
|
bool setAppearance(uint16_t appearance);
|
||||||
void setCompleteServices32(const std::vector<NimBLEUUID>& uuids);
|
bool setCompleteServices(const NimBLEUUID& uuid);
|
||||||
void setFlags(uint8_t);
|
bool setCompleteServices16(const std::vector<NimBLEUUID>& uuids);
|
||||||
void setManufacturerData(const std::string& data);
|
bool setCompleteServices32(const std::vector<NimBLEUUID>& uuids);
|
||||||
void setManufacturerData(const std::vector<uint8_t>& data);
|
bool addServiceUUID(const NimBLEUUID& serviceUUID);
|
||||||
void setURI(const std::string& uri);
|
bool addServiceUUID(const char* serviceUUID);
|
||||||
void setName(const std::string& name, bool isComplete = true);
|
bool removeServiceUUID(const NimBLEUUID& serviceUUID);
|
||||||
void setPartialServices(const NimBLEUUID& uuid);
|
bool removeServices();
|
||||||
void setPartialServices16(const std::vector<NimBLEUUID>& uuids);
|
bool setFlags(uint8_t);
|
||||||
void setPartialServices32(const std::vector<NimBLEUUID>& uuids);
|
bool setManufacturerData(const uint8_t* data, size_t length);
|
||||||
void setServiceData(const NimBLEUUID& uuid, const std::string& data);
|
bool setManufacturerData(const std::string& data);
|
||||||
void setShortName(const std::string& name);
|
bool setManufacturerData(const std::vector<uint8_t>& data);
|
||||||
void addData(const uint8_t* data, size_t length);
|
bool setURI(const std::string& uri);
|
||||||
void addData(const std::vector<uint8_t>& data);
|
bool setName(const std::string& name, bool isComplete = true);
|
||||||
void addTxPower();
|
bool setPartialServices(const NimBLEUUID& uuid);
|
||||||
void setPreferredParams(uint16_t min, uint16_t max);
|
bool setPartialServices16(const std::vector<NimBLEUUID>& uuids);
|
||||||
|
bool setPartialServices32(const std::vector<NimBLEUUID>& uuids);
|
||||||
|
bool setServiceData(const NimBLEUUID& uuid, const uint8_t* data, size_t length);
|
||||||
|
bool setServiceData(const NimBLEUUID& uuid, const std::string& data);
|
||||||
|
bool setServiceData(const NimBLEUUID& uuid, const std::vector<uint8_t>& data);
|
||||||
|
bool setShortName(const std::string& name);
|
||||||
|
bool addTxPower();
|
||||||
|
bool setPreferredParams(uint16_t min, uint16_t max);
|
||||||
|
bool setPreferredConnectionInterval(uint16_t minInterval, uint16_t maxInterval);
|
||||||
|
bool addData(const uint8_t* data, size_t length);
|
||||||
|
bool addData(const std::vector<uint8_t>& data);
|
||||||
void clearData();
|
void clearData();
|
||||||
|
|
||||||
|
int getDataLocation(uint8_t type) const;
|
||||||
std::vector<uint8_t> getPayload() const;
|
std::vector<uint8_t> getPayload() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class NimBLEAdvertising;
|
friend class NimBLEAdvertising;
|
||||||
void setServices(bool complete, uint8_t size, const std::vector<NimBLEUUID>& v_uuid);
|
|
||||||
std::vector<uint8_t> m_payload; // The payload of the advertisement.
|
bool setServices(bool complete, uint8_t size, const std::vector<NimBLEUUID>& v_uuid);
|
||||||
|
std::vector<uint8_t> m_payload;
|
||||||
}; // NimBLEAdvertisementData
|
}; // NimBLEAdvertisementData
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Perform and manage %BLE advertising.
|
* @brief Perform and manage BLE advertising.
|
||||||
*
|
*
|
||||||
* A %BLE server will want to perform advertising in order to make itself known to %BLE clients.
|
* A BLE server will want to perform advertising in order to make itself known to BLE clients.
|
||||||
*/
|
*/
|
||||||
class NimBLEAdvertising {
|
class NimBLEAdvertising {
|
||||||
public:
|
public:
|
||||||
NimBLEAdvertising();
|
NimBLEAdvertising();
|
||||||
|
bool start(uint32_t duration = 0, const NimBLEAddress* dirAddr = nullptr);
|
||||||
|
void setAdvertisingCompleteCallback(advCompleteCB_t callback);
|
||||||
|
bool stop();
|
||||||
|
void setConnectableMode(uint8_t mode);
|
||||||
|
void setDiscoverableMode(uint8_t mode);
|
||||||
|
bool reset();
|
||||||
|
bool isAdvertising();
|
||||||
|
void setAdvertisingInterval(uint16_t interval);
|
||||||
|
void setAdvertisementData(const NimBLEAdvertisementData& advertisementData);
|
||||||
|
void setScanResponseData(const NimBLEAdvertisementData& advertisementData);
|
||||||
|
void setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly);
|
||||||
|
void setScanResponse(bool enable);
|
||||||
|
|
||||||
void addServiceUUID(const NimBLEUUID& serviceUUID);
|
void addServiceUUID(const NimBLEUUID& serviceUUID);
|
||||||
void addServiceUUID(const char* serviceUUID);
|
void addServiceUUID(const char* serviceUUID);
|
||||||
void removeServiceUUID(const NimBLEUUID& serviceUUID);
|
void removeServiceUUID(const NimBLEUUID& serviceUUID);
|
||||||
bool start(uint32_t duration = 0, const NimBLEAddress* dirAddr = nullptr);
|
|
||||||
void setAdvertisingCompleteCallback(advCompleteCB_t callback);
|
|
||||||
void removeServices();
|
void removeServices();
|
||||||
bool stop();
|
|
||||||
void setAppearance(uint16_t appearance);
|
void setAppearance(uint16_t appearance);
|
||||||
void setName(const std::string& name);
|
void setName(const std::string& name);
|
||||||
void setManufacturerData(const uint8_t* data, size_t length);
|
void setManufacturerData(const uint8_t* data, size_t length);
|
||||||
|
@ -100,22 +122,13 @@ class NimBLEAdvertising {
|
||||||
void setURI(const std::string& uri);
|
void setURI(const std::string& uri);
|
||||||
void setServiceData(const NimBLEUUID& uuid, const uint8_t* data, size_t length);
|
void setServiceData(const NimBLEUUID& uuid, const uint8_t* data, size_t length);
|
||||||
void setServiceData(const NimBLEUUID& uuid, const std::string& data);
|
void setServiceData(const NimBLEUUID& uuid, const std::string& data);
|
||||||
void setConnectableMode(uint8_t mode);
|
|
||||||
void setDiscoverableMode(uint8_t mode);
|
|
||||||
void setServiceData(const NimBLEUUID& uuid, const std::vector<uint8_t>& data);
|
void setServiceData(const NimBLEUUID& uuid, const std::vector<uint8_t>& data);
|
||||||
void setAdvertisingInterval(uint16_t interval);
|
|
||||||
void setMaxInterval(uint16_t maxInterval);
|
void setMaxInterval(uint16_t maxInterval);
|
||||||
void setMinInterval(uint16_t minInterval);
|
void setMinInterval(uint16_t minInterval);
|
||||||
void setAdvertisementData(const NimBLEAdvertisementData& advertisementData);
|
|
||||||
void setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly);
|
|
||||||
void setScanResponseData(const NimBLEAdvertisementData& advertisementData);
|
|
||||||
void setScanResponse(bool enable);
|
|
||||||
void setPreferredConnectionInterval(uint16_t minInterval, uint16_t maxInterval);
|
void setPreferredConnectionInterval(uint16_t minInterval, uint16_t maxInterval);
|
||||||
void setMinPreferred(uint16_t min);
|
void setMinPreferred(uint16_t min);
|
||||||
void setMaxPreferred(uint16_t max);
|
void setMaxPreferred(uint16_t max);
|
||||||
void addTxPower();
|
void addTxPower();
|
||||||
bool reset();
|
|
||||||
bool isAdvertising();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class NimBLEDevice;
|
friend class NimBLEDevice;
|
||||||
|
@ -124,23 +137,16 @@ class NimBLEAdvertising {
|
||||||
void onHostSync();
|
void onHostSync();
|
||||||
static int handleGapEvent(ble_gap_event* event, void* arg);
|
static int handleGapEvent(ble_gap_event* event, void* arg);
|
||||||
|
|
||||||
ble_hs_adv_fields m_advData;
|
NimBLEAdvertisementData m_advData;
|
||||||
ble_hs_adv_fields m_scanData;
|
NimBLEAdvertisementData m_scanData;
|
||||||
ble_gap_adv_params m_advParams;
|
ble_gap_adv_params m_advParams;
|
||||||
std::vector<NimBLEUUID> m_serviceUUIDs;
|
|
||||||
bool m_customAdvData;
|
|
||||||
bool m_customScanResponseData;
|
|
||||||
bool m_scanResp;
|
|
||||||
bool m_advDataSet;
|
|
||||||
advCompleteCB_t m_advCompCb;
|
advCompleteCB_t m_advCompCb;
|
||||||
uint8_t m_slaveItvl[4];
|
uint8_t m_slaveItvl[4];
|
||||||
uint32_t m_duration;
|
uint32_t m_duration;
|
||||||
std::vector<uint8_t> m_svcData16;
|
bool m_customAdvData : 1;
|
||||||
std::vector<uint8_t> m_svcData32;
|
bool m_customScanResponseData : 1;
|
||||||
std::vector<uint8_t> m_svcData128;
|
bool m_scanResp : 1;
|
||||||
std::vector<uint8_t> m_name;
|
bool m_advDataSet : 1;
|
||||||
std::vector<uint8_t> m_mfgData;
|
|
||||||
std::vector<uint8_t> m_uri;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && !CONFIG_BT_NIMBLE_EXT_ADV */
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && !CONFIG_BT_NIMBLE_EXT_ADV */
|
||||||
|
|
Loading…
Reference in a new issue