Overview
In this lesson, we will examine how to support concurrent (simultaneous) BLE connections(links) and the different concurrency options offered by Nordic Semiconductor SoftDevices. Shed light on the Connection State Library of the nRF5 SDK used to manage simultaneous BLE links and get familiarized with the nRF5 SDK terminology used for concurrent connections. Then, in the exercise section, we will practice through hands-on exercises enabling multiple central devices to connect to the same peripheral at the same time( 1 Peripheral / N Centrals ), where N is limited by the SoftDevice used, and it is currently up 20. The multi-link capable peripheral includes the NUS service, enabling bidirectional communication channels between all central devices and the peripheral. We will also use the BLE concurrency to build BLE star networks in different configurations.
Introduction
As we have seen in Lesson4 , most SoftDevices support concurrent BLE connections(links). See tables below for the S100 series for both nRF52 and nRF51, to identify which SoftDevice support concurrent connections and how many devices can be connected concurrency (total Links).


For a device configured to be in a peripheral role, supporting concurrency means supporting multiple central devices concurrently. This is known in the nRF5 SDK terminology as NRF_SDH_BLE_PERIPHERAL_LINK_COUNT
, which is the maximum number of peripheral links a peripheral can offer. Take a look at the example below where the nRF5x board is acting as a BLE peripheral and it is supporting up to 4 central devices concurrently (NRF_SDH_BLE_PERIPHERAL_LINK_COUNT 4
).
In a different scenario, for a device configured to be in a central role, supporting concurrency means supporting multiple peripheral devices concurrently. This is known in the nRF5 SDK terminology as NRF_SDH_BLE_CENTRAL_LINK_COUNT
, which is the maximum number of central links a central can offer. Take a look at the example below where the nRF5x board is acting as a BLE central and it is supporting up to 4 peripheral devices concurrently (NRF_SDH_BLE_CENTRAL_LINK_COUNT 4
).
In yet another different scenario, for a device configured to be in both central and peripheral roles(multi-role), supporting concurrency could include supporting multiple central devices concurrently (NRF_SDH_BLE_PERIPHERAL_LINK_COUNT
) and/or supporting multiple peripheral devices concurrently (NRF_SDH_BLE_CENTRAL_LINK_COUNT
). Take a look at the example below where the nRF5x board is acting as both central and peripheral. It is supporting 2 central devices concurrently (NRF_SDH_BLE_PERIPHERAL_LINK_COUNT 2
) and supporting 2 peripheral devices concurrently (NRF_SDH_BLE_CENTRAL_LINK_COUNT 2
) . Therefore, the total links is the summation of both and is equal to 4 (NRF_SDH_BLE_TOTAL_LINK_COUNT 4
).
Note : In all cases, the total links which is given the identifier NRF_SDH_BLE_TOTAL_LINK_COUNT
is always the summation of NRF_SDH_BLE_PERIPHERAL_LINK_COUNT
and NRF_SDH_BLE_CENTRAL_LINK_COUNT
regardless of the role or the configuration.
NRF_SDH_BLE_TOTAL_LINK_COUNT
= NRF_SDH_BLE_PERIPHERAL_LINK_COUNT
+ NRF_SDH_BLE_CENTRAL_LINK_COUNT
Note : Only few SoftDevices support multi-role. See SoftDevice comparison tables and check the Roles row. All Roles means it support multi-role.
Connection State Library
The connection state library provides a set of user-friendly functions to manage concurrent connections(links). It supports both peripheral links and central links, and it keeps track of the states for the different connections. We will use this library to help us manage the different handles assigned for each connection. Keep in mind that when concurrency is supported, each connection will have a its own unique handle. It will also help us in knowing the current number of connected devices, we will see this in-depth in the exercise section of this lesson. This module stores certain states for each connection, which can be queried by connection handle.
Keep in mind that a connection handle is a 16-bits value that uniquely identifies each connection. If the nRF5x SoC is connected to one peer device, we would have only one connection handle and it is assigned the value of zero. On the other hand, if the nRF5x SoC is connected to four peer devices, we would have four connection handles and they are assigned the values of 0, 1, 2 and 3 respectively. The only special case is when the nRF5x SoC is not connected to any peer devices, in this case, querying about a connection handle would yield the value BLE_CONN_HANDLE_INVALID (65535‬) which in hex is 0xFFFF .
Below is the set of functions offered by the connection state library:

