Exercise 1

Connecting to your smartphone

In the last lesson, we started advertising with the Nordic board and then scanned for these advertisements with a phone. You were able to connect to the board via the nRF Connect for Mobile app, but nothing more happened.

In this exercise, we will establish a connection between your Nordic board, as a peripheral, and your smartphone, as a central. Then we will set up some callback functions, to be notified when the connection parameters are changed. Then we will add a temporary service to be able to send data through the established connection.

Exercise steps

In the GitHub repository for this course, go to the base code for this exercise, found in lesson3/blefund_less3_exer1.

You may notice that we are using the application you ended up with in the previous exercise (lesson 2 exercise 3) as the base code for this exercise.

1. Include the header file for handling connection events.

Start by adding the header file needed for handling our Bluetooth Low Energy connections. Add the following close to the top of your main.c

#include <zephyr/bluetooth/conn.h>

2. Set up callbacks to be triggered when a connection has been established or disconnected.

2.1 Declare a connection callback structure.

Let’s declare a structure called connection_callbacks of type bt_conn_cb.

This structure is used for tracking the state of the connection. For now, we will use the members connected and disconnected to track when a new connection has been established and when a connection has been disconnected. Take a look at the API documentation for a full list of all possible events.

Note

These events are different from the connection events we discussed in the previous topic, which cannot be seen by the application. These events are called connected callback events.

We will call our callbacks on_connected and on_disconnected.

Add the following lines to main.c

struct bt_conn_cb connection_callbacks = {
    .connected              = on_connected,
    .disconnected           = on_disconnected,
};

2.2 Define the callback functions on_connected and on_disconnected.

Because the callbacks are triggered from the Bluetooth libraries, it is important that they have the same function parameters as described in the documentation of the API linked above.

We will start with some simple callback functions that we can build on later. Add the following functions to your main.c

void on_connected(struct bt_conn *conn, uint8_t err)
{
    if (err) {
        LOG_ERR("Connection error %d", err);
        return;
    }
    LOG_INF("Connected");
    my_conn = bt_conn_ref(conn);

    /* STEP 3.2  Turn the connection status LED on */
}

void on_disconnected(struct bt_conn *conn, uint8_t reason)
{
    LOG_INF("Disconnected. Reason %d", reason);
    bt_conn_unref(my_conn);

    /* STEP 3.3  Turn the connection status LED off */
}

The my_conn parameter is just a bt_conn pointer that has been declared further up in the main.c file. We will use it to keep track of our connection in the next exercise.

2.3 Register the callback structure connection_callbacks.

Register the callback structure, using the function, bt_conn_cb_register. This needs to be called before we start advertising, to avoid a connection being established before we have registered the callback.

Add the following line in main.c

bt_conn_cb_register(&connection_callbacks);

Note

Note that in many of the Bluetooth Low Energy samples, you will not see bt_conn_cb_register() being used. Instead, they use the macro BT_CONN_CB_DEFINE(), which will both define and register these callbacks.

3. Configure an LED to indicate the current connection status.

3.1 Define the connection status LED

Add the following line close to the top of your main.c

#define CONNECTION_STATUS_LED   DK_LED2

3.2 On a connected event, turn the connection status LED on.

In the callback function for the connected event, on_connected(), add the following line to turn the LED on

dk_set_led(CONNECTION_STATUS_LED, 1);

3.3 On a disconnected event, turn the connection status LED off.

In the callback function for the disconnected event, on_disconnected(), add the following line to turn the LED off

dk_set_led(CONNECTION_STATUS_LED, 0);

4. Build and flash the application to your board.

5. Open a terminal to see the log output from the application.

Just like we did in lesson 1, connect to the COM port of your DK in VS Code by expanding your device under Connected Devices and selecting the COM port for the device. The number for the COM port may differ on your PC.

Note

When using the nRF5340 DK, you will have two COM ports, one for the application core and one for the network core. We want to view the output from the application core.

Use the default settings 115200 8n1 rtscrs:off. Then reset the device to see the full log message.

