Skip to content

Commit 6d57673

Browse files
krish2718carlescufi
authored andcommitted
net: lib: Add Wi-Fi ready lib
This library should be used samples to manage Wi-Fi usage dynamically. Signed-off-by: Chaitanya Tata <Chaitanya.Tata@nordicsemi.no>
1 parent a60a1e5 commit 6d57673

File tree

8 files changed

+353
-1
lines changed

8 files changed

+353
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
.. _lib_wifi_ready:
2+
3+
Wi-Fi ready
4+
###########
5+
6+
.. contents::
7+
:local:
8+
:depth: 2
9+
10+
The Wi-Fi ready library manages Wi-Fi® readiness for applications by handling supplicant ready and not ready events.
11+
12+
Overview
13+
********
14+
15+
The Wi-Fi ready library informs applications of Wi-Fi readiness by managing supplicant events, indicating when Wi-Fi is available for use.
16+
17+
Configuration
18+
*************
19+
20+
To use this library, enable the :kconfig:option:`CONFIG_WIFI_READY_LIB` Kconfig option.
21+
22+
API documentation
23+
*****************
24+
25+
| Header file: :file:`include/net/wifi_ready.h`
26+
| Source files: :file:`subsys/net/lib/wifi_ready`
27+
28+
.. doxygengroup:: wifi_ready
29+
:project: nrf
30+
:members:

doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ Modem libraries
335335
Libraries for networking
336336
------------------------
337337

338-
|no_changes_yet_note|
338+
* Added the :ref:`lib_wifi_ready` library.
339339

340340
Libraries for NFC
341341
-----------------

include/net/wifi_ready.h

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright (c) 2024 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
8+
#ifndef __LIB_WIFI_READY_H__
9+
#define __LIB_WIFI_READY_H__
10+
11+
#include <zephyr/net/net_if.h>
12+
13+
/**
14+
* @defgroup wifi_ready Wi-Fi ready library
15+
* @brief Library for handling Wi-Fi ready events.
16+
*
17+
* @{
18+
*/
19+
20+
#ifdef __cplusplus
21+
extern "C" {
22+
#endif
23+
24+
/**
25+
* @brief Structure for storing a callback function to be called when the Wi-Fi is ready.
26+
*/
27+
typedef struct {
28+
/** Callback function to be called when the Wi-Fi is ready. */
29+
void (*wifi_ready_cb)(bool wifi_ready);
30+
/** Interface to which the callback is registered. */
31+
struct net_if *iface;
32+
/** Only for internal use. */
33+
struct k_work item;
34+
} wifi_ready_callback_t;
35+
36+
/**
37+
* @brief Register a callback to be called when the Wi-Fi is ready.
38+
*
39+
* @param cb Callback function to be called when the Wi-Fi is ready.
40+
* The callback is called from NET_MGMT thread, so, care should be taken
41+
* to avoid blocking the thread and also stack size should be considered.
42+
* @param iface (optional) Interface to which the callback is registered.
43+
*
44+
* @return 0 if the callback was successfully registered, or a negative error code
45+
* if the callback could not be registered.
46+
*
47+
* @retval -EINVAL if the callback is NULL.
48+
* @retval -ENOMEM if the callback array is full.
49+
* @retval -EALREADY if the callback is already registered.
50+
*/
51+
52+
int register_wifi_ready_callback(wifi_ready_callback_t cb, struct net_if *iface);
53+
/**
54+
* @brief Unregister a callback that was registered to be called when the Wi-Fi is ready.
55+
*
56+
* @param cb Callback function to be unregistered.
57+
* @param iface (optional) Interface to which the callback is registered.
58+
*
59+
* @return 0 if the callback was successfully unregistered, or a negative error code
60+
* if the callback could not be unregistered.
61+
*
62+
* @retval -EINVAL if the callback is NULL.
63+
* @retval -ENOENT if the callback is not registered.
64+
*/
65+
int unregister_wifi_ready_callback(wifi_ready_callback_t cb, struct net_if *iface);
66+
67+
#ifdef __cplusplus
68+
}
69+
#endif
70+
71+
/**
72+
* @}
73+
*/
74+
75+
#endif /* __LIB_WIFI_READY_H__*/

subsys/net/lib/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,4 @@ add_subdirectory_ifdef(CONFIG_WIFI_MGMT_EXT wifi_mgmt_ext)
3333
add_subdirectory_ifdef(CONFIG_MQTT_HELPER mqtt_helper)
3434
add_subdirectory_ifdef(CONFIG_NRF_PROVISIONING nrf_provisioning)
3535
add_subdirectory_ifdef(CONFIG_NRF_MCUMGR_SMP_CLIENT mcumgr_smp_client)
36+
add_subdirectory_ifdef(CONFIG_WIFI_READY_LIB wifi_ready)

subsys/net/lib/Kconfig