The library does not have any conditional compilation flags, so you don’t have to enable anything in sdk_config.h
. To use the library, simply import its implementation file into the project and include its header file. Both implementation file ble_conn_state.c
and header file ble_conn_state.h
for this library are stored in <nRF5 SDK Installation Path >components\ble\common
. More information on the library API can be found inside the header file or on Nordic Semiconductor infocenter.
Lesson 9 – Exercises
Exercise 1 – Supporting multiple central devices concurrently
In this exercise, we will take the peer-to-peer example of Lesson 5 Exercise 1 and make it support multiple central devices concurrently. In Lesson 5 Exercise 1, we had on one side, the nRF5x board acting as a peripheral implementing a NUS profile(server side); and on the other side, a Smart Phone/ tablet or a PC/laptop running nRF Connect and acting as a central. The firmware on the nRF5x board of Lesson5 – Exercise 1 allowed only one central device to be connected to the board at a time. See below illustration.
In this exercise, we will modify the firmware of the peripheral (the nRF5x board ) to make it support concurrent central devices (Up to 4). Keep in mind that since we are using the S140 SoftDevice on a nRF52840, we actually can support up to 20 central devices. However, to simplify the testing part, we will set NRF_SDH_BLE_PERIPHERAL_LINK_COUNT
, which is the maximum number of peripheral links a peripheral can offer to 4. See illustration below :
We will configure the firmware on the nRF5x board side such that when data is receive from device X, it will echo the data back to the same device. In addition to that, when Button 4 on the is pressed, all connected central devices will receive the message “Button 4 Pressed” .
Exercise Steps:
1. Make sure that nRF5 SDK version 17.0.2 is downloaded and extracted on your local driver.
2. Download the exercise base from (Enroll to the Intermediate course to access full content). This code is based on the Lesson5 – Exercise 1, except for some modifications to the comments and the advertised device name.
3. Open Segger Embedded Studio and double check that the nRF5SDK global macro is pointing to the right location where the nRF5 SDK is downloaded on your local disk. This can be done by checking Tools Menu -> Options -> Building -> Global Macros (nRF5SDK) and compare it to the root directory where the nRF5 SDK is downloaded . ( You will get all sort of files not found errors if the macro is not matching to where the nRF5 SDK is downloaded on your local machine!).
4. Increase the number of NRF_SDH_BLE_PERIPHERAL_LINK_COUNT
, which is the maximum number of peripheral links a peripheral can offer . This is done using the CMSIS Configuration Wizard or by directly modifying the sdk_config.h
as we have seen in previous lessons. Follow the screenshots below:
5. Supporting more links will increase the RAM usage of the SoftDevice, therefore, we need to adjust the linker macros to give more RAM memory to the SoftDevice and reduce the available memory to the application (“Our Code”). How much RAM is now needed by the SoftDevice? Fortunately, we have the handy debugging feature of the SoftDevice Handler Library function
nrf_sdh_ble_enable()
, which will tell us exactly how much RAM is needed for the SoftDeivce with the new settings, and how much RAM is left to the application.
5.1 Build the firmware as shown in the screenshot below.
5.2 Make sure that the board is connected and powered ON. Then, start a debugging session by clicking on Go from the Debug menu .
5.3 The debugging perspective of the Segger Embedded Studio will be activated, press on the Go button again.
5.4 Examine the Debug Console. Note that the firmware failed to start, simply because there were not enough RAM allocated to the SoftDevice with the new settings (Increased number of links). The error is NRF_ERROR_NO_MEM
and has a code of 4. Copy the new values suggested for the RAM_START
and the RAM_SIZE
linker macros somewhere (Notepad or some editor) . RAM_START
and RAM_SIZE
are highlighted in green in the screenshot below:
5.5 Close the debugging perspective.
5.6 Update the linker macros, then build the firmware, debug on the board to make sure that the error NRF_ERROR_NO_MEM
is resolved. Finally, close the debugging perspective as shown below:
With this, we have allocated enough RAM memory to the SoftDevice to support up to 4 simultaneous connections, and also updated the remaining RAM memory allocated to the application ( “Our code” ).
6. Modify the Queued Writes module to support concurrency.
6.1 Change the way the Queued Writes instance is created. Search(Ctrl + F) for STEP 6.1 in main.c
to identify the location where to do the changes.
Change the syntax from:
NRF_BLE_QWR_DEF(m_qwr);
To:
NRF_BLE_QWRS_DEF(m_qwr, NRF_SDH_BLE_TOTAL_LINK_COUNT);
6.2 Change the way the Queued Writes instance is initialized:
Change the syntax from:
err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
APP_ERROR_CHECK(err_code);
To:
for (uint32_t i = 0; i < NRF_SDH_BLE_TOTAL_LINK_COUNT; i++)
{
err_code = nrf_ble_qwr_init(&m_qwr[i], &qwr_init);
APP_ERROR_CHECK(err_code);
}
Copy from here .
Keep in mind that the Queued Write module is only truly needed when you plan to support Queued Write in one of the characteristic. Which is not the case of any of the current example characteristics.
7. Connection State Library preparations. The library implementation file and the path where its header is located have already been added to the project. What we still need to do is to include its header ble_conn_state.h
in main.c
and call the ble_conn_state_init()
function to initialize the Connection State Library.
7.1 Include the header file of the Connection State Library.
#include "ble_conn_state.h"
7.2 Call the function ble_conn_state_init()
to initialize the Connection State Library.
ble_conn_state_init();
After this point, we can use the rich set of user-friendly functions offered by the Connection State Library to manage simultaneous connections.
8. Delete the declaration of the m_conn_handle
variable, instead, we will always query either the Connection State Library or the BLE event received from the SoftDevice regarding the connection handle. In the old code, which does not support concurrency (Lesson5 – Exercise 1), we had only one connection and hence we had defined the connection handle as one global variable m_conn_handle
. The value of this variable could either be zero when in-connection or 0xFFFF when not-in-connection. With concurrency, this is no longer valid. Therefore, we will get rid of the global variable m_conn_handle
and always query either the Connection State Library or the BLE event received from the SoftDevice regarding the connection handle.
Delete the following line (Or comment it out).
static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID;
9. Modify the advertising scheme. In all the previous lessons, we used the Advertising Module (ble_advertising
) from the nRF5 SDK which simplifies the process of setting up the advertising, instead of issuing SoftDevice API directly. However, this simplification comes at the cost of reducing the amount of control we have over the advertisement phase. Therefore, for this exercise, we will use the SoftDevice API directly to have full control over the advertisement phase.
The advertising scheme that we will follow here is to keep the nRF5x board advertising as long as there is a connection link available, in other words, when not all the potential central devices are connected. Once four central devices are connected to the board, we will stop the advertisement. Through the advertising SoftDevice API, you can implement any desired scheme.
9.1 Remove the ble_advertising
module.
9.1.1 Remove ble_advertising
module implementation file as shown in the screenshot below:
9.1.2 Remove the
ble_advertising
header include.
Delete the following line(Or comment it out).
#include "ble_advertising.h"
9.1.3 Remove the call to the BLE_ADVERTISING_DEF()
macro which creates the ble_advertising
module instance.
9.1.4 Remove the handler function on_adv_evt()
of the ble_advertising
module. Search for STEP 9.1.4 in main.c
and remove(or comment it out) the function on_adv_evt()
Note that we will move the responsibility of blinking LED1 to indicate that the board is in advertising mode (bsp_indication_set(BSP_INDICATE_ADVERTISING);
) from the deleted handler function on_adv_evt()
to the advertising_start()
function in the following steps.
9.2 Add the following lines of code needed for initializing the advertising phase using the SoftDevice API directly.
static uint8_t m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; /**< Advertising handle used to identify an advertising set. */
static uint8_t m_enc_advdata[BLE_GAP_ADV_SET_DATA_SIZE_MAX]; /**< Buffer for storing an encoded advertising set. */
static uint8_t m_enc_scan_response_data[BLE_GAP_ADV_SET_DATA_SIZE_MAX]; /**< Buffer for storing an encoded scan data. */
/**@brief Struct that contains pointers to the encoded advertising data. */
static ble_gap_adv_data_t m_adv_data =
{
.adv_data =
{
.p_data = m_enc_advdata,
.len = BLE_GAP_ADV_SET_DATA_SIZE_MAX
},
.scan_rsp_data =
{
.p_data = m_enc_scan_response_data,
.len = BLE_GAP_ADV_SET_DATA_SIZE_MAX
}
};
Copy from here , locate STEP 9.2 in main.c
and paste the code .
9.3 Modify the advertising duration from 180 seconds to unlimited .
Change the macro definition APP_ADV_DURATION
From:
#define APP_ADV_DURATION 18000 /**< The advertising duration (180 seconds) in units of 10 milliseconds. */
To:
#define APP_ADV_DURATION BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED /**< Unlimited advertising in general discoverable mode */
Copy from here .
9.4 Modify the adverting initialization function advertising_init()
to use the SoftDevice API directly, instead of relying on the ble_advertising
module.
Copy from here and replace with the advertising_init()
in main.c
.
When it comes to the advertising data, both old advertising initialization code and new advertising initialization code have the same advertising data, except the flag field in the new configuration is set to General Discovery mode .General Discovery mode indicates that the peripheral is advertising for a long period of time (Longer Availability). Also notice that the new code is more verbose and requires setting more parameters. Below is a side-by-side comparison of the old advertising initialization code and the new advertising initialization code.

