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

v2.9.0 – v2.8.0

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

0. Prepare the project and build and flash it to your board.

0.1 If you haven’t already done so, clone the GitHub repository for this course.

Copy the link to the repository and use VS Code’s Command Palette to clone the repository.

Clone the course’s GitHub repository in VS Code

1.2 In the nRF Connect extension in VS Code, select Open an existing application, and navigate to wifi-fund/l2, click on the folder called l2_e1 and select Open.

1. Enable the necessary configurations.

1.1 Enable Wi-Fi in Sysbuild.

Add the following line to the sysbuild.conf file

SB_CONFIG_WIFI_NRF70=y
Kconfig

1.2 Enable the Wi-Fi-relevant configurations.

Add the following lines to your prj.conf file

CONFIG_WIFI=y
CONFIG_WIFI_NM_WPA_SUPPLICANT=y
Kconfig

1.3 Optimize Wi-Fi stack to save memory.

To optimize the performance and memory usage of the Wi-Fi stack, we will reduce some of the default parameters that are unnecessarily large for our simple application.

CONFIG_NRF70_RX_NUM_BUFS specifies the number of RX buffers that can be used by the nRF Wi-Fi driver. The number of buffers must be enough to keep up with the RX traffic, otherwise packets might be dropped. We will set this to 16, which can handle moderate traffic without excessive memory usage.

CONFIG_NRF70_MAX_TX_AGGREGATION specifies the maximum number of frames that can be coalesced into a single Wi-Fi frame. More frames imply more coalescing opportunities but can add latency to the TX path as we wait for more frames to arrive. We will set this to 4 which provides moderature frame aggregation without excessive latency.

CONFIG_NRF70_RX_NUM_BUFS=16
CONFIG_NRF70_MAX_TX_AGGREGATION=4
Kconfig

1.4 Enable the Network Management relevant configurations.

Add the following lines to your prj.conf file

CONFIG_NET_MGMT=y
CONFIG_NET_MGMT_EVENT=y
CONFIG_NET_MGMT_EVENT_INFO=y
Kconfig

1.5 Enable the Connection Manager and L2 connectivity.

Enable the Connection Manager to listen to the network interface and raise L4 events connected and disconnected when we are connected and increase the connectivity monitoring stack. Set the L2 connectivity to Wi-Fi.

We will also disable the auto connection feature by disabling CONFIG_L2_WIFI_CONNECTIVITY_AUTO_CONNECT since we want to establish the connection manually in this exercise for educational purposes.

Add the following lines to your prj.conf file.

CONFIG_NET_CONNECTION_MANAGER=y
CONFIG_NET_CONNECTION_MANAGER_MONITOR_STACK_SIZE=5200
CONFIG_L2_WIFI_CONNECTIVITY=y
CONFIG_L2_WIFI_CONNECTIVITY_AUTO_CONNECT=n
Kconfig

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

CONFIG_WIFI_CREDENTIALS=y
CONFIG_WIFI_CREDENTIALS_STATIC=y
CONFIG_WIFI_CREDENTIALS_STATIC_SSID="<your_network_SSID>"
CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="<your_network_password>"
Kconfig

3. Include the necessary header files.

Include header files for the Network Management API, the Wi-Fi management API and the Wi-Fi Credentials library.

Add the following lines to the main.c file

#include <zephyr/net/net_mgmt.h>
#include <zephyr/net/wifi_mgmt.h>
#include <net/wifi_credentials.h>
C

4. Define a macro for the relevant network events.

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

NET_EVENT_L4_CONNECTED is raised by the Connection Manager when there is at least one network interface ready.

NET_EVENT_L4_DISCONNECTED is raised by the Connection Manager when there are no longer any ready network interfaces left.

#define EVENT_MASK (NET_EVENT_L4_CONNECTED | NET_EVENT_L4_DISCONNECTED)
C

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;
C

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);
C

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;
	}
}
C

7. 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);
C

8. 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.

8.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);
C

