Skip to content
This repository has been archived by the owner on Jul 31, 2024. It is now read-only.

Commit

Permalink
samples: implement WiFi state machine to handle reconnects
Browse files Browse the repository at this point in the history
Implement WiFi connectivity state machine running in a dedicated work
queue (which runs in a dedicated thread). Network management events from
Zephyr are handled there, as well as timeouts and retries when attempting
to connect. As a result, WiFi connectivity is bringed back whenever there
was a temporary problem with WiFi AP connection.

In case WiFi radio is not ready (L1 is down, which results in LOWER_DOWN
interface management event/state) wait until it becomes ready (which is
required by ESP32 WiFi driver, since it does not handle connect requests
otherwise).

Initialize and launch WiFi work queue thread automatically by using
SYS_INIT(), so that `net_connect()` function does not need to handle WiFi
explicitly.

Since `net_connect()` handles mostly DHCPv4 setup and waiting to obtain
IPv4 address, there is no need to check whether interace is UP at the
beginning. DHCPv4 in Zephyr has its own state machine, with network events
handling, all it requires is just calling net_dhcpv4_start() even for
interfaces that are not operational at the time of function call.

Replace waiting for "DHCPv4 bound" event with waiting for "IPv4 address
add" event. The latter allows to wait for WiFi to be connected to AP with
assigned IP address, while still handling (implicitly) "DHCPv4 bound"
event, which is required for ethernet cable connected devices.

Signed-off-by: Marcin Niestroj <[email protected]>
  • Loading branch information
mniestroj committed Oct 25, 2023
1 parent 8517b66 commit 1bade1d
Show file tree
Hide file tree
Showing 4 changed files with 443 additions and 126 deletions.
16 changes: 16 additions & 0 deletions samples/common/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,22 @@ config GOLIOTH_SAMPLE_WIFI
help
Enable utilities for easy WiFi setup, mainly for use inside samples/.

if GOLIOTH_SAMPLE_WIFI

config GOLIOTH_SAMPLE_WIFI_STACK_SIZE
int "WiFi manager stack size"
default 2048

config GOLIOTH_SAMPLE_WIFI_INIT_PRIORITY
int "WiFi manager init priority"
default 90

config GOLIOTH_SAMPLE_WIFI_THREAD_PRIORITY
int "WiFi manager thread priority"
default 7

endif # GOLIOTH_SAMPLE_WIFI

config GOLIOTH_SAMPLE_WIFI_SETTINGS
bool "Load SSID and PSK from settigs subsystem"
depends on GOLIOTH_SAMPLE_WIFI
Expand Down
22 changes: 0 additions & 22 deletions samples/common/include/samples/common/wifi.h

This file was deleted.

48 changes: 6 additions & 42 deletions samples/common/net_connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
LOG_MODULE_REGISTER(golioth_samples, LOG_LEVEL_DBG);

#include <samples/common/net_connect.h>
#include <samples/common/wifi.h>
#include <zephyr/net/net_if.h>
#include <zephyr/net/dhcpv4.h>

Expand All @@ -28,65 +27,30 @@ static void event_cb_handler(struct net_mgmt_event_callback *cb,
}
}

static void wait_for_iface_up_event(struct net_if *iface)
static void wait_for_net_event(struct net_if *iface, uint32_t event)
{
struct wait_data wait;

wait.cb.handler = event_cb_handler;
wait.cb.event_mask = NET_EVENT_IF_UP;
wait.cb.event_mask = event;

k_sem_init(&wait.sem, 0, 1);
net_mgmt_add_event_callback(&wait.cb);

if (!net_if_is_up(iface)) {
k_sem_take(&wait.sem, K_FOREVER);
}
k_sem_take(&wait.sem, K_FOREVER);

net_mgmt_del_event_callback(&wait.cb);
}

static void wait_for_iface_up_poll(struct net_if *iface)
{
while (!net_if_is_up(iface)) {
LOG_DBG("Interface is not up yet!");
k_sleep(K_MSEC(100));
}
}

static void wait_for_iface_up(struct net_if *iface)
{
if (IS_ENABLED(CONFIG_NET_MGMT_EVENT)) {
wait_for_iface_up_event(iface);
} else {
wait_for_iface_up_poll(iface);
}
}

static void wait_for_dhcp_bound(struct net_if *iface)
{
(void)net_mgmt_event_wait_on_iface(iface, NET_EVENT_IPV4_DHCP_BOUND,
NULL, NULL, NULL,
K_FOREVER);
}

void net_connect(void)
{
struct net_if *iface = net_if_get_default();

if (!(IS_ENABLED(CONFIG_GOLIOTH_SAMPLE_WIFI) &&
net_if_flag_is_set(iface, NET_IF_DORMANT))) {
LOG_INF("Waiting for interface to be up");
wait_for_iface_up(iface);
}

if (IS_ENABLED(CONFIG_GOLIOTH_SAMPLE_WIFI)) {
LOG_INF("Connecting to WiFi");
wifi_connect(iface);
}

if (IS_ENABLED(CONFIG_GOLIOTH_SAMPLE_DHCP_BIND)) {
LOG_INF("Starting DHCP to obtain IP address");
net_dhcpv4_start(iface);
wait_for_dhcp_bound(iface);
}

LOG_INF("Waiting to obtain IP address");
wait_for_net_event(iface, NET_EVENT_IPV4_ADDR_ADD);
}
Loading

0 comments on commit 1bade1d

Please sign in to comment.