9.5 Modify the advertising_start()
function to use the SoftDevice API directly instead of using the ble_advertising
module
Change from this
static void advertising_start(void)
{
uint32_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
APP_ERROR_CHECK(err_code);
}
to this :
static void advertising_start(void)
{
uint32_t err_code = sd_ble_gap_adv_start(m_adv_handle, APP_BLE_CONN_CFG_TAG);
APP_ERROR_CHECK(err_code);
bsp_indication_set(BSP_INDICATE_ADVERTISING);
}
Copy from here .
Notice that in the new implementation of the advertising_start
we are calling the SoftDevice API directly, hence the sd_ble_gap_adv_start()
function starts with sd_
. In addition to that, the new advertising_start()
takes care of setting the LED1 blinking , this used to be taken care of by the removed ble_advertising
module handler.
10. Modify the application handler ble_evt_handler
to take into account the simultaneous connections and the fact that we will query either the Connection State Library or the BLE event received from the SoftDevice for the connection handle.
The new application handler will also take the responsibility of putting the status of LED1 to BSP_INDICATE_CONNECTED
which is (LED 1 is on ) to indicate that all the central devices are connected. The way the Queued Write module is assigned connection handlers is changed now to take into account the several connection handlers. The major change to the ble_evt_handler
is related to the following: Advertising is automatically stopped when the event BLE_GAP_EVT_CONNECTED
is received . In the previous code, the old application handler, which support only one single connection, that was actually the intended behavior. However, when supporting multiple links, we should not stop advertising after establishing the first connection, that is why we must restart advertising until the number of actually connected links is equal to the number of NRF_SDH_BLE_PERIPHERAL_LINK_COUNT
. In other words, all the central devices are connected. Take a look at the side-by-side comparison of the old application handler code and the new application handler code.