+1
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,6 @@ rsource "wifi_mgmt_ext/Kconfig"
4545
rsource "mqtt_helper/Kconfig"
4646
rsource "nrf_provisioning/Kconfig"
4747
rsource "mcumgr_smp_client/Kconfig"
48+
rsource "wifi_ready/Kconfig"
4849

4950
endmenu
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#
2+
# Copyright (c) 2024 Nordic Semiconductor
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
zephyr_library_named(WIFI_READY_LIB)
8+
zephyr_library_sources(wifi_ready.c)

subsys/net/lib/wifi_ready/Kconfig

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#
2+
# Copyright (c) 2024 Nordic Semiconductor
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
menuconfig WIFI_READY_LIB
8+
bool "Wi-Fi ready event handling library"
9+
select EXPERIMENTAL
10+
depends on WPA_SUPP
11+
depends on NET_MGMT
12+
help
13+
Enable WiFi ready management subsystem that allows the application to
14+
register callbacks that are called when the WiFi is ready to be used and
15+
when the WiFi is not ready to be used.
16+
17+
if WIFI_READY_LIB
18+
19+
module = WIFI_READY_LIB
20+
module-str = wifi_ready_lib
21+
source "subsys/logging/Kconfig.template.log_config"
22+
23+
config WIFI_READY_MAX_CALLBACKS
24+
int "Maximum number of Wi-Fi ready callbacks"
25+
default 2
26+
help
27+
Set the maximum number of Wi-Fi ready callbacks that can be registered
28+
by the application.
29+
30+
config WIFI_READY_INIT_PRIORITY
31+
int "Wi-Fi ready initialization priority"
32+
default 90
33+
help
34+
Set the initialization priority of the Wi-Fi ready subsystem.
35+
endif
+202
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
/*
2+
* Copyright (c) 2024 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
#include <zephyr/kernel.h>
8+
#include <zephyr/init.h>
9+
#include <zephyr/logging/log.h>
10+
#include <zephyr/net/net_event.h>
11+
12+
#include <stdio.h>
13+
#include <stdlib.h>
14+
15+
#include <net/wifi_ready.h>
16+
#include <supp_events.h>
17+
#include <zephyr/net/wifi_nm.h>
18+
19+
LOG_MODULE_REGISTER(wifi_ready, CONFIG_WIFI_READY_LIB_LOG_LEVEL);
20+
21+
static wifi_ready_callback_t wifi_ready_callbacks[CONFIG_WIFI_READY_MAX_CALLBACKS];
22+
static unsigned char callback_count;
23+
static K_MUTEX_DEFINE(wifi_ready_mutex);
24+
25+
#define WPA_SUPP_EVENTS (NET_EVENT_WPA_SUPP_READY) | \
26+
(NET_EVENT_WPA_SUPP_NOT_READY)
27+
28+
static struct net_mgmt_event_callback net_wpa_supp_cb;
29+
30+
/* In case Wi-Fi is already ready, call the callbacks */
31+
static void wifi_ready_work_handler(struct k_work *item);
32+
33+
static void call_wifi_ready_callbacks(bool ready, struct net_if *iface)
34+
{
35+
int i;
36+
37+
k_mutex_lock(&wifi_ready_mutex, K_FOREVER);
38+
for (i = 0; i < ARRAY_SIZE(wifi_ready_callbacks); i++) {
39+
if (wifi_ready_callbacks[i].wifi_ready_cb &&
40+
((wifi_ready_callbacks[i].iface &&
41+
(wifi_ready_callbacks[i].iface == iface)) ||
42+
!wifi_ready_callbacks[i].iface)) {
43+
wifi_ready_callbacks[i].wifi_ready_cb(ready);
44+
}
45+
}
46+
k_mutex_unlock(&wifi_ready_mutex);
47+
}
48+
49+
static void wifi_ready_work_handler(struct k_work *item)
50+
{
51+
wifi_ready_callback_t *cb = CONTAINER_OF(item, wifi_ready_callback_t, item);
52+
53+
call_wifi_ready_callbacks(true, cb->iface);
54+
}
55+
56+
static void handle_wpa_supp_event(struct net_if *iface, bool ready)
57+
{
58+
LOG_DBG("Supplicant event %s for iface %p",
59+
ready ? "ready" : "not ready", iface);
60+
61+
call_wifi_ready_callbacks(ready, iface);
62+
}
63+
64+
static void wpa_supp_event_handler(struct net_mgmt_event_callback *cb,
65+
uint32_t mgmt_event, struct net_if *iface)
66+
{
67+
ARG_UNUSED(cb);
68+
69+
LOG_DBG("Event received: %d", mgmt_event);
70+
switch (mgmt_event) {
71+
case NET_EVENT_WPA_SUPP_READY:
72+
handle_wpa_supp_event(iface, true);
73+
break;
74+
case NET_EVENT_WPA_SUPP_NOT_READY:
75+
handle_wpa_supp_event(iface, false);
76+
break;
77+
default:
78+
LOG_DBG("Unhandled event (%d)", mgmt_event);
79+
break;
80+
}
81+
}
82+
83+
int register_wifi_ready_callback(wifi_ready_callback_t cb, struct net_if *iface)
84+
{
85+
int ret = 0, i;
86+
unsigned int next_avail_idx = CONFIG_WIFI_READY_MAX_CALLBACKS;
87+
struct net_if *wpas_iface = NULL;
88+
89+
k_mutex_lock(&wifi_ready_mutex, K_FOREVER);
90+
91+
if (!cb.wifi_ready_cb) {
92+
LOG_ERR("Callback is NULL");
93+
ret = -EINVAL;
94+
goto out;
95+
}
96+
97+
for (i = 0; i < ARRAY_SIZE(wifi_ready_callbacks); i++) {
98+
if (wifi_ready_callbacks[i].wifi_ready_cb == NULL) {
99+
next_avail_idx = i;
100+
break;
101+
}
102+
}
103+
104+
if (next_avail_idx == CONFIG_WIFI_READY_MAX_CALLBACKS) {
105+
LOG_ERR("Reject callback registration, maximum count %d reached",
106+
CONFIG_WIFI_READY_MAX_CALLBACKS);
107+
ret = -ENOMEM;
108+
goto out;
109+
}
110+
111+
/* Check if callback has already been registered for iface */
112+
for (i = 0; i < ARRAY_SIZE(wifi_ready_callbacks); i++) {
113+
if (wifi_ready_callbacks[i].iface == iface &&
114+
wifi_ready_callbacks[i].wifi_ready_cb == cb.wifi_ready_cb) {
115+
LOG_ERR("Callback has already registered for iface");
116+
ret = -EALREADY;
117+
goto out;
118+
}
119+
}
120+
121+
wifi_ready_callbacks[next_avail_idx].wifi_ready_cb = cb.wifi_ready_cb;
122+
wifi_ready_callbacks[next_avail_idx].iface = iface;
123+
124+
if (++callback_count == 1) {
125+
net_mgmt_init_event_callback(&net_wpa_supp_cb,
126+
wpa_supp_event_handler, WPA_SUPP_EVENTS);
127+
net_mgmt_add_event_callback(&net_wpa_supp_cb);
128+
}
129+
130+
if (iface) {
131+
wpas_iface = iface;
132+
} else {
133+
wpas_iface = net_if_get_first_wifi();
134+
if (!wpas_iface) {
135+
LOG_ERR("Failed to get Wi-Fi interface");
136+
ret = -ENODEV;
137+
goto out;
138+
}
139+
}
140+
141+
/* In case Wi-Fi is already ready, call the callback */
142+
if (wifi_nm_get_instance_iface(wpas_iface)) {
143+
k_work_submit(&wifi_ready_callbacks[next_avail_idx].item);
144+
}
145+
146+
out:
147+
k_mutex_unlock(&wifi_ready_mutex);
148+
return ret;
149+
150+
}
151+
152+
153+
int unregister_wifi_ready_callback(wifi_ready_callback_t cb, struct net_if *iface)
154+
{
155+
int ret = 0, i;
156+
bool found = false;
157+
158+
k_mutex_lock(&wifi_ready_mutex, K_FOREVER);
159+
160+
if (!cb.wifi_ready_cb) {
161+
LOG_ERR("Callback is NULL");
162+
ret = -EINVAL;
163+
goto out;
164+
}
165+
166+
for (i = 0; i < ARRAY_SIZE(wifi_ready_callbacks); i++) {
167+
if (wifi_ready_callbacks[i].iface == iface &&
168+
wifi_ready_callbacks[i].wifi_ready_cb == cb.wifi_ready_cb) {
169+
wifi_ready_callbacks[i].wifi_ready_cb = NULL;
170+
wifi_ready_callbacks[i].iface = NULL;
171+
found = true;
172+
}
173+
}
174+
175+
if (!found) {
176+
ret = -ENOENT;
177+
goto out;
178+
}
179+
180+
if (--callback_count == 0) {
181+
net_mgmt_del_event_callback(&net_wpa_supp_cb);
182+
}
183+
184+
out:
185+
if (ret < 0) {
186+
LOG_ERR("Failed to unregister callback: %d", ret);
187+
}
188+
k_mutex_unlock(&wifi_ready_mutex);
189+
return ret;
190+
}
191+
192+
static int wifi_ready_init(void)
193+
{
194+
/* Initialize the work items */
195+
for (int i = 0; i < ARRAY_SIZE(wifi_ready_callbacks); i++) {
196+
k_work_init(&wifi_ready_callbacks[i].item, wifi_ready_work_handler);
197+
}
198+
199+
return 0;
200+
}
201+
202+
SYS_INIT(wifi_ready_init, APPLICATION, CONFIG_WIFI_READY_INIT_PRIORITY);

0 commit comments

Comments
 (0)