Feedback
Feedback

If you are having issues with the exercises, please create a ticket on DevZone: devzone.nordicsemi.com
Click or drag files to this area to upload. You can upload up to 2 files.

Exercise 2

Connecting to Wi-Fi using the Network Management API

In this exercise, we will learn how to connect to Wi-Fi using the Network Management API. Throughout this exercise, we will learn how to include support for the Network Management API and how to configure the necessary callbacks for Wi-Fi events. First, we will go through how to configure the necessary Wi-Fi parameters directly in the application to request a connection. Then, how to add CLI support, to provision the Wi-Fi credentials more securely.

Exercise steps

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

1. Enable the necessary configurations.

1.1 Enable the Wi-Fi-relevant configurations.

Add the following lines to your prj.conf file

1.2 Enable the Network Management relevant configurations.

Add the following lines to your prj.conf file

2. Configure the Wi-Fi credentials.

To statically add the Wi-Fi network configuration to the application, we will use Kconfigs available in the Wi-Fi credentials library. Please note that this is not recommended outside of the development phase.

Add the following lines to your prj.conf file

3. Include the necessary header files.

Add the following lines to the main.c file

#include <zephyr/net/wifi.h>
#include <zephyr/net/wifi_mgmt.h>
#include <zephyr/net/net_mgmt.h>
#include <net/wifi_mgmt_ext.h>

4. Define a macro for the relevant network events.

Define a bit mask of the relevant events to pass to the event handler.

#define EVENT_MASK (NET_EVENT_L4_CONNECTED | NET_EVENT_L4_DISCONNECTED)

5. Declare the callback structure for Wi-Fi events.

Declare the callback structure mgmt_cb of type struct net_mgmt_event_callback to handle the network events.

static struct net_mgmt_event_callback mgmt_cb;

6. Define the callback function for network events.

6.1 Define the boolean connected and the semaphore run_app.

Define connected to keep track of the current connection status, and the semaphore run_app to ensure the application waits for a Wi-Fi connection.

static bool connected;
static K_SEM_DEFINE(run_app, 0, 1);

6.2 Define the callback function net_mgmt_event_handler() to handle the connection and disconnection to Wi-Fi. We want LED1 on the board to reflect our current Wi-Fi connection status.

static void net_mgmt_event_handler(struct net_mgmt_event_callback *cb,
			  uint32_t mgmt_event, struct net_if *iface)
{
	if ((mgmt_event & EVENT_MASK) != mgmt_event) {
		return;
	}
	if (mgmt_event == NET_EVENT_L4_CONNECTED) {
		LOG_INF("Network connected");
		connected = true;
		dk_set_led_on(DK_LED1);
		k_sem_give(&run_app);
		return;
	}
	if (mgmt_event == NET_EVENT_L4_DISCONNECTED) {
		if (connected == false) {
			LOG_INF("Waiting for network to be connected");
		} else {
			dk_set_led_off(DK_LED1);
			LOG_INF("Network disconnected");
			connected = false;
		}
		k_sem_reset(&run_app);
		return;
	}
}

7. Define the function wifi_args_to_params() to populate the Wi-Fi credential parameters.

Define a function that takes the parameter struct wifi_connect_req_params and assigns the relevant Wi-Fi network configuration information.

7.1 Populate the SSID and password.

The SSID and password of your network have been set in the Kconfigs CONFIG_WIFI_CREDENTIALS_STATIC_SSID and CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD.

Add the following code snippet to your application

params->ssid = CONFIG_WIFI_CREDENTIALS_STATIC_SSID;
params->ssid_length = strlen(params->ssid);

params->psk = CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD;
params->psk_length = strlen(params->psk);

7.2 Populate the remaining parameters

Add the following code snippet

params->channel = WIFI_CHANNEL_ANY;
params->security = WIFI_SECURITY_TYPE_PSK;
params->mfp = WIFI_MFP_OPTIONAL;
params->timeout = SYS_FOREVER_MS;

8. Declare the variables for the network configuration parameters and interface.

8.1 Declare the variable for the network configuration parameters.

Declare the variable cnx_params of type struct wifi_connect_req_params in main()

struct wifi_connect_req_params cnx_params;

8.2 Get the network interface.

Define the pointer struct iface, and use the helper function net_if_get_first_wifi() to assign the default network interface. Return an error if the result is NULL.

struct net_if *iface = net_if_get_first_wifi();
if (iface == NULL) {
	LOG_ERR("Returned network interface is NULL");
	return -1;
}

9. Initialize and add the callback function for network events.

Initialize the callback structure mgmt_cb with the handler function net_mgmt_event_handler, then add the callback structure.