Copy the new application handler from here and replace the old one with it .
11. Change the way the Connection Parameters module handler on_conn_params_evt()
is written to query the event received regarding the connection handle. Instead of relying on the deprecated m_conn_handle
global variable.
12. Same concept applies for the handler function gatt_evt_handler()
of the GATT module.
Remove the reference to the deprecated m_conn_handle
in the GATT module handler function gatt_evt_handler()
, and substitute it with ble_conn_state_valid(p_evt->conn_handle)
.
Change from this :
void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt)
{
if ((m_conn_handle == p_evt->conn_handle) && (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED))
{
m_ble_nus_max_data_len = p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;
NRF_LOG_INFO("Data len is set to 0x%X(%d)", m_ble_nus_max_data_len, m_ble_nus_max_data_len);
}
NRF_LOG_DEBUG("ATT MTU exchange completed. central 0x%x peripheral 0x%x",
p_gatt->att_mtu_desired_central,
p_gatt->att_mtu_desired_periph);
}
To :
void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt)
{
if ((ble_conn_state_valid(p_evt->conn_handle)) && (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED))
{
m_ble_nus_max_data_len = p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;
NRF_LOG_INFO("Data len is set to 0x%X(%d)", m_ble_nus_max_data_len, m_ble_nus_max_data_len);
}
NRF_LOG_DEBUG("ATT MTU exchange completed. central 0x%x peripheral 0x%x",
p_gatt->att_mtu_desired_central,
p_gatt->att_mtu_desired_periph);
}
As shown below :
13. Change the bsp_event_handler()
handler function of the BSP module so that when button 4 is pressed, the message “Button 4 Pressed” is sent to all connected central devices.
In the old handler function for the BSP module of Lesson5-Exercise 1 , we supported the following two events :
Event: BSP_EVENT_DISCONNECT ( Long push to Button 1 ). Action: trigger a disconnect from the peer.
Event: BSP_EVENT_WHITELIST_OFF( Long push to Button 2 ). Action: reset the whitelist(not used) and restart advertising.
In the new handler function for the BSP module of Lesson9-Exercise 1, we will support only one event:
Event: BSP_EVENT_KEY_3 ( A regular push to Button 4) Action: Send the message “Button 4 Pressed” to all connected central devices.(Given that they enabled their notification CCCD).
Below is a side-by-side comparison of the old handler function of the BSP module of Lesson5-Exercise 1 and the new handler function of the BSP module of Lesson9-Exercise 1.