8.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;
params->band = WIFI_FREQ_BAND_UNKNOWN;
memset(params->bssid, 0, sizeof(params->bssid));
C

The last line is necessary to clear the BSSID parameter. If it is not cleared and happens to have a non-zero value, the Wi-Fi stack will assume it is a valid request and only connect to an AP matching this value.

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

9.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;
C

9.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;
}
C

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);
C

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;
}
C

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

*** Booting nRF Connect SDK v2.9.0-7787b2649840 ***
*** Using Zephyr OS v3.7.99-1f8f3dc29142 ***
[00:00:00.667,907] <inf> Lesson2_Exercise2: Initializing Wi-Fi driver
[00:00:00.668,243] <inf> wifi_supplicant: wpa_supplicant initialized
[00:00:01.472,503] <inf> Lesson2_Exercise2: Connecting to Wi-Fi
[00:00:07.082,397] <inf> Lesson2_Exercise2: Network connected
Terminal

However, 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 storage backend.

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 with TF-M, while Zephyr’s settings subsystem can be used when building without TF-M.

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

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

CONFIG_WIFI_CREDENTIALS_STATIC=n
#CONFIG_WIFI_CREDENTIALS_STATIC_SSID="<your_network_SSID>"
#CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="<your_network_password>"
Kconfig

12.2 Configure the board-specific .conf file for the board target with TF-M.

In the directory called boards in the base code exercise, open the .conf file corresponding to your board target with TF-M, e.g 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=y
CONFIG_TFM_PROFILE_TYPE_MEDIUM=y
CONFIG_PM_PARTITION_SIZE_TFM_SRAM=0x18000
Kconfig
  • 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 Small 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.

12.3 Configure the board-specific .conf file for the board target without TF-M.

Since the PSA backend requires TF-M which is only included when building with TF-M (_ns board target), building without TF-M would result in build errors.

Open the .conf file in the boards directory corresponding to the board target without TF-M, e.g. 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

CONFIG_WIFI_CREDENTIALS_BACKEND_SETTINGS=y
CONFIG_FLASH=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_FLASH_MAP=y
CONFIG_NVS=y
CONFIG_SETTINGS=y
CONFIG_SETTINGS_NVS=y
Kconfig

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

CONFIG_SHELL=y
CONFIG_NET_L2_WIFI_SHELL=y
CONFIG_WIFI_CREDENTIALS_SHELL=y
CONFIG_SHELL_STACK_SIZE=5200
Kconfig

14. Enable the auto connect feature of the L2 Wi-Fi connectivity.

Remove the following Kconfig from the prj.conf file

#CONFIG_L2_WIFI_CONNECTIVITY_AUTO_CONNECT=n
Kconfig

CONFIG_L2_WIFI_CONNECTIVITY automatically selects the following Kconfig

This will call Wi-Fi connect with any stored credentials on the device right after the network interface is ready.

15. Note the #ifdef directives around code relying on CONFIG_WIFI_CREDENTIALS_STATIC.

Notice in src/main.c that the code that relies on CONFIG_WIFI_CREDENTIALS_STATIC contains #ifdef directives conditional on the Kconfig. So the wifi_args_to_params() function that we defined in step 8, as well as steps 9.1, 9.2, 10 and 11 in main() will not be included in the build because we have disabled CONFIG_WIFI_CREDENTIALS_STATIC.

#ifdef CONFIG_WIFI_CREDENTIALS_STATIC
/* Code to only be included when CONFIG_WIFI_CREDENTIALS_STATIC is enabled, e.g steps 8, 9, 10 and 11 */
#endif //CONFIG_WIFI_CREDENTIALS_STATIC
C

This is because we will be issuing credentials and connecting using the Shell interface instead.

16. Build the application, and erase and flash to your board.

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

We recommend building with TF-M, for a secure application.