Restart the device to see the full log output. At this point, you should be seeing the following log output

*** Booting Zephyr OS build v3.1.99-ncs1-1 ***
[00:00:00.004,302] <inf> Lesson3_Exercise1: Starting Lesson 3 - Exercise 1
[00:00:00.007,659] <inf> Lesson3_Exercise1: Bluetooth initialized
[00:00:00.008,605] <inf> Lesson3_Exercise1: Advertising successfully started

6. Use your smartphone to scan and connect to your board.

As we have done in previous exercises, use the nRF Connect for Mobile app the scan for devices. Connect to your device, called “Nordic_Peripheral“, by selecting Connect next to the name. This will also open a new window with a lot of tabs, but we will focus on what happens on the board for now.

Notice that the LED on your board indicates a connection, and you should also be seeing the following log output

This means that we are now in the connected state. The phone, acting as a central, picked up the advertising packets from the nRF device, which is the peripheral in this connection.

Important

If you are using iOS, you will also see the following warning lines in the log after the connected event, that can be ignored.

7. Disconnect the device from your smartphone

Let’s disconnect from the peripheral, by clicking the “Disconnect” button in the upper right-hand corner.

You should see the following log output

The error codes are defined in the Bluetooth specification, and can indicate why the connection was terminated.

If you open the file hci_err.h, you can see that 19, which is written 0x13 in hexadecimal refers to BT_HCI_ERR_REMOTE_USER_TERM_CONN, which means that the remote user terminated the connection. If we do the test again, but instead of disconnecting from the app, we take the phone far away from the device, we should see that the disconnect reason is 8. This is BT_HCI_ERR_CONN_TIMEOUT, which means that we just saw a supervision timeout occur.

At this point, we want to be able to send some data between the peripheral and the central. To do this, we need to add a service to our application. We will be adding the LED Button Service to the application.

More on this

We will cover Bluetooth LE services and sending data in more detail in lesson 4. For now, it is only relevant to know that this function sends data to the connected device.

8. Change the application to send a message whenever button 1 is pressed.

We want to send some data whenever button 1 is pressed, and to be able to do this we need to add the LED Button Service (LBS).

8.1. Include the LBS in the application.

Start by adding this line to your prj.conf.

The first line will set up the service, while the other just says that it is possible to manually read the value. We will not do this, but we will later use an app that requires this setting to be set.

8.2 Include the LED Button Service header file near the top of your main.c.

#include <bluetooth/services/lbs.h>

8.3 Add a callback to be notified when button 1 is pressed.

We want to send the button state of button 1 to the central device (your phone) whenever button 1 on the device is pressed.

Add the button_changed() callback in your main.c:

static void button_changed(uint32_t button_state, uint32_t has_changed)
{
    int err;
    if (has_changed & USER_BUTTON) {
        LOG_INF("Button changed");

        err = bt_lbs_send_button_state(button_state ? true : false);
        if (err) {
            LOG_ERR("Couldn't send notification. err: %d", err);
        }
    }
}

8.4 Complete the implementation of the init_button() function.

In init_button(), we will register the function button_changed() to be called when buttons on the board are pressed.

    err = dk_buttons_init(button_changed);
    if (err) {
        LOG_INF("Cannot init buttons (err: %d)", err);
    }

9. Build and flash the application to your board, and connect to it via your phone.

When the connection is established, click the tab saying “Cli…” (or Client if your screen is large enough). This tab holds a list of all the services present on the connected device. Look for the “Nordic LED and Button Service”, and click on it to expand it. Click on the Notification button, which is an arrow pointing down on a line (marked in the picture below). If you try to press button 1 on your device, you should see the Value field changing between “Button Released” and “Button Pressed”.

Register an account
Already have an account? Log in
(All fields are required unless specified optional)

  • 8 or more characters
  • Upper and lower case letters
  • At least one number or special character

Forgot your password?
Enter the email associated with your account, and we will send you a link to reset your password.