Pay attention to how we are obtaining the handles for all the connections in which the role of the local device (the nRF5x board) is acting as a peripheral through the call to the Connection State Library function ble_conn_state_periph_handles()
. The function returns a variable of type ble_conn_state_conn_handle_list_t
struct, which has two members: conn_handles
the list of the handles, and len
which holds the current length of the list (which also indicates the number of active peripheral links).

We will write a for loop that calls the NUS function ble_nus_data_send()
to send the data “Button 4 Pressed” to every handle in the conn_handles
list. Effectively sending the message “Button 4 Pressed” to all connected central devices. Copy the new handler function of the BSP module from here and replace the old one.
14. Add a prototype for the advertising_start()
function and define the MES_BUTTON4
string literal. Search for STEP 14 in main.c
and uncomment the following two lines.
static void advertising_start(void);
static uint8_t MES_BUTTON4[] = "Button 4 Pressed";
15. Modify the uart_event_handle()
handler function for the UART peripheral. Remember that Lesson5-Exercise1 is based on the nRF5 SDK peripheral example ble_app_uart
. In that example, data received through the UART “If anything is connected ” will be sent over BLE to the connected peer. We will revise the code such that : data received through the UART “If anything is connected ” will be sent over BLE to all connected central peers.
Copy the new implementation of the case APP_UART_DATA_READY
from here, which is the case of receiving data through the UART peripheral and replace the implementation as shown below:
Note: The way the uart_event_handle()
is currently written dictates that the data received over UART (If any), must be terminated by either ‘carriage return’ ‘\r’ (0x0D) or a ‘new line’ ‘\n’ (0x0A) for it to be sent over BLE to the peer central devices.
Note: Remember that the Debug Terminal is configured in sdk_config.h
to use the RTT backend, the RTT does not rely on the UART peripheral. The RTT uses the J-Link as its physical transport.
16. Finally, modify the NUS application handler nus_data_handler()
to echo back the received data. The old NUS application handler, logs the received data(Through RTT), and forward it to the UART peripheral. The new NUS application handler will do the same, in addition, it will echo back the data to the peer. Take a look at the side-by-side comparison below of the old NUS application handler code and the new NUS application handler.