BoardBuild without TF-MBuild with TF-MExtra CMake arguments
nRF7002 DKnrf7002dk_nrf5340_cpuappnrf7002dk_nrf5340_cpuapp_nsN/A
nRF5340 DK + nRF7002 EKnrf5340dk_nrf5340_cpuappnrf5340dk_nrf5340_cpuapp_ns-DSHIELD=nrf7002ek

More on this

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.

When flashing, use Erase and Flash to Board to make sure any stored credentials are removed.

Erase and Flash to Board in VS Code

17. Connect to a Wi-Fi network.

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

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

wifi_cred add -s "<your_network_SSID>" -p "<your_network_password>" -k <key_mgmt>

For the last command, refer to the output from wifi scan

<key-mgmt>: 0: None, 1: WPA2-PSK, 2: WPA2-PSK-256, 3: SAE-HNP, 4: SAE-H2E, 5: SAE-AUTO, 6: WAPI, 7: EAP-TLS, 8: WEP, 9 : WPA-PSK, 10 : WPA-Auto-Personal, 11: DPP

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

wifi_cred auto_connect

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

*** Booting nRF Connect SDK v2.9.0-7787b2649840 ***
*** Using Zephyr OS v3.7.99-1f8f3dc29142 ***
[00:00:00.667,907] <inf> Lesson2_Exercise2: Initializing Wi-Fi driver
[00:00:00.668,243] <inf> wifi_supplicant: wpa_supplicant initialized
uart: wifi_cred add -s "<your_network_SSID>" -p "<your_network_password>" -k <key_mgmt>
wifi_cred add -s "<your_network_SSID>" -p "<your_network_password>" -k <key_mgmt>
uart: wifi_cred auto_connect
wifi_cred auto_connect
[00:01:47.411,926] <inf> wifi_mgmt_ext: Connection requested
Connected
[00:00:38.871,398] <inf> Lesson2_Exercise2: Network connected
Terminal

17.3 Reset your device and observe the auto connect feature is enabled.

To confirm that the automatic connection feature has been enabled, reset your device by pressing the RESET button.

Observe that the connection request is sent automatically by the Wi-Fi management extension library after the WPA supplicant has been initialized. And the application logs that the network is connected.

*** Booting nRF Connect SDK v2.9.0-7787b2649840 ***
*** Using Zephyr OS v3.7.99-1f8f3dc29142 ***
[00:00:00.525,451] <inf> Lesson2_Exercise2: Initializing Wi-Fi driver
[00:00:00.525,817] <inf> wifi_supplicant: wpa_supplicant initialized
[00:00:12.086,975] <inf> wifi_mgmt_ext: Connection requested
Connected
[00:00:16.433,776] <inf> Lesson2_Exercise2: Network connected
Terminal

Note

The credentials used in this exercise will be stored in the following exercises, as long as you do not Erase and Flash to Board. To issue new credentials, send

wifi_cred delete "<your_network_SSID>"

then

wifi_cred add -s "<your_network_SSID>" -p "<your_network_password>" -k <key_mgmt>

with the new credentials.

v2.7.0 – v2.6.1

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

0. Prepare the project and build and flash it to your board.

0.1 If you haven’t already done so, clone the GitHub repository for this course.

Copy the link to the repository and use VS Code’s Command Palette to clone the repository.

Clone the course’s GitHub repository in VS Code

1.2 In the nRF Connect extension in VS Code, select Open an existing application, and navigate to wifi-fund/l2, click on the folder called l2_e1 and select Open.

1. Enable the necessary configurations.

1.1 Enable the Wi-Fi-relevant configurations.

Add the following lines to your prj.conf file

CONFIG_WIFI=y
CONFIG_WIFI_NRF700X=y
CONFIG_WPA_SUPP=y
Kconfig

1.2 Enable the Network Management relevant configurations.

Add the following lines to your prj.conf file

CONFIG_NET_MGMT=y
CONFIG_NET_MGMT_EVENT=y
CONFIG_NET_MGMT_EVENT_INFO=y
CONFIG_NET_MGMT_EVENT_STACK_SIZE=4096
CONFIG_NET_CONNECTION_MANAGER=y
CONFIG_WIFI_MGMT_EXT=y
Kconfig

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

