[BlueNRG-2-Android] Source code troubleshooting, bonding and privacy

The objective of the firmware presented in this article is to provide an example which would implement the following functionality:

  • After resetting the BlueNRG-2 (called the “device” or simply BlueNRG later on) it would make itself general discoverable and accept a connection from whatever connects first.
  • It would bond with this first connecting thing (called the “cellphone” later on) and allow it to connect and modify GATT characteristics exclusively.
  • No other central device (cellphone) would be allowed to modify device’s characteristics (or even connect).
  • This BlueNRG device would work with modern iOS and Android phones (it’s 2018 when I’m writing this).

My starting point was an example from STSW-BLUENRG1-DK version 3.0.0 named BLE_Security which resides in BlueNRG-1_2-DK-3.0.0/Project/BLE_Examples/BLE_Security/src/peripheral directory. This package comes as an executable if  I remember correctly, but most of the ST’s execs run under wine (wine-3.6 (Ubuntu 3.6-1), Ubuntu version 18.04). So just after incorporating the example source code into my project I was able to pair, bond, connect and read characteristics on the BlueNRG-2 using nRF connect app running on Android 8 on Huawei Honor 9. The problem arisen though, when I tried to disconnect, and then connect again. In such case I would always get “GATT ERROR 0x85” in the nRF connect logs, and the only way to connect to the BlueNRG again was to reset it (it clears its security database, removing all bond information) and to remove bond information from the cellphone. After some time I posted a question on my ST forum, but not getting the answer I slowly figured out, that  there is problem with whitelist, because when I turned “undirected connectable” without whitelist, everything worked OK. Let me explain. In the file BlueNRG-1_2-DK-3.0.0/Project/BLE_Examples/BLE_Security/src/peripheral/BLE_Security_Peripheral.c there is Make_Connection function which at first turn general discoverable :

 ret = aci_gap_set_discoverable (ADV_IND, 0x100, 0x200, PUBLIC_ADDR, filter, sizeof (local_name), local_name, 0, NULL, 0, 0);

with filter ==NO_WHITE_LIST_USE and after bonding it turns undirected connectable like this :

 ret = aci_gap_set_undirected_connectable(0x100,0x200,PUBLIC_ADDR, filter);

with filter == WHITE_LIST_FOR_ALL. The way I see this problem is, that modern cellphones use random private resolvable addresses which can change anytime, so it may happen that the address BlueNRG has on its whitelist is out of date. The solution is to turn on the controller privacy (introduced in so called link layer privacy 1.2 in BLE 4.2) which would resolve addresses in the link layer tier thus allowing whitelisting. There’s more reliable sources on the topic, but the way I understand it is that [I may be wrong here] on the 3rd stage of bonding peripheral and central exchange IRKs between each other (along with other information) and thus the peer device identity is stored in the BlueNRG. This peer device identity consists of peer’s device identity address (the “real” address which can be public or static random), the local IRK and peer’s IRK. This information is then passed to the controller letting it to resolve random private resolvable addresses from the peer (cellphone) or to “randomize / hide” its own address. [/I may be wrong here]

To turn the controller privacy on I modified aci_gap_init as so:

ret = aci_gap_init (GAP_PERIPHERAL_ROLE, 0x02, sizeof (deviceName), &service_handle, &dev_name_char_handle, &appearance_char_handle);

but it retured error BLE_STATUS_INVALID_PARAMS. The same goes if I wanted to turn “LE secure connections” instead of “legacy pairing” where I got BLE_ERROR_UNSUPPORTED_FEATURE.It turned out that I needed to modify stack_user_cfg.h and turn appropriate options on :


In addition I added stack_user_cfg.c and libcrypto.a to the source base, and was able to go past the aci_gap_init call. Next I wanted to turn on the “LE secure connections” which where introduced in BLE 4.2. This is some fancy option which modifies the way the bonding process goes and introduces even more security, yay. I did:


and got BLE_STATUS_OUT_OF_MEMORY (0x48) when adding first (and only) custom GATT service. Turns out, that when SC is supported, there is another characteristic added to the Genaral Access service called Central Address Resolution characteristic. So I needed to fire the BLUENRG1_Wizard.exe and generate new header file with “privacy – controller” option turned on. This way ATT attributes number was increased by 1 and the out of memory error went away.

Next problem was that aci_gap_set_discoverable started to return BLE_STATUS_INVALID_PARAMS (0x42). It turns out, that when host or controller privacy is turned on, Own_Address_Type parameter can be only RESOLVABLE_PRIVATE_ADDR or NON_RESOLVABLE_PRIVATE_ADDR, and conversely when privacy is off, Own_Address_Type can be only PUBLIC_ADDR or STATIC_RANDOM_ADDR. So this way if you want the BlueNRG to resolve private resolvable addresses from the peer, you are also forced to use them on the NRG as well.

This way I was able to run the firmware without any errors, but my cellphone was unable to detect the device 99% of the time. It would occasionally detect it, but on very rare occasions. The problem was solved after… replacing 16MHz High Speed oscillator crystal with 32MHz one. I really do not know where this bug/feature is documented, but I myself found it in the Privacy_1_2_Slave_WhiteList.py script of the BlueNRG GUI application. After replacement I made a change so HS_SPEED_XTAL macro would preprocess to 1 and SYSCLK_FREQ to 32000000.