Pay attention to how we are obtaining the number of connections in which the role of the local device (the nRF5x board) is acting as a peripheral through the call to the Connection State Library function ble_conn_state_peripheral_conn_count()
. The function returns a variable of type uint32_t
that represents how many peripherals links there is, in other words, the number of central devices connected to the nRF5x board.
Copy the code from here, and replace the old NUS application handler. with the new handler, when data is receive from device X, the nRF5x board will echo the data back to the same device.
With this we are done with the firmware modifications of the peripheral (the nRF5x board ) to make it support concurrent central devices (Up to 4). The next step is testing.
17. Build the firmware as shown in the screenshot below.
>>You can also download the solution file for here (Enroll to the Intermediate course to access full content).
Note for the solution file : Double check that the nRF5SDK global macro is pointing to the right location where the nRF5 SDK is downloaded on your local disk. This can be done by checking Tools Menu -> Options -> Building -> Global Macros (nRF5SDK) and compare it to the root directory where the nRF5 SDK is downloaded . ( You will get all sort of files not found errors if the macro is not matching to where the nRF5 SDK is downloaded on your local machine!). Check previous lessons for more info on how to run the solution files.
Exercise 1 Testing
In this test, we will establish four concurrent connections with the nRF5x board. Then, test each link by sending and receiving data back and forth between the nRF5x board and the central devices. We will also test how the nRF5x board can broadcast messages to all connected central devices. Note that in terms of network topology, we are creating a star network, where the nRF5x board is acting as the hub between all devices(nodes). Each node can talk to the hub, and also can talk to any other node in the network, but the data must pass through the hub.
18. Make sure that the board is connected and powered ON. Then, start a debugging session by clicking on Go from the Debug menu. The debugging perspective of the Segger Embedded Studio will be activated, press on the Go button again. As shown below:
Your nRF5x board is now in advertising with the name “Lesson9 – Exer1” . Advertising is also indicated by LED1 blinking. The board is set up in Step 9 to advertise indefinitely and it will only stop when 4 central devices are connected. Therefore, you will need at least four devices to act as a BLE central for this testing. Any BLE-supported device will do ( PC/Laptop or Smart Phone/ tablet running nRF Connect ). We will use a laptop using the nRF52840-Dongle as a BLE adapter (Covered in Lesson 3 ), two Android Smart Phone, and one IPad as the peer central devices. You can use any available BLE-supported devices.
19. Establish the first connection with the board. From a central device, scan and connect to “Lesson9 – Exer1”. Note that on the peripheral side the advertising will keep going. Then, send some data from the central device to the board, notice that the data is dumped on the RTT-enabled Debug Terminal. After that, Enable notification and send some data from the central device to the board, note that, in addition to dumping the data on the RTT-enabled Debug Terminal, the data will be echoed back to the central device. See the demo below where we used a laptop (using nRF52840-Dongle as a BLE adapter) as the first central device.
20. Basically, repeat the previous step using a different device. Establish the second connection with the nRF5x board. From a second central device, scan and connect to “Lesson9 – Exer1”. We are using an Android Smart Phone for the second device. You are free to use any available BLE-supported devices you have.
The Debug Terminal of the nRF5x board should log that a second device is connected and it should also log the MTU of the second connection. Note that you might have a different MTU value, this is depending on the device type and operating system running on the device.
Note that on the nRF5x board side the advertising will keep going (LED1 is still blinking), as we still did not use all available connections. So far, we have used 2 out of 4 available connections.
Send some data from the second central device to the nRF5x board.
Notice that the data is dumped on the RTT-enabled Debug Terminal of the nRF5x board.
Also, notice that the number of concurrently connected devices is 2.
After that, Enable notification on the second device.
Send some data from the second central device to the nRF5x board.
As expected, in addition to dumping the data on the RTT-enabled Debug Terminal of the nRF5x board, the data will be echoed back to the device .
Go back to your first central device and send some data, to validate that both connections are valid.
On the RTT-enabled Debug Terminal of the nRF5x board , you should observe that the data from the first central device is received as shown below:
This validates that both connections are valid and that you can send and receive data from both connections simultaneously.
In the next steps, we will establish the remaining two connections. Do NOT disconnect your first and second devices.
21. Establish the third connection. Same as before, from a third central device, scan and connect to “Lesson9 – Exer1”. We are using an Apple iPad for the third device. You are free to use any available BLE-supported devices you have.
The Debug Terminal of the nRF5x board should log that a third device is connected and it should also log the MTU of the second connection. Note that Apple iOS has a different MTU value than Android.
Also note that on the nRF5x board side, the advertising will keep going(LED1 is still blinking), as we still did not use all available connections. So far, we have used 3 out of 4 available connections.
Send some data from the third central device to the nRF5x board. The interface of the nRF Connect on iOS is different than the one on Android and the one on Laptop/PC, follow the screenshots below to locate how to access the peer device’s GATT structure:
Press on the little up arrow next to the RX characteristic to access the write to characteristic window.
Then, in the write to characteristic window, send some data to the nRF5x board in the desired format (Byte Array, Uint8, Bool, or UTF-8).
Notice that the data is dumped on the RTT-enabled Debug Terminal of the nRF5x board.
Also notice that the number of connected devices are 3.
After that, enable notification on the third device. This is done on the iPad by pressing on the three arrows facing done button next to the TX characteristic. It should turn blue indicating that it is enabled.
Again, send some data from the third central device to the nRF5x board.
As expected, in addition to dumping the data on the RTT-enabled Debug Terminal of the nRF5x board, the data will be echoed back to the device .
Go back to your first or second device and send some data, to validate that all connections are valid.
22. Establish the fourth connection. In the same fashion as the previous steps. From the fourth central device, scan and connect to “Lesson9 – Exer1”. We are using an Android Smart Phone for the fourth device. You are free to use any available BLE-supported devices you have.
The Debug Terminal of the nRF5x board should log that a fourth device is connected and it should also log the MTU of the fourth connection. Note you might have a different MTU value, this is depending on the device type and operating system running on the device.
Note that on the nRF5x board side, the advertising is STOPPED which is indicated by LED1 being ON (Not blinking). If you happen to have a fifth device and perform a BLE scan, you will not be able to find the nRF5x board “Lesson9 – Exer1 . The advertising is stopped because we used all four connections.
Send some data from the fourth central device to the nRF5x board as shown below:
Notice that the data is dumped on the RTT-enabled Debug Terminal of the nRF5x board.
Also, notice that the number of concurrently connected devices is 4.
After that, Enable notification on the fourth device and send some data from the fourth central device to the nRF5x board.
As expected, in addition to dumping the data on the RTT-enabled Debug Terminal of the nRF5x board, the data will be echoed back to the device .
Go back to your other central devices (1 , 2 and 3) and send some data, to validate that all connections are still valid.
23. Now we have four simultaneous connections with four different central devices established, Press Button 4 on the nRF5x board, all devices will receive the message “Button 4 Pressed” . Note that the central devices must have their notifications enabled for them to receive the message.
Something to keep in mind, if you disconnect any of the devices , the nRF5x board, as we set it in the firmware, will start advertising again. Advertising is stopped only when the total number of current simultaneous connections is equal to NRF_SDH_BLE_PERIPHERAL_LINK_COUNT
.
Exercise 2 – Star Network with Flooding
The purpose of this exercise is to demonstrate how simple it is now to configure the BLE star network developed in the previous exercise in any configuration desired. We will modify Exercise 1 code such that when the hub (the nRF5x board) receives a message from a node ( a device), It will forward that message to all the other nodes( aka: Flooding). For example, if Device 1 sends the message “Message from Device 1“, Device 2, Device 3, and Device 4 will receive that message, In addition to logging it. See illustration below :
Remember that in the previous exercise(Lesson9 – Exercise 1 ), the functionality was when a message is received from Device X , the message is echoed (sent back) to the same device.
On the other hand, in this exercise, when a message is received from Device X, it should be forwarded to all devices in the star network except Device X. The solution is very simple. All we have to do is to slightly modify the NUS application handler nus_data_handler()
to reflect the new configuration desired.
Exercise Steps:
1. Make sure that nRF5 SDK version 17.0.2 is downloaded and extracted on your local driver.
2. Download the exercise base from here (Enroll to the Intermediate course to access full content) . This code is identical to the Lesson9 – Exercise 1, except some modifications to the comments and the device name.
3. Open Segger and Double check that the nRF5SDK global macro is pointing to the right location where the nRF5 SDK is downloaded on your local disk. This can be done by checking Tools Menu -> Options -> Building -> Global Macros (nRF5SDK) and compare it to the root directory where the nRF5 SDK is downloaded . ( You will get all sort of files not found errors if the macro is not matching to where the nRF5 SDK is downloaded on your local machine!).
4. Modify the NUS application handler nus_data_handler()
to forward the received data to all devices, except the device sending the data.
Replace the nus_data_handler()
with the new NUS application handler here. Below is a side-by-side comparison of the old NUS application handler code and the new NUS application handler.

>>You can also download the solution file for (Enroll to the Intermediate course to access full content)
Note for the solution file : Double check that the nRF5SDK global macro is pointing to the right location where the nRF5 SDK is downloaded on your local disk. This can be done by checking Tools Menu -> Options -> Building -> Global Macros (nRF5SDK) and compare it to the root directory where the nRF5 SDK is downloaded . ( You will get all sort of files not found errors if the macro is not matching to where the nRF5 SDK is downloaded on your local machine!). Check previous lessons for more info on how to run the solution files.
Exercise 2 Testing
5. Build the firmware. Make sure that the board is connected and powered ON. Then, start a debugging session by clicking on Go in the Debug menu. The debugging perspective of the Segger Embedded Studio will be activated, press on the Go button again.
Now your board is advertising and ready to accept connections.
6. Connect four central devices in the same fashion as we did in the previous exercise. Make sure to enable notification in all of them, then send some data from any device, you should observe that the data is forwarded to all the other devices in the network. In the below demonstration, we first send data from device 1 -> 2, 3 and 4 . Then 4 -> 1,2,3 . Followed by 3->1,2,4. Finally 2->1,3,4.