CONFIG_WIFI_CREDENTIALS=y
CONFIG_WIFI_CREDENTIALS_STATIC=y
CONFIG_WIFI_CREDENTIALS_STATIC_SSID="<your_network_SSID>"
CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="<your_network_password>"
Kconfig

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>
C

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)
C

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;
C

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);
C

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;
	}
}
C

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);
C

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;
params->band = WIFI_FREQ_BAND_UNKNOWN;
memset(params->bssid, 0, sizeof(params->bssid));
C

The last line is necessary to clear the BSSID parameter. If it is not cleared and happens to have a non-zero value, the Wi-Fi stack will assume it is a valid request and only connect to an AP matching this value.

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;
C

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;
}
C

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);
C

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);
C

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;
}
C

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

*** Booting nRF Connect SDK 2.6.1-3758bcbfa5cd ***
[00:00:01.472,503] <inf> Lesson2_Exercise2: Connecting to Wi-Fi
[00:00:07.082,397] <inf> Lesson2_Exercise2: Network connected
Terminal

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 board 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 with TF-M, while Zephyr’s settings subsystem can be used when building without TF-M.

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

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

CONFIG_WIFI_CREDENTIALS_STATIC=n
#CONFIG_WIFI_CREDENTIALS_STATIC_SSID="<your_network_SSID>"
#CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="<your_network_password>"
Kconfig

12.2 Configure the board-specific .conf file for the board target with TF-M.

In the directory called boards in the base code exercise, open the .conf file corresponding to your board target with TF-M, e.g 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=y
CONFIG_TFM_PROFILE_TYPE_MEDIUM=y
CONFIG_PM_PARTITION_SIZE_TFM_SRAM=0x18000
CONFIG_MBEDTLS_HEAP_SIZE=16384 
Kconfig
  • 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 Configure the board-specific .conf file for the board target without TF-M.

Since the PSA backend requires TF-M which is only included when building with TF-M (“non-secure” board target), building without TF-M (“secure” board target) would result in build errors.

Open the .conf file in the boards directory corresponding to the board target without TF-M, e.g. 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

CONFIG_WIFI_CREDENTIALS_BACKEND_SETTINGS=y
CONFIG_FLASH=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_FLASH_MAP=y
CONFIG_NVS=y
CONFIG_SETTINGS=y
CONFIG_SETTINGS_NVS=y
Kconfig

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

#include <net/wifi_credentials.h>
C

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

CONFIG_SHELL=y
CONFIG_WIFI_CREDENTIALS_SHELL=y
CONFIG_SHELL_STACK_SIZE=4400
Kconfig

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 board 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-MExtra CMake arguments
nRF7002 DKnrf7002dk_nrf5340_cpuappnrf7002dk_nrf5340_cpuapp_nsN/A
nRF5340 DK + nRF7002 EKnrf5340dk_nrf5340_cpuappnrf5340dk_nrf5340_cpuapp_ns-DSHIELD=nrf7002ek

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

wifi_cred add "<your_network_SSID>" WPA2-PSK "<your_network_password>"

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

wifi_cred auto_connect

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

*** Booting nRF Connect SDK 2.6.1-3758bcbfa5cd ***
uart: wifi_cred add "<your_network_SSID>" WPA2-PSK "<your_network_password>"
wifi_cred add "<your_network_SSID>" WPA2-PSK "<your_network_password>"
uart: wifi_cred auto_connect
wifi_cred auto_connect
[00:00:38.871,398] <inf> Lesson2_Exercise2: Network connected[1B][0m
Terminal

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.

v2.6.0 – v2.5.0

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

0. Prepare the project and build and flash it to your board.

0.1 If you haven’t already done so, clone the GitHub repository for this course.

Copy the link to the repository and use VS Code’s Command Palette to clone the repository.

Clone the course’s GitHub repository in VS Code

1.2 In the nRF Connect extension in VS Code, select Open an existing application, and navigate to wifi-fund/l2, click on the folder called l2_e1 and select Open.

1. Enable the necessary configurations.

1.1 Enable the Wi-Fi-relevant configurations.

Add the following lines to your prj.conf file

CONFIG_WIFI=y
CONFIG_WIFI_NRF700X=y
CONFIG_WPA_SUPP=y
Kconfig

1.2 Enable the Network Management relevant configurations.

Add the following lines to your prj.conf file

CONFIG_NET_MGMT=y
CONFIG_NET_MGMT_EVENT=y
CONFIG_NET_MGMT_EVENT_INFO=y
CONFIG_NET_MGMT_EVENT_STACK_SIZE=4096
CONFIG_NET_CONNECTION_MANAGER=y
CONFIG_WIFI_MGMT_EXT=y
Kconfig

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

CONFIG_WIFI_CREDENTIALS=y
CONFIG_WIFI_CREDENTIALS_STATIC=y
CONFIG_WIFI_CREDENTIALS_STATIC_SSID="<your_network_SSID>"
CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="<your_network_password>"
Kconfig

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>
C

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)
C

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;
C

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);
C

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;
	}
}
C

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);
C

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;
params->band = WIFI_FREQ_BAND_UNKNOWN;
C

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;
C

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;
}
C

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);
C

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);
C

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;
}
C

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

*** Booting nRF Connect SDK 2.6.0-3758bcbfa5cd ***
[00:00:01.472,503] <inf> Lesson2_Exercise2: Connecting to Wi-Fi
[00:00:07.082,397] <inf> Lesson2_Exercise2: Network connected
Terminal

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 board 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 with TF-M, while Zephyr’s settings subsystem can be used when building without TF-M.

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

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

CONFIG_WIFI_CREDENTIALS_STATIC=n
#CONFIG_WIFI_CREDENTIALS_STATIC_SSID="<your_network_SSID>"
#CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="<your_network_password>"
Kconfig

12.2 Create a board-specific .conf file for the board target with TF-M.

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=y
CONFIG_TFM_PROFILE_TYPE_MEDIUM=y
CONFIG_PM_PARTITION_SIZE_TFM_SRAM=0x18000
CONFIG_MBEDTLS_HEAP_SIZE=16384 
Kconfig
  • 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 board target without TF-M.

Since the PSA backend requires TF-M which is only included when building with TF-M (“non-secure” board target), building without TF-M (“secure” board target) would result in build errors.

Create another file in the boards for the board 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

CONFIG_WIFI_CREDENTIALS_BACKEND_SETTINGS=y
CONFIG_FLASH=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_FLASH_MAP=y
CONFIG_NVS=y
CONFIG_SETTINGS=y
CONFIG_SETTINGS_NVS=y
Kconfig

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

#include <net/wifi_credentials.h>
C

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

CONFIG_SHELL=y
CONFIG_WIFI_CREDENTIALS_SHELL=y
CONFIG_SHELL_STACK_SIZE=4400
Kconfig

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 board 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-MExtra CMake arguments
nRF7002 DKnrf7002dk_nrf5340_cpuappnrf7002dk_nrf5340_cpuapp_nsN/A
nRF5340 DK + nRF7002 EKnrf5340dk_nrf5340_cpuappnrf5340dk_nrf5340_cpuapp_ns-DSHIELD=nrf7002ek

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

wifi_cred add "<your_network_SSID>" WPA2-PSK "<your_network_password>"

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

wifi_cred auto_connect

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

*** Booting nRF Connect SDK 2.6.0-3758bcbfa5cd ***
uart: wifi_cred add "<your_network_SSID>" WPA2-PSK "<your_network_password>"
wifi_cred add "<your_network_SSID>" WPA2-PSK "<your_network_password>"
uart: wifi_cred auto_connect
wifi_cred auto_connect
[00:00:38.871,398] <inf> Lesson2_Exercise2: Network connected[1B][0m
Terminal

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.