And the last problem I had, which took me almost 2 days to fix was caused by (I think) improper capabilities setup:

ret = aci_gap_set_io_capability (IO_CAP_NO_INPUT_NO_OUTPUT);

I wanted to bond using “Just Works” scheme, but this particular set of calls above made paring process behave very odd. I was able to scan for my device (still using nRF connect), and to bond (… -> bond), but it would not appear on the “bonded” list as it usually happened:

And although I could connect to such oddly bonded device and even reconnect to id multiple times, what I could not achieve was to reconnect after devices disconnected by themselves due to signal loss (i.e. when cellphone was carried away). In such case, when I brought my cellphone back and turned scanning on, my BlueNRG device would reappear in the “Scanned” list but with different address! Trying to connect to it would return GAT ERROR 0x3d in the nRF logs which means BLE_ERROR_CONNECTION_END_WITH_MIC_FAILURE (MIC is some little chunk of bytes added to the payload when privacy is turned on if I remember correctly). To fix this I had to do two things:

  • reset the phone and find out, that “Bonding” list in the nRF connect was all of a sudden populated with ten or so instances of my BlueNRG device made that day during some of the tests.

And then during pairing, I had to enter a PIN (123456), and after that I was able to do whatever I wanted, disconnect, go out of range, reconnect turn Bluetooth off and on, reset the phone and so on. All worked pretty fine.

Remarks / TODOs:

  • My peripheral’s (BlueNRG) name isn’t shown int the “Scanned” list in nRF connect, and I don’t know how to fix this.
  • I don’t know how to enable “Just Works” scheme.
  • Linux (Ubuntu 18.04) uses static random addresses, so the whole address resolving and privacy thing is not a problem.

3 comments for “[BlueNRG-2-Android] Source code troubleshooting, bonding and privacy

  1. Mariusz
    November 12, 2018 at 2:43 pm

    mam podobny problem z BluBRG1. Po sparowaniu układ działa poprawnie. Po rozłączeniu już nie mogę się połączyć. Program został napisany na podstawie BLE_Security ( DK 2.6.0 ).
    Pracuję z losowym kluczem DONOT_USE_FIXED_PIN_FOR_PAIRING
    Android 8.0
    Ponieważ mój angielski nie jest najlepszy jeśli to możliwe to proszę o jakąś wskazówkę co zmienić. Z góry dziękuję.
    Jeżeli jest funkcja aci_gatt_set_event_mask(uint32_t GATT_Evt_Mask) to funkcja odwrotna też jest ?


    • admin
      November 13, 2018 at 10:22 am


      Przede wszystkim proszę zupdejtować DK do najnowszej wersji (ja używałem 3.0.0). W 2.6.0 natrafiłem na poważny błąd, przez który nie można się było połączyć w niektórych przypadkach. No a dalej, to jak w artykule : problem z przykładem BLE_Security polega na tym, że jest włączona WHITELISTA, ale nie jest włączona prywatność. Kiedy telefon się bonduje z BlueNRG, BlueNRG zapamiętuje jego adres. Ale to jest adres random private resolvalbe address, i po krótkim czasie (możliwe, że zaraz po rozłączeniu) telefon go zmienia i stąd następna próba połączenia zawodzi. Tak to rozumiem. Więc albo należy wyłączyć whitelistę (dużo prościej), albo włączyć prywatność 1.2 (tę na kontrolerze). Z włączeniem prywatności jest trochę problemów, między innymi potrzebny jest kryształ 32MHz zamiast 16MHz.

      Niestety nie wiem jak pobrać event mask.

  2. RAF329
    August 24, 2019 at 3:03 pm

    Hi Lukasz Iwaszkiewicz!
    I have the same problem with BlueNRG-2 (own pcb, LS_SOURCE=LS_SOURCE_INTERNAL_RO and external 32Mhz ) in BLE Security Peripheral example.
    In IAR Tereminal IO a have next notes:

    ic Address: 0xa1 0x12 0x94 0xe1 0x80 0x02
    aci_gatt_init() –> SUCCESS
    aci_gap_init(PERIPHERAL, device name lenght: 11) –> SUCCESS
    aci_gatt_update_char_value_ext() –> SUCCESS
    aci_gap_clear_security_db() –> SUCCESS
    aci_gap_set_io_capability(0) –> SUCCESS
    aci_gap_set_authentication_requirement() –> SUCCESS
    Device Service added.
    TX Char Handle 000D, RX Char Handle 0010
    Add_Service() –> SUCCESS
    BlueNRG-1 BLE Security Peripheral Application (version: 1.0.0, security mode: PassKey Fixed Pin; button: 0)
    aci_gap_set_discoverable() OK
    Device Connected: do aci_gap_slave_security_req() –> SUCCESS

    Connected with: Address_Type: RANDOM Address: 0x39 0xe6 0x8f 0xe4 0x5e 0x55
    Disconnection, Reason: 0x3e

    In ble_status.h this error –

    In nRF Connect i have the error 0x85: GATT ERROR.

    If i write 0 in function Make_Connection(0);//advertising_filter – this problem not go away.

    Thank you for you great note about this problem!!!

Leave a Reply

Your email address will not be published. Required fields are marked *