Hello,
I have a question about pairing a nrf52480 board with an android phone. So my current code seems to seems to initiated the pairing and i do get prompted from my phone to select Pair / Cancel, but immediately after that the board prints out error 0x88 (“Unspecified reason“) at pairing result. Now for my use case i don’t require any encryption at all and just need to have the device paired.
Before I started writing in c++, I tried pairing with my phone using circuit python as a POC which was successful.
I am pretty new to BLE on embedded so if there is any additional information i can give please let me know.
Here is my rough current state of code for BLE:
#include <bluetooth.h>
#include <globals.h>
#include <display.h>
static const uint8_t SERVICE_UUID
= UUID_128_LE(
0x13,0x7c,0x44,0x35,
0x8a,0x64,
0x4b,0xcb,
0x93,0xf1,
0x37,0x92,0xc6,0xbd,0xc9,0x65
);
static const uint8_t PROTOCOL_NAME_UUID
= UUID_128_LE(
0x13,0x7c,0x44,0x35,
0x8a,0x64,
0x4b,0xcb,
0x93,0xf1,
0x37,0x92,0xc6,0xbd,0xc9,0x66
);
static const uint8_t COMMAND_UUID
= UUID_128_LE(
0x13,0x7c,0x44,0x35,
0x8a,0x64,
0x4b,0xcb,
0x93,0xf1,
0x37,0x92,0xc6,0xbd,0xc9,0x67
);
static const uint8_t LEG_UUID
= UUID_128_LE(
0x13,0x7c,0x44,0x35,
0x8a,0x64,
0x4b,0xcb,
0x93,0xf1,
0x37,0x92,0xc6,0xbd,0xc9,0x68
);
const char protocol_name
= “SAP6”;
GattCharacteristic protocol_char(
UUID(PROTOCOL_NAME_UUID),
(uint8_t*)protocol_name,
sizeof(protocol_name),
sizeof(protocol_name),
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
);
uint8_t command_value = 0;
GattCharacteristic command_char(
UUID(COMMAND_UUID),
&command_value,
sizeof(command_value),
sizeof(command_value),
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE |
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE,
nullptr
);
LegData leg_value = {0};
GattCharacteristic leg_char(
UUID(LEG_UUID),
(uint8_t*)&leg_value,
sizeof(LegData),
sizeof(LegData),
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ |
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY,
nullptr
);
events::EventQueue event_queue(10 * EVENTS_EVENT_SIZE);
BLE &caveble = BLE::Instance();
class MyGapEventHandler : public ble::Gap::EventHandler {
void onConnectionComplete(const ble::ConnectionCompleteEvent &event) override {
event_queue.call(
{
displayManager.drawMsg(“connected”);
});
}
void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &event) override {
caveble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
char msg[50];
snprintf(msg, sizeof(msg), "Disconnect reason: %d", event.getReason());
displayManager.drawMsg(msg);
}
};
class MySecurityEventHandler : public ble::SecurityManager::EventHandler {
void pairingRequest(ble::connection_handle_t connHandle) override {
caveble.securityManager().acceptPairingRequest(connHandle);
event_queue.call(
{
displayManager.drawMsg(“Accepting Pairing…”);
});
}
void confirmationRequest(ble::connection_handle_t connectionHandle) override {
caveble.securityManager().confirmationEntered(connectionHandle, true);
event_queue.call([]{
displayManager.drawMsg("Confirming");
});
}
void passkeyDisplay(ble::connection_handle_t connectionHandle, const SecurityManager::Passkey_t passkey) override {
char msg[50];
snprintf(msg, sizeof(msg), "Passkey: %s\n", passkey);
displayManager.drawMsg(msg);
}
void pairingResult(ble::connection_handle_t connectionHandle, SecurityManager::SecurityCompletionStatus_t status) override {
if (status == SecurityManager::SEC_STATUS_SUCCESS) {
displayManager.drawMsg("Pairing successful");
} else {
char msg[50];
snprintf(msg, sizeof(msg), "Pairing failed with status %u", status);
displayManager.drawMsg(msg);
}
}
};
/* ============================================================
GATT SERVER DEMO
============================================================ */
class GattServerDemo : public ble::GattServer::EventHandler {
static const uint16_t EXAMPLE_SERVICE_UUID = 0xA000;
static const uint16_t WRITABLE_CHARACTERISTIC_UUID = 0xA001;
public:
GattServerDemo()
: _characteristic_value(0),
_writable_characteristic(
WRITABLE_CHARACTERISTIC_UUID,
&_characteristic_value
)
{
}
void start()
{
GattCharacteristic* chars[] = {
&protocol_char,
&command_char,
&leg_char
};
GattService vendor_service(
UUID(SERVICE_UUID),
chars,
sizeof(chars) / sizeof(chars[0])
);
caveble.gattServer().addService(vendor_service);
caveble.gattServer().setEventHandler(this);
}
private:
virtual void onDataWritten(const GattWriteCallbackParams ¶ms) override
{
if ((params.handle == _writable_characteristic.getValueHandle()) &&
(params.len == 1)) {
}
}
uint8_t _characteristic_value;
ReadWriteGattCharacteristic<uint8_t> _writable_characteristic;
};
GattServerDemo demo;
/* ============================================================
BLE EVENT HANDLING
============================================================ */
void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context)
{
event_queue.call(mbed::callback(&caveble, &BLE::processEvents));
}
void start_advertising()
{
uint8_t adv_buffer[31];
ble::AdvertisingDataBuilder adv_builder(adv_buffer);
adv_builder.setFlags();
uint8_t scan_buffer[31];
ble::AdvertisingDataBuilder scan_builder(scan_buffer);
scan_builder.setName("SAP6_JP");
scan_builder.setTxPowerAdvertised(8);
caveble.gap().setAdvertisingPayload(
ble::LEGACY_ADVERTISING_HANDLE,
adv_builder.getAdvertisingData()
);
caveble.gap().setAdvertisingScanResponse(
ble::LEGACY_ADVERTISING_HANDLE,
scan_builder.getAdvertisingData()
);
caveble.gap().setAdvertisingParameters(
ble::LEGACY_ADVERTISING_HANDLE,
ble::AdvertisingParameters(
ble::advertising_type_t::CONNECTABLE_UNDIRECTED,
ble::adv_interval_t(ble::millisecond_t(500))
)
);
caveble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
}
void on_init_complete(BLE::InitializationCompleteCallbackContext *params)
{
if (params->error != BLE_ERROR_NONE) {
printf(“BLE init failed\r\n”);
return;
}
static MySecurityEventHandler sec_handler;
caveble.securityManager().setSecurityManagerEventHandler(&sec_handler);
caveble.securityManager().init(true, false, ble::SecurityManager::IO_CAPS_NONE, nullptr, false);
caveble.securityManager().allowLegacyPairing(true);
caveble.securityManager().setPairingRequestAuthorisation(true);
caveble.securityManager().preserveBondingStateOnReset(false);
static MyGapEventHandler gap_handler;
caveble.gap().setEventHandler(&gap_handler);
demo.start();
start_advertising();
}
rtos::Thread BLEThread(osPriorityNormal, 4096);
void BLETask(void);
void BLEBegin()
{
caveble.onEventsToProcess(schedule_ble_events);
BLEThread.start(BLETask);
event_queue.call([&]() { caveble.init(on_init_complete); });
btState = BtState::ADVERTISING;
}
void BLETask() {
event_queue.dispatch_forever();
}