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.
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.
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
Kconfig1.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
Kconfig1.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
KconfigCONFIG_NRF70_RX_NUM_BUFS
: Number of RX buffers, default value 48CONFIG_NRF70_MAX_TX_AGGREGATION
: Maximum number of TX packets to aggregate, default value 121.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
KconfigCONFIG_NET_MGMT
: Adds the Network Management APICONFIG_NET_MGMT_EVENT
: Adds support for runtime network event notificationsCONFIG_NET_MGMT_EVENT_INFO
: Adds supports for passing information along with an event1.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
Kconfig2. 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>"
KconfigCONFIG_WIFI_CREDENTIALS
– enables the Wi-Fi credentials management subsystemCONFIG_WIFI_CREDENTIALS_STATIC
– enables the static Wi-Fi network configurationCONFIG_WIFI_CREDENTIALS_STATIC_SSID
– SSID of the statically configured Wi-Fi networkCONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD
– Password of the statically configured Wi-FI network3. 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>
C4. 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)
C5. 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;
C6. 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);
C6.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;
}
}
C7. 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);
C8. 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);
C8.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));
CThe 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;
C9.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;
}
C10. 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);
C11. 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;
}
C11. 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
TerminalHowever, 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>"
Kconfig12.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
KconfigCONFIG_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
KconfigCONFIG_WIFI_CREDENTIALS_BACKEND_SETTINGS
: Enables the Zephyr settings subsystem backend.CONFIG_FLASH
: Enables the flash driversCONFIG_FLASH_PAGE_LAYOUT
: API for retrieving the layout of pagesCONFIG_FLASH_MAP
: Enables the flash map abstraction moduleCONFIG_NVS
: Enables support for non-volatile storageCONFIG_SETTINGS
: Enables the settings subsystemCONFIG_SETTINGS_NVS
: Enables NVS storage support13. 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
KconfigCONFIG_SHELL
– Enables shell commandsCONFIG_NET_L2_WIFI_SHELL
– Shell commands for Wi-Fi, wifi
CONFIG_WIFI_CREDENTIALS_SHELL
– Shell commands for Wi-Fi credentials, wifi_cred
CONFIG_SHELL_STACK_SIZE
– Increase the stack size allocated to shell subsystem14. 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
KconfigCONFIG_L2_WIFI_CONNECTIVITY
automatically selects the following Kconfig
CONFIG_L2_WIFI_CONNECTIVITY_AUTO_CONNECT
– When enabled, connect will automatically be called after the network interface has been brought up.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
CThis 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.
Board | Build without TF-M | Build with TF-M | Extra CMake arguments |
---|---|---|---|
nRF7002 DK | nrf7002dk_nrf5340_cpuapp | nrf7002dk_nrf5340_cpuapp_ns | N/A |
nRF5340 DK + nRF7002 EK | nrf5340dk_nrf5340_cpuapp | nrf5340dk_nrf5340_cpuapp_ns | -DSHIELD=nrf7002ek |
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.
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
Terminal17.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
TerminalThe 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.
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.
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.
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
Kconfig1.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
Kconfig2. 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>"
KconfigCONFIG_WIFI_CREDENTIALS
– enables the Wi-Fi credentials management subsystemCONFIG_WIFI_CREDENTIALS_STATIC
– enables the static Wi-Fi network configurationCONFIG_WIFI_CREDENTIALS_STATIC_SSID
– SSID of the statically configured Wi-Fi networkCONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD
– Password of the statically configured Wi-FI network3. 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>
C4. 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)
C5. 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;
C6. 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);
C6.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;
}
}
C7. 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);
C7.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));
CThe 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;
C8.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;
}
C9. 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);
C10. 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);
C11. 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;
}
C11. 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
TerminalProvisioning 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>"
Kconfig12.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
KconfigCONFIG_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
KconfigCONFIG_WIFI_CREDENTIALS_BACKEND_SETTINGS
: Enables the Zephyr settings subsystem backend.CONFIG_FLASH
: Enables the flash driversCONFIG_FLASH_PAGE_LAYOUT
: API for retrieving the layout of pagesCONFIG_FLASH_MAP
: Enables the flash map abstraction moduleCONFIG_NVS
: Enables support for non-volatile storageCONFIG_SETTINGS
: Enables the settings subsystemCONFIG_SETTINGS_NVS
: Enables NVS storage support12.4 Include the header file for the Wi-Fi credentials library in main.c
#include <net/wifi_credentials.h>
C13. 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
KconfigCONFIG_SHELL
– Enables shell commandsCONFIG_WIFI_CREDENTIALS_SHELL
– Shell commands to manage Wi-Fi credentialsCONFIG_SHELL_STACK_SIZE
– Increase the stack size allocated to shell subsystem13. 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.
Board | Build without TF-M | Build with TF-M | Extra CMake arguments |
---|---|---|---|
nRF7002 DK | nrf7002dk_nrf5340_cpuapp | nrf7002dk_nrf5340_cpuapp_ns | N/A |
nRF5340 DK + nRF7002 EK | nrf5340dk_nrf5340_cpuapp | nrf5340dk_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
TerminalProvisioning 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.
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.
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.
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
Kconfig1.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
Kconfig2. 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>"
KconfigCONFIG_WIFI_CREDENTIALS
– enables the Wi-Fi credentials management subsystemCONFIG_WIFI_CREDENTIALS_STATIC
– enables the static Wi-Fi network configurationCONFIG_WIFI_CREDENTIALS_STATIC_SSID
– SSID of the statically configured Wi-Fi networkCONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD
– Password of the statically configured Wi-FI network3. 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>
C4. 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)
C5. 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;
C6. 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);
C6.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;
}
}
C7. 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);
C7.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;
C8. 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;
C8.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;
}
C9. 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);
C10. 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);
C11. 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;
}
C11. 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
TerminalProvisioning 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>"
Kconfig12.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
KconfigCONFIG_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
KconfigCONFIG_WIFI_CREDENTIALS_BACKEND_SETTINGS
: Enables the Zephyr settings subsystem backend.CONFIG_FLASH
: Enables the flash driversCONFIG_FLASH_PAGE_LAYOUT
: API for retrieving the layout of pagesCONFIG_FLASH_MAP
: Enables the flash map abstraction moduleCONFIG_NVS
: Enables support for non-volatile storageCONFIG_SETTINGS
: Enables the settings subsystemCONFIG_SETTINGS_NVS
: Enables NVS storage support12.4 Include the header file for the Wi-Fi credentials library in main.c
#include <net/wifi_credentials.h>
C13. 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
KconfigCONFIG_SHELL
– Enables shell commandsCONFIG_WIFI_CREDENTIALS_SHELL
– Shell commands to manage Wi-Fi credentialsCONFIG_SHELL_STACK_SIZE
– Increase the stack size allocated to shell subsystem13. 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.
Board | Build without TF-M | Build with TF-M | Extra CMake arguments |
---|---|---|---|
nRF7002 DK | nrf7002dk_nrf5340_cpuapp | nrf7002dk_nrf5340_cpuapp_ns | N/A |
nRF5340 DK + nRF7002 EK | nrf5340dk_nrf5340_cpuapp | nrf5340dk_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
TerminalProvisioning 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.