NimBLE-Arduino
NimBLE-Arduino copied to clipboard
When two services are added only first is visible (advertises)
Used two arduino platformio libraries:
https://github.com/vovagorodok/ArduinoBleChess
https://github.com/vovagorodok/ArduinoBleOTA
Like:
inline void initBle(const std::string &deviceName)
{
BLEDevice::init(deviceName);
}
inline void advertizeBle()
{
auto* server = BLEDevice::createServer();
auto* advertising = server->getAdvertising();
advertising->setScanResponse(true);
advertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
advertising->setMaxPreferred(0x12);
if (not advertising->start())
LOG_ERROR << "Ble advertising error";
}
void setup()
{
initBle(DEVICE_NAME);
if (not ArduinoBleChess.begin(peripheral))
LOG_ERROR << "Ble chess initialization error";
if (not ArduinoBleOTA.begin(InternalStorage))
LOG_ERROR << "Ble ota initialization error";
advertizeBle();
}
Where:
bool ArduinoBleChessClass::begin(BleChessPeripheral& peripheral)
{
auto* server = BLEDevice::createServer();
bleChessConnection.registerPeripheral(peripheral);
server->setCallbacks(this);
auto* service = server->createService(CHESS_SERVICE_UUID);
auto* rxCharacteristic = service->createCharacteristic(
CHESS_CHARACTERISTIC_UUID_RX,
NIMBLE_PROPERTY::WRITE
);
rxCharacteristic->setCallbacks(this);
auto* txCharacteristic = service->createCharacteristic(
CHESS_CHARACTERISTIC_UUID_TX,
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY
);
this->txCharacteristic = txCharacteristic;
auto* advertising = server->getAdvertising();
advertising->addServiceUUID(CHESS_SERVICE_UUID);
return service->start();
}
bool ArduinoBleOTAClass::begin(OTAStorage& storage)
{
auto* server = BLEDevice::createServer();
BLEDevice::setMTU(BLE_OTA_MTU_SIZE);
bleOtaUploader.begin(storage);
auto* service = server->createService(OTA_SERVICE_UUID);
auto* rxCharacteristic = service->createCharacteristic(
OTA_CHARACTERISTIC_UUID_RX,
NIMBLE_PROPERTY::WRITE_NR
);
rxCharacteristic->setCallbacks(this);
auto* txCharacteristic = service->createCharacteristic(
OTA_CHARACTERISTIC_UUID_TX,
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY
);
this->txCharacteristic = txCharacteristic;
auto* advertising = server->getAdvertising();
advertising->addServiceUUID(OTA_SERVICE_UUID);
return service->start();
}
Only first service is visible:
When I change the order of initialization, than only second service is visible
All return service->start();
returns true
. No error logs
After connect both services are visible. Something with advertising?
There is only room for one 128bit uuid in the advertisement. The current code does not create a second instance of a service uuid list in the scan response using those methods.
You should be able to accomplish this by using the advertisement data class and setting the advertisement and scan response data with that.
Have you an example for that?
The iBeacon example shows the use of this.
https://github.com/h2zero/NimBLE-Arduino/blob/release/1.4/examples/Refactored_original_examples/BLE_iBeacon/BLE_iBeacon.ino
Trying something like:
inline void advertizeBle(const std::string &deviceName)
{
auto* server = BLEDevice::createServer();
auto* advertising = server->getAdvertising();
NimBLEAdvertisementData advertisementData{};
advertisementData.setName(deviceName);
// advertisementData.addTxPower();
advertisementData.setFlags(BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP);
advertisementData.setCompleteServices(NimBLEUUID(CHESS_SERVICE_UUID));
advertisementData.setCompleteServices(NimBLEUUID(OTA_SERVICE_UUID));
advertising->setAdvertisementData(advertisementData);
advertising->setScanResponseData(advertisementData);
// advertising->setScanResponse(true);
advertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
advertising->setMaxPreferred(0x12);
if (not advertising->start())
LOG_ERROR << "Ble advertising error";
}
But as I see can be added only one 128 uuid:
void NimBLEAdvertisementData::setCompleteServices(const NimBLEUUID &uuid) {
setServices(true, uuid.bitSize(), {uuid});
} // setCompleteServices
Its Bluetooth LE or library limit?
In nRF Connect I see doubled CHESS_SERVICE_UUID
You need to create 2 instances of advertisement data, one for the advertisement and the other for scan response. Each should have a different service uuid.
Changed to:
inline void advertizeBle(const std::string& deviceName)
{
auto* server = BLEDevice::createServer();
auto* advertising = server->getAdvertising();
NimBLEAdvertisementData chessAdvertisementData{};
NimBLEAdvertisementData otaAdvertisementData{};
otaAdvertisementData.setShortName(deviceName);
otaAdvertisementData.setFlags(BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP);
otaAdvertisementData.setCompleteServices(NimBLEUUID(OTA_SERVICE_UUID));
chessAdvertisementData.setShortName(deviceName);
chessAdvertisementData.setFlags(BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP);
chessAdvertisementData.setCompleteServices(NimBLEUUID(CHESS_SERVICE_UUID));
advertising->setAdvertisementData(otaAdvertisementData);
advertising->setScanResponseData(chessAdvertisementData);
// advertising->setScanResponse(true);
advertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
advertising->setMaxPreferred(0x12);
if (not advertising->start())
LOG_ERROR << "Ble advertising error";
}
In nRF Connect I see that uuis are removed from advertising data. Looks that no enough space for two 128 uuids and name and flags. When I left only two 128 uuids and flags only for otaAdvertisementData it works. Adding even deviceName removes uuids. Any possibility to increase that space or it limited by Bloetooth LE?
Decided to add: first 128bit uuid + name (max 11 chars) to AdvertisementData and second 128bit uuid + flags to ResponseData. From BLE documentation I see that each AdvertisementData can be max 31 bytes size.
- Can I somehow concatenate this two blocks to one 62bytes i order to place larger names? Beacons do that?
- Should be added something else to this datas in order to have correct work?
- About this lines:
advertising->setScanResponse(true);
advertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
advertising->setMaxPreferred(0x12);
How they should be handled in this case?
Standard convention would be to have the flags and main uuid in the advertisement, then the name and secondary data in the scan response.
Can I somehow concatenate this two blocks to one 62bytes i order to place larger names? Beacons do that?
This is not possible, the 2 data sets are completely separate.
advertising->setMinPreferred(0x06); // functions that help with iPhone connections issue advertising->setMaxPreferred(0x12);
These can be removed to save space, I haven't experienced any negative consequences in doing so.
Like that?:
constexpr auto MAX_ADVERTISEMENT_DATA_SIZE = 31;
constexpr auto UUID_128_BIT_SIZE = 16;
constexpr auto LENGTH_AND_TYPE_BYTES_SIZE = 2;
constexpr auto TOTAL_OVERHEAD = UUID_128_BIT_SIZE + LENGTH_AND_TYPE_BYTES_SIZE * 2;
constexpr auto MAX_NAME_SIZE = MAX_ADVERTISEMENT_DATA_SIZE - TOTAL_OVERHEAD;
inline bool advertizeBle(const std::string& deviceName,
const std::string& primaryUUID,
const std::string& secondaryUUID)
{
if (deviceName.size() > MAX_NAME_SIZE)
return false;
auto* server = BLEDevice::createServer();
auto* advertising = server->getAdvertising();
NimBLEAdvertisementData primaryAdvertisementData{};
primaryAdvertisementData.setFlags(BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP);
primaryAdvertisementData.setCompleteServices(NimBLEUUID(primaryUUID));
advertising->setAdvertisementData(primaryAdvertisementData);
NimBLEAdvertisementData secondaryAdvertisementData{};
secondaryAdvertisementData.setShortName(deviceName);
secondaryAdvertisementData.setCompleteServices(NimBLEUUID(secondaryUUID));
advertising->setScanResponseData(secondaryAdvertisementData);
return advertising->start();
}
According, to:
advertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
advertising->setMaxPreferred(0x12);
It was in examples and I decided to add it everywhere. Should work with iPhone without this lines? I haven't iPhone to test that.
According, to:
advertising->setScanResponse(true);
Should stay added or remove?
Actually i think bluetooth specs allows to "merge" advertising and scan response, but i never been trying it. You can try to build long advertising packet, up to 62 bytes, then split it and use as a raw data.
Actually i think bluetooth specs allows to "merge" advertising and scan response, but i never been trying it. You can try to build long advertising packet, up to 62 bytes, then split it and use as a raw data.
Hmm. Good idea to just try it :) There no possibility to simply do it. Should be created NimBLEAdvertisementData
like class for that. 11 bytes name for me is enough for this moment. I think i'll back to this experiment in future.
According to advertizeBle()
function and questions below. All looks ok? I'll add this function and update multiservice examples in my libraries
I'm not sure if that would be possible with NimBLE as the functions don't really allow for it.