net_mgmt_init_event_callback(&mgmt_cb, net_mgmt_event_handler, EVENT_MASK);
net_mgmt_add_event_callback(&mgmt_cb);

10. Populate cnx_params with the network configuration.

Call wifi_args_to_params() to populate cnx_params that was declared in the previous step.

wifi_args_to_params(&cnx_params);

11. Call net_mgmt() to request the Wi-Fi connection.

Now that the necessary parameters are populated, call net_mgmt() with NET_REQUEST_WIFI_CONNECT to specify the management procedure being requested. Then pass the parameters iface and cnx_params to specify the network interface and network configuration parameters.

int err = net_mgmt(NET_REQUEST_WIFI_CONNECT, iface, &cnx_params, sizeof(struct wifi_connect_req_params));
if (err) {
	LOG_ERR("Connecting to Wi-Fi failed, err: %d", err);
	return ENOEXEC;
}

11. Build and flash the application to your board.

If the connection was successful, LED1 on your board should light, and you should see the following log output

Provisioning the Wi-Fi device by adding all the necessary information directly to the firmware is not secure nor good practice. Instead, we want to add support for shell commands in the application, so that we can enter the Wi-Fi credentials through the command line instead, just like we did in Exercise 1.

12. Enable Wi-Fi credentials backend depending on the build target

As we covered in Wi-Fi Provisioning, the Wi-Fi credentials library provides two different backend options for credential storage: Zephyr’s settings subsystem and PSA Protected Storage. PSA is a part of the TF-M architecture, so it should be used when building for the non-secure build target, while Zephyr’s settings subsystem can be used for the secure build target.

Let’s create a prj.conf overlay file for each build configuration so that our sample will build regardless of the build target.

12.1 Disable the static Wi-Fi network configuration and remove the Kconfigs storing your SSID and password

12.2 Create a board-specific .conf file for the non-secure build target.

Create a directory called boards in the base code exercise, and create a file called nrf7002dk_nrf5340_cpuapp_ns.conf or nrf5340dk_nrf5340_cpuapp_ns.conf, depending on which hardware you are using for this course.

Add the following lines to this file

  • CONFIG_WIFI_CREDENTIALS_BACKEND_PSA: Enables the PSA backend API.
  • CONFIG_TFM_PROFILE_TYPE_MEDIUM: Sets the desired profile for the TrustedFirmware-M (TF-M) implementation. A TF-M profile, in this context, is a set of configurations that sets the level of security and features to be included in the build. Our choice of Medium profile is to achieve a balance between the included security level and the resources used.
  • CONFIG_PM_PARTITION_SIZE_TFM_SRAM=0x18000: Sets the memory partition allocated to the TF-M to 98.3 KB. This is the memory space we recommend allocating to the TF-M to ensure it operates correctly.
  • CONFIG_MBEDTLS_HEAP_SIZE=16384: Configures the heap memory size allocated to the mbedTLS library, which is used for TLS-related operations.

12.3 Create a board-specific .conf file for the secure build target.

Since the PSA backend requires TF-M which is only included when building for the non-secure build-target, building for the secure build-target would result in build errors.

Create another file in the boards for the secure build-target, called nrf7002dk_nrf5340_cpuapp.conf or nrf5340dk_nrf5340_cpuapp.conf, depending on which hardware you are using for this course.

Add the following lines to this file

12.4 Include the header file for the Wi-Fi credentials library in main.c

#include <net/wifi_credentials.h>

13. Enable support for shell commands in the application.

Let’s enable support for issuing commands over shell in the application

Add the following lines in prj.conf

13. Comment out the unnecessary code in main.c.

To avoid build errors and warnings, let’s comment out step 7 (the function wifi_args_to_params()), step 8.1, 8.2, as well as step 10 and 11.

14. Build and flash the application to your board.

Since we have enabled both backends depending on the build target, you can choose if you would like to build with or without TF-M, depending on the security requirements of your application.

BoardBuild without TF-MBuild with TF-M
nRF7002 DKnrf7002dk_nrf5340_cpuappnrf7002dk_nrf5340_cpuapp_ns
nRF5340 DK + nRF7002 EKnrf5340dk_nrf5340_cpuappnrf5340dk_nrf5340_cpuapp_ns

15. Connect to a Wi-Fi network.

Now that we have enabled shell commands, we will connect to a network through the terminal.

15.1 Open a terminal and issue the following command to store the credentials

15.2 Issue the following command to automatically connect to the network that is stored

If the connection was successful, you should see the following log output.

Note

Provisioning and connecting to Wi-Fi using shell commands is the connection method we will be using in the other exercises in this course. With the exception of Lesson 3 Exercise 2, all the following exercises will use the PSA backend for storing the credentials.
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.