diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index e1d99d5d1..61314658f 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -7,3 +7,4 @@ add_subdirectory_ifdef(CONFIG_SHARED_DEVICE shared_device) add_subdirectory_ifdef(CONFIG_INFUSE_IMU imu) add_subdirectory_ifdef(CONFIG_LED led) add_subdirectory_ifdef(CONFIG_INFUSE_WATCHDOG watchdog) +add_subdirectory_ifdef(CONFIG_WIFI wifi) diff --git a/drivers/Kconfig b/drivers/Kconfig index a818f06e7..e915f1566 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -7,3 +7,4 @@ rsource "led/Kconfig" rsource "sensor/Kconfig" rsource "shared_device/Kconfig" rsource "watchdog/Kconfig" +rsource "wifi/Kconfig" diff --git a/drivers/wifi/CMakeLists.txt b/drivers/wifi/CMakeLists.txt new file mode 100644 index 000000000..45bf76caa --- /dev/null +++ b/drivers/wifi/CMakeLists.txt @@ -0,0 +1,3 @@ +# Infuse-IoT WiFi sources + +zephyr_sources_ifdef(CONFIG_WIFI_SIM wifi_sim.c) diff --git a/drivers/wifi/Kconfig b/drivers/wifi/Kconfig new file mode 100644 index 000000000..4de7aeb19 --- /dev/null +++ b/drivers/wifi/Kconfig @@ -0,0 +1,20 @@ +# Infuse-IoT watchdog configuration + +config WIFI_SIM + bool "Simulated WiFi device" + select WIFI_OFFLOAD + +if WIFI_SIM + +config WIFI_SIM_AP_SSID + string "Network name that results in a connection to the network" + default "nsos_sim_network" + +config WIFI_SIM_AP_PSK + string "Network pre-shared-key that results in a connection to the network" + default "nsos_sim_password" + +config WIFI_SIM_IF_AUTO_START + bool "Automatically start the interface" + +endif # WIFI_SIM diff --git a/drivers/wifi/wifi_sim.c b/drivers/wifi/wifi_sim.c new file mode 100644 index 000000000..dbf3ea420 --- /dev/null +++ b/drivers/wifi/wifi_sim.c @@ -0,0 +1,237 @@ +/** + * @file + * @copyright 2025 Embeint Holdings Pty Ltd + * @author Jordan Yates + * + * SPDX-License-Identifier: FSL-1.1-ALv2 + */ + +#include +#include +#include +#include +#include +#include +#include + +struct wifi_sim_iface_data { + struct k_work power_up; + struct k_work power_down; + struct k_work_delayable connect_success; + struct k_work_delayable connect_failure; + struct k_work disconnect; + struct net_if *iface; + bool ap_in_range; + bool connecting; + bool connected; +}; + +LOG_MODULE_REGISTER(sim_wifi, LOG_LEVEL_INF); + +static int offload_dummy_get(sa_family_t family, enum net_sock_type type, + enum net_ip_protocol ip_proto, struct net_context **context) +{ + return -1; +} + +/* Placeholders, until Zephyr IP stack updated to handle a NULL net_offload */ +static struct net_offload offload_dummy = { + .get = offload_dummy_get, + .bind = NULL, + .listen = NULL, + .connect = NULL, + .accept = NULL, + .send = NULL, + .sendto = NULL, + .recv = NULL, + .put = NULL, +}; + +static void sim_wifi_connect_success_work(struct k_work *work) +{ + struct k_work_delayable *delayable = k_work_delayable_from_work(work); + struct wifi_sim_iface_data *data = + CONTAINER_OF(delayable, struct wifi_sim_iface_data, connect_success); + + LOG_INF("Submitting connection success"); + data->connected = true; + data->connecting = false; + net_if_dormant_off(data->iface); + wifi_mgmt_raise_connect_result_event(data->iface, 0); +} + +static void sim_wifi_connect_failure_work(struct k_work *work) +{ + struct k_work_delayable *delayable = k_work_delayable_from_work(work); + struct wifi_sim_iface_data *data = + CONTAINER_OF(delayable, struct wifi_sim_iface_data, connect_failure); + + LOG_INF("Submitting connection failed"); + data->connected = false; + data->connecting = false; + wifi_mgmt_raise_connect_result_event(data->iface, -ETIMEDOUT); +} + +static int sim_wifi_connect(const struct device *dev, struct wifi_connect_req_params *params) +{ + struct wifi_sim_iface_data *data = dev->data; + + if (data->connecting || data->connected) { + return -EINVAL; + } + + if (!data->ap_in_range) { + LOG_INF("Connection will fail (%s)", "out of range"); + k_work_schedule(&data->connect_failure, K_MSEC(500)); + } else if (params->security != WIFI_SECURITY_TYPE_PSK) { + LOG_INF("Connection will fail (%s)", "bad security"); + k_work_schedule(&data->connect_failure, K_MSEC(500)); + } else if ((params->ssid_length != strlen(CONFIG_WIFI_SIM_AP_SSID)) || + (strncmp(params->ssid, CONFIG_WIFI_SIM_AP_SSID, params->ssid_length) != 0)) { + LOG_INF("Connection will fail (%s)", "bad SSID"); + k_work_schedule(&data->connect_failure, K_MSEC(500)); + } else if ((params->psk_length != strlen(CONFIG_WIFI_SIM_AP_PSK)) || + (strncmp(params->psk, CONFIG_WIFI_SIM_AP_PSK, params->psk_length) != 0)) { + LOG_INF("Connection will fail (%s)", "bad PSK"); + k_work_schedule(&data->connect_failure, K_MSEC(500)); + } else { + /* Checks passed, simulated connection */ + LOG_INF("Connection will succeed"); + k_work_schedule(&data->connect_success, K_MSEC(500)); + } + data->connecting = true; + return 0; +} + +static void sim_wifi_disconnect_work(struct k_work *work) +{ + struct wifi_sim_iface_data *data = + CONTAINER_OF(work, struct wifi_sim_iface_data, disconnect); + + data->connected = false; + data->connecting = false; + net_if_dormant_on(data->iface); + wifi_mgmt_raise_disconnect_result_event(data->iface, 0); +} + +static int sim_wifi_disconnect(const struct device *dev) +{ + struct wifi_sim_iface_data *data = dev->data; + + if (data->connecting) { + LOG_INF("Triggering disconnect while connecting"); + k_work_cancel_delayable(&data->connect_success); + k_work_reschedule(&data->connect_failure, K_NO_WAIT); + k_sleep(K_TICKS(1)); + } else if (data->connected) { + LOG_INF("Triggering disconnect when connected"); + k_work_submit(&data->disconnect); + k_sleep(K_TICKS(1)); + } else { + LOG_DBG("No connection present"); + return -EINVAL; + } + return 0; +} + +static void sim_wifi_init(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct wifi_sim_iface_data *data = dev->data; + + iface->if_dev->offload = &offload_dummy; + data->iface = iface; + + if (!IS_ENABLED(CONFIG_WIFI_SIM_IF_AUTO_START)) { + net_if_flag_set(iface, NET_IF_NO_AUTO_START); + } + + net_if_carrier_off(iface); + net_if_dormant_on(iface); +} + +static void sim_wifi_power_up_work(struct k_work *work) +{ + struct wifi_sim_iface_data *data = CONTAINER_OF(work, struct wifi_sim_iface_data, power_up); + + net_if_carrier_on(data->iface); +} + +static void sim_wifi_power_down_work(struct k_work *work) +{ + struct wifi_sim_iface_data *data = + CONTAINER_OF(work, struct wifi_sim_iface_data, power_down); + + net_if_carrier_off(data->iface); + net_if_carrier_off(data->iface); +} + +static int sim_wifi_enable(const struct net_if *iface, bool state) +{ + const struct device *dev = iface->if_dev->dev; + struct wifi_sim_iface_data *data = dev->data; + + if (state) { + k_work_submit(&data->power_up); + } else { + k_work_submit(&data->power_down); + } + return 0; +} + +static int sim_wifi_dev_init(const struct device *dev) +{ + struct wifi_sim_iface_data *data = dev->data; + + data->ap_in_range = true; + k_work_init(&data->power_up, sim_wifi_power_up_work); + k_work_init(&data->power_down, sim_wifi_power_down_work); + k_work_init_delayable(&data->connect_success, sim_wifi_connect_success_work); + k_work_init_delayable(&data->connect_failure, sim_wifi_connect_failure_work); + k_work_init(&data->disconnect, sim_wifi_disconnect_work); + + return 0; +} + +static enum offloaded_net_if_types sim_wifi_get_type(void) +{ + return L2_OFFLOADED_NET_IF_TYPE_WIFI; +} + +static const struct wifi_mgmt_ops sim_wifi_mgmt = { + .connect = sim_wifi_connect, + .disconnect = sim_wifi_disconnect, +}; + +static const struct net_wifi_mgmt_offload sim_wifi_api = { + .wifi_iface.iface_api.init = sim_wifi_init, + .wifi_iface.get_type = sim_wifi_get_type, + .wifi_iface.enable = sim_wifi_enable, + .wifi_mgmt_api = &sim_wifi_mgmt, +}; + +static struct wifi_sim_iface_data data; +NET_DEVICE_OFFLOAD_INIT(sim_wifi_dev, "sim_wifi_dev", sim_wifi_dev_init, NULL, &data, NULL, + CONFIG_WIFI_INIT_PRIORITY, &sim_wifi_api, NET_ETH_MTU); +CONNECTIVITY_WIFI_MGMT_BIND(sim_wifi_dev); + +void wifi_sim_in_network_range(bool in_range) +{ + const struct device *dev = &DEVICE_NAME_GET(sim_wifi_dev); + struct wifi_sim_iface_data *data = dev->data; + + LOG_INF("AP is now %s", in_range ? "in range" : "out of range"); + data->ap_in_range = in_range; +} + +void wifi_sim_trigger_disconnect(void) +{ + const struct device *dev = &DEVICE_NAME_GET(sim_wifi_dev); + struct wifi_sim_iface_data *data = dev->data; + + if (data->connected) { + LOG_INF("Simulating network disconnect"); + k_work_submit(&data->disconnect); + k_sleep(K_TICKS(1)); + } +} diff --git a/include/infuse/drivers/wifi/wifi_sim.h b/include/infuse/drivers/wifi/wifi_sim.h new file mode 100644 index 000000000..8a18c9911 --- /dev/null +++ b/include/infuse/drivers/wifi/wifi_sim.h @@ -0,0 +1,45 @@ +/** + * @file + * @brief Simulated Wi-Fi driver + * @copyright 2025 Embeint Holdings Pty Ltd + * @author Jordan Yates + * + * SPDX-License-Identifier: FSL-1.1-ALv2 + */ + +#ifndef INFUSE_SDK_INCLUDE_INFUSE_DRIVERS_WIFI_WIFI_SIM_H_ +#define INFUSE_SDK_INCLUDE_INFUSE_DRIVERS_WIFI_WIFI_SIM_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief wifi_sim API + * @defgroup wifi_sim_apis wifi_sim APIs + * @{ + */ + +/** + * @brief Simulate whether the device is in range of a network + * + * @param in_range True when in range, false otherwise + */ +void wifi_sim_in_network_range(bool in_range); + +/** + * @brief If currently connected to a network, disconnect + */ +void wifi_sim_trigger_disconnect(void); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* INFUSE_SDK_INCLUDE_INFUSE_DRIVERS_WIFI_WIFI_SIM_H_ */ diff --git a/include/infuse/gnss/ubx/cfg.h b/include/infuse/gnss/ubx/cfg.h index 3f948590a..84764c553 100644 --- a/include/infuse/gnss/ubx/cfg.h +++ b/include/infuse/gnss/ubx/cfg.h @@ -121,6 +121,35 @@ enum _ubx_cfg_key_grp { #define _UBX_CFG_KEY_DEFINE(size, group, id, name) \ _UBX_CFG_KEY_NAME(group, name) = (size | (_UBX_CFG_KEY_GRP_##group) | id) +/** + * @addtogroup UBX_CFG_KEY_HW + * @ingroup ubx_cfg + * @{ + */ + +enum ubx_cfg_key_hw { + _UBX_CFG_KEY_DEFINE(_UBX_CFG_KEY_SIZE_1BIT_, HW, 0x2E, ANT_CFG_VOLTCTRL), + _UBX_CFG_KEY_DEFINE(_UBX_CFG_KEY_SIZE_1BIT_, HW, 0x2F, ANT_CFG_SHORTDET), + _UBX_CFG_KEY_DEFINE(_UBX_CFG_KEY_SIZE_1BIT_, HW, 0x30, ANT_CFG_SHORTDET_POL), + _UBX_CFG_KEY_DEFINE(_UBX_CFG_KEY_SIZE_1BIT_, HW, 0x31, ANT_CFG_OPENDET), + _UBX_CFG_KEY_DEFINE(_UBX_CFG_KEY_SIZE_1BIT_, HW, 0x32, ANT_CFG_OPENDET_POL), + _UBX_CFG_KEY_DEFINE(_UBX_CFG_KEY_SIZE_1BIT_, HW, 0x33, ANT_CFG_PWRDOWN), + _UBX_CFG_KEY_DEFINE(_UBX_CFG_KEY_SIZE_1BIT_, HW, 0x34, ANT_CFG_PWRDOWN_POL), + _UBX_CFG_KEY_DEFINE(_UBX_CFG_KEY_SIZE_1BIT_, HW, 0x35, ANT_CFG_RECOVER), + _UBX_CFG_KEY_DEFINE(_UBX_CFG_KEY_SIZE_1BYTE, HW, 0x36, ANT_SUP_SWITCH_PIN), + _UBX_CFG_KEY_DEFINE(_UBX_CFG_KEY_SIZE_1BYTE, HW, 0x37, ANT_SUP_SHORT_PIN), + _UBX_CFG_KEY_DEFINE(_UBX_CFG_KEY_SIZE_1BYTE, HW, 0x38, ANT_SUP_OPEN_PIN), + _UBX_CFG_KEY_DEFINE(_UBX_CFG_KEY_SIZE_2BYTE, HW, 0x3C, ANT_ON_SHORT_US), + _UBX_CFG_KEY_DEFINE(_UBX_CFG_KEY_SIZE_1BYTE, HW, 0x54, ANT_SUP_ENGINE), + _UBX_CFG_KEY_DEFINE(_UBX_CFG_KEY_SIZE_1BYTE, HW, 0x55, ANT_SUP_SHORT_THR), + _UBX_CFG_KEY_DEFINE(_UBX_CFG_KEY_SIZE_1BYTE, HW, 0x56, ANT_SUP_OPEN_THR), + _UBX_CFG_KEY_DEFINE(_UBX_CFG_KEY_SIZE_1BYTE, HW, 0x57, RF_LNA_MODE), +}; + +/** + * @} + */ + /** * @addtogroup UBX_CFG_KEY_I2C * @ingroup ubx_cfg diff --git a/subsys/net/conn_mgr/conn_mgr_wifi_kv_store.c b/subsys/net/conn_mgr/conn_mgr_wifi_kv_store.c index 81c9aff41..0191122c6 100644 --- a/subsys/net/conn_mgr/conn_mgr_wifi_kv_store.c +++ b/subsys/net/conn_mgr/conn_mgr_wifi_kv_store.c @@ -22,12 +22,11 @@ static struct net_mgmt_event_callback wifi_mgmt_cb; static struct k_work_delayable conn_config_changed; static struct k_work_delayable conn_create; static struct k_work_delayable conn_timeout; -static struct k_work_delayable idle_timeout; static struct k_work conn_terminate; static struct net_if *wifi_if; static bool connection_requested; static bool did_conn_timeout; -static bool did_idle_timeout; +static bool manual_disconnect; static bool is_connected; LOG_MODULE_REGISTER(wifi_mgmt, LOG_LEVEL_INF); @@ -114,20 +113,17 @@ static void conn_create_worker(struct k_work *work) static void conn_timeout_worker(struct k_work *work) { did_conn_timeout = true; + manual_disconnect = true; LOG_INF("Connection attempt timed out"); - /* Cancel the pending connection */ + /* Cancel any pending connections */ + k_work_cancel_delayable(&conn_create); (void)net_mgmt(NET_REQUEST_WIFI_DISCONNECT, wifi_if, NULL, 0); /* Notify stack of timeout */ net_mgmt_event_notify(NET_EVENT_CONN_IF_TIMEOUT, wifi_if); } -static void wifi_mgmt_used(struct conn_mgr_conn_binding *const binding) -{ - k_work_reschedule(&idle_timeout, K_SECONDS(binding->idle_timeout)); -} - static void conn_config_changed_worker(struct k_work *work) { int timeout; @@ -143,6 +139,7 @@ static void conn_config_changed_worker(struct k_work *work) } /* Configuration changed, trigger a disconnect */ + manual_disconnect = true; (void)net_mgmt(NET_REQUEST_WIFI_DISCONNECT, wifi_if, NULL, 0); /* Reschedule connection */ if (conn_mgr_if_get_flag(wifi_if, CONN_MGR_IF_PERSISTENT)) { @@ -161,7 +158,6 @@ static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, uint64_t { const struct wifi_status *status = cb->info; bool persistent = conn_mgr_if_get_flag(wifi_if, CONN_MGR_IF_PERSISTENT); - struct conn_mgr_conn_binding *const binding = conn_mgr_if_get_binding(iface); int timeout; if (iface != wifi_if) { @@ -175,11 +171,7 @@ static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, uint64_t /* Cancel any pending work timeout */ LOG_INF("Connection successful"); (void)k_work_cancel_delayable(&conn_timeout); - /* Start idle timeout if configured */ - did_idle_timeout = false; - if (binding->idle_timeout != CONN_MGR_IF_NO_TIMEOUT) { - wifi_mgmt_used(binding); - } + manual_disconnect = false; } else if (did_conn_timeout && !persistent) { /* Don't retry if the connection timed out and its not persistent */ LOG_INF("Non-persistent connection timed-out"); @@ -199,17 +191,12 @@ static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, uint64_t LOG_INF("Connection lost (%d)%s", status->disconn_reason, persistent ? ", retrying" : ""); - /* Cancel any pending idle timeouts */ - if (binding->idle_timeout != CONN_MGR_IF_NO_TIMEOUT) { - k_work_cancel_delayable(&idle_timeout); - } - if (persistent) { #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT /* WPA SUPP automatically attempts to reconnect. - * Unless we requested the disconnect in idle timeout. + * Unless we explicitly requested the disconnect. */ - if (did_idle_timeout) { + if (manual_disconnect) { k_work_schedule(&conn_create, K_SECONDS(1)); } #else @@ -223,8 +210,8 @@ static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, uint64_t } } else { #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT - /* Stop reconnection attempts (unless idle timeout already did) */ - if (!did_idle_timeout) { + /* Stop reconnection attempts (unless explicit disconnect already did) */ + if (!manual_disconnect) { (void)net_mgmt(NET_REQUEST_WIFI_DISCONNECT, wifi_if, NULL, 0); } #endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT */ @@ -244,7 +231,6 @@ static int wifi_mgmt_connect(struct conn_mgr_conn_binding *const binding) /* Connection is now requested */ connection_requested = true; did_conn_timeout = false; - did_idle_timeout = false; /* Schedule the connection */ k_work_schedule(&conn_create, K_NO_WAIT); /* Schedule the timeout if set */ @@ -256,16 +242,9 @@ static int wifi_mgmt_connect(struct conn_mgr_conn_binding *const binding) return 0; } -static void conn_idle_worker(struct k_work *work) -{ - LOG_INF("Interface idle"); - did_idle_timeout = true; - (void)net_mgmt(NET_REQUEST_WIFI_DISCONNECT, wifi_if, NULL, 0); - net_mgmt_event_notify(NET_EVENT_CONN_IF_IDLE_TIMEOUT, wifi_if); -} - static void conn_terminate_worker(struct k_work *work) { + manual_disconnect = true; (void)net_mgmt(NET_REQUEST_WIFI_DISCONNECT, wifi_if, NULL, 0); } @@ -312,7 +291,6 @@ static void wifi_mgmt_init(struct conn_mgr_conn_binding *const binding) k_work_init_delayable(&conn_create, conn_create_worker); k_work_init_delayable(&conn_timeout, conn_timeout_worker); - k_work_init_delayable(&idle_timeout, conn_idle_worker); k_work_init_delayable(&conn_config_changed, conn_config_changed_worker); k_work_init(&conn_terminate, conn_terminate_worker); @@ -331,7 +309,6 @@ static void wifi_mgmt_init(struct conn_mgr_conn_binding *const binding) static struct conn_mgr_conn_api l2_wifi_conn_api = { .connect = wifi_mgmt_connect, - .used = wifi_mgmt_used, .disconnect = wifi_mgmt_disconnect, .init = wifi_mgmt_init, }; diff --git a/tests/net/conn_mgr/wifi_kv_store/CMakeLists.txt b/tests/net/conn_mgr/wifi_kv_store/CMakeLists.txt new file mode 100644 index 000000000..8818abd3b --- /dev/null +++ b/tests/net/conn_mgr/wifi_kv_store/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(wifi_kv_store) + +target_sources(app PRIVATE + src/main.c +) diff --git a/tests/net/conn_mgr/wifi_kv_store/boards/native_sim.overlay b/tests/net/conn_mgr/wifi_kv_store/boards/native_sim.overlay new file mode 100644 index 000000000..88287259c --- /dev/null +++ b/tests/net/conn_mgr/wifi_kv_store/boards/native_sim.overlay @@ -0,0 +1,5 @@ +/ { + chosen { + infuse,kv-partition = &storage_partition; + }; +}; diff --git a/tests/net/conn_mgr/wifi_kv_store/prj.conf b/tests/net/conn_mgr/wifi_kv_store/prj.conf new file mode 100644 index 000000000..54ff85868 --- /dev/null +++ b/tests/net/conn_mgr/wifi_kv_store/prj.conf @@ -0,0 +1,12 @@ +CONFIG_ZTEST=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_NETWORKING=y +CONFIG_INFUSE_SDK_NETWORKING=y +CONFIG_WIFI=y +CONFIG_WIFI_SIM=y +CONFIG_WIFI_USAGE_MODE_STA=y +CONFIG_NET_L2_WIFI_MGMT=y +CONFIG_FLASH=y +CONFIG_FLASH_MAP=y +CONFIG_NVS=y +CONFIG_KV_STORE=y diff --git a/tests/net/conn_mgr/wifi_kv_store/src/main.c b/tests/net/conn_mgr/wifi_kv_store/src/main.c new file mode 100644 index 000000000..ad5063b78 --- /dev/null +++ b/tests/net/conn_mgr/wifi_kv_store/src/main.c @@ -0,0 +1,329 @@ +/** + * @file + * @copyright 2024 Embeint Holdings Pty Ltd + * @author Jordan Yates + * + * SPDX-License-Identifier: FSL-1.1-ALv2 + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +static void validate_initial(struct net_if *iface) +{ + zassert_not_null(iface); + zassert_false(net_if_is_admin_up(iface)); + zassert_false(net_if_is_carrier_ok(iface)); + zassert_true(net_if_is_dormant(iface)); +} + +static void validate_connected(struct net_if *iface) +{ + zassert_true(net_if_is_admin_up(iface)); + zassert_true(net_if_is_carrier_ok(iface)); + zassert_false(net_if_is_dormant(iface)); +} + +static void validate_disconnected(struct net_if *iface, bool admin_up, bool carrier_up) +{ + zassert_equal(admin_up, net_if_is_admin_up(iface)); + zassert_equal(carrier_up, net_if_is_carrier_ok(iface)); + zassert_true(net_if_is_dormant(iface)); +} + +ZTEST(wifi_kv_store, test_no_configuration) +{ + struct net_if *iface = net_if_get_first_wifi(); + + validate_initial(iface); + + /* Turn on all interfaces */ + conn_mgr_all_if_up(true); + conn_mgr_all_if_connect(true); + + /* No WiFi configuration, nothing should happen */ + k_sleep(K_SECONDS(2)); + validate_disconnected(iface, true, true); + + conn_mgr_all_if_disconnect(true); + conn_mgr_all_if_down(true); +} + +ZTEST(wifi_kv_store, test_configured_on_boot) +{ + KV_STRING_CONST(ssid, CONFIG_WIFI_SIM_AP_SSID); + KV_STRING_CONST(psk, CONFIG_WIFI_SIM_AP_PSK); + struct net_if *iface = net_if_get_first_wifi(); + + validate_initial(iface); + + zassert_equal(sizeof(ssid), kv_store_write(KV_KEY_WIFI_SSID, &ssid, sizeof(ssid))); + zassert_equal(sizeof(psk), kv_store_write(KV_KEY_WIFI_PSK, &psk, sizeof(psk))); + k_sleep(K_MSEC(200)); + + /* Turn on all interfaces */ + conn_mgr_all_if_up(true); + conn_mgr_all_if_connect(true); + + /* Should now be connected */ + k_sleep(K_SECONDS(1)); + validate_connected(iface); + + /* Turn off all interfaces */ + conn_mgr_all_if_disconnect(true); + /* Delay required due to the instantaneous behaviour of posix */ + k_sleep(K_MSEC(10)); + conn_mgr_all_if_down(true); + k_sleep(K_MSEC(10)); +} + +ZTEST(wifi_kv_store, test_configured_on_boot_retried) +{ + KV_STRING_CONST(ssid, CONFIG_WIFI_SIM_AP_SSID); + KV_STRING_CONST(psk, CONFIG_WIFI_SIM_AP_PSK); + struct net_if *iface = net_if_get_first_wifi(); + + validate_initial(iface); + + zassert_equal(sizeof(ssid), kv_store_write(KV_KEY_WIFI_SSID, &ssid, sizeof(ssid))); + zassert_equal(sizeof(psk), kv_store_write(KV_KEY_WIFI_PSK, &psk, sizeof(psk))); + k_sleep(K_MSEC(200)); + + /* Not in range to start with */ + wifi_sim_in_network_range(false); + + /* Turn on all interfaces */ + conn_mgr_all_if_up(true); + conn_mgr_all_if_connect(true); + + /* There is no connection timeout, so individual timeouts should be retried */ + k_sleep(K_SECONDS(6)); + wifi_sim_in_network_range(true); + + /* Should now be connected */ + k_sleep(K_SECONDS(2)); + validate_connected(iface); + + /* Simulate a disconnect */ + wifi_sim_trigger_disconnect(); + + /* Not persistent, should not attempt to reconnect, admin and carrier down */ + k_sleep(K_SECONDS(2)); + validate_disconnected(iface, false, false); + + /* Turn off all interfaces */ + conn_mgr_all_if_disconnect(true); + /* Delay required due to the instantaneous behaviour of posix */ + k_sleep(K_MSEC(10)); + conn_mgr_all_if_down(true); + k_sleep(K_MSEC(10)); +} + +ZTEST(wifi_kv_store, test_configured_on_boot_timeout) +{ + KV_STRING_CONST(ssid, CONFIG_WIFI_SIM_AP_SSID); + KV_STRING_CONST(psk, CONFIG_WIFI_SIM_AP_PSK); + struct net_if *iface = net_if_get_first_wifi(); + + validate_initial(iface); + + zassert_equal(sizeof(ssid), kv_store_write(KV_KEY_WIFI_SSID, &ssid, sizeof(ssid))); + zassert_equal(sizeof(psk), kv_store_write(KV_KEY_WIFI_PSK, &psk, sizeof(psk))); + k_sleep(K_MSEC(200)); + + /* Not in range to start with */ + wifi_sim_in_network_range(false); + + /* Connection timeout is 4 seconds */ + zassert_equal(0, conn_mgr_if_set_timeout(iface, 4)); + + /* Turn on all interfaces */ + conn_mgr_all_if_up(true); + conn_mgr_all_if_connect(true); + + k_sleep(K_SECONDS(1)); + zassert_true(net_if_is_admin_up(iface)); + + /* Connection should have timed out and taken interfaces down */ + k_sleep(K_SECONDS(5)); + zassert_false(net_if_is_admin_up(iface)); + zassert_false(net_if_is_carrier_ok(iface)); + + /* Coming back in range shouldn't do anything */ + wifi_sim_in_network_range(true); + k_sleep(K_SECONDS(3)); + zassert_false(net_if_is_admin_up(iface)); + zassert_false(net_if_is_carrier_ok(iface)); +} + +ZTEST(wifi_kv_store, test_configured_after_up) +{ + KV_STRING_CONST(ssid, CONFIG_WIFI_SIM_AP_SSID); + KV_STRING_CONST(psk, CONFIG_WIFI_SIM_AP_PSK); + struct net_if *iface = net_if_get_first_wifi(); + + validate_initial(iface); + + /* Turn on all interfaces */ + conn_mgr_all_if_up(true); + conn_mgr_all_if_connect(true); + + /* Not connected to start with */ + k_sleep(K_SECONDS(1)); + validate_disconnected(iface, true, true); + + /* Write the network configuration */ + zassert_equal(sizeof(ssid), kv_store_write(KV_KEY_WIFI_SSID, &ssid, sizeof(ssid))); + zassert_equal(sizeof(psk), kv_store_write(KV_KEY_WIFI_PSK, &psk, sizeof(psk))); + + /* Still not connected, interface is not persistent so not retried */ + k_sleep(K_SECONDS(1)); + validate_disconnected(iface, true, true); + + /* Turn off all interfaces */ + conn_mgr_all_if_disconnect(true); + /* Delay required due to the instantaneous behaviour of posix */ + k_sleep(K_MSEC(10)); + conn_mgr_all_if_down(true); + k_sleep(K_MSEC(10)); +} + +ZTEST(wifi_kv_store, test_persistent_configured_after_up) +{ + KV_STRING_CONST(ssid, CONFIG_WIFI_SIM_AP_SSID); + KV_STRING_CONST(psk, CONFIG_WIFI_SIM_AP_PSK); + struct net_if *iface = net_if_get_first_wifi(); + + conn_mgr_if_set_flag(iface, CONN_MGR_IF_PERSISTENT, true); + + validate_initial(iface); + + /* Not in range to start with */ + wifi_sim_in_network_range(false); + + /* Turn on all interfaces */ + conn_mgr_all_if_up(true); + conn_mgr_all_if_connect(true); + + /* Not connected to start with */ + k_sleep(K_SECONDS(1)); + validate_disconnected(iface, true, true); + + /* Write the network configuration */ + zassert_equal(sizeof(ssid), kv_store_write(KV_KEY_WIFI_SSID, &ssid, sizeof(ssid))); + zassert_equal(sizeof(psk), kv_store_write(KV_KEY_WIFI_PSK, &psk, sizeof(psk))); + + /* Still not connected (AP not in range) */ + k_sleep(K_SECONDS(2)); + validate_disconnected(iface, true, true); + + /* Now back in range */ + wifi_sim_in_network_range(true); + + /* Should now be connected */ + k_sleep(K_SECONDS(2)); + validate_connected(iface); + + /* Simulate a disconnect */ + wifi_sim_trigger_disconnect(); + + /* Should automatically reconnect */ + k_sleep(K_SECONDS(2)); + validate_connected(iface); + + /* Delete the configuration */ + kv_store_delete(KV_KEY_WIFI_SSID); + kv_store_delete(KV_KEY_WIFI_PSK); + + /* Transitions back to disconnected */ + k_sleep(K_SECONDS(1)); + validate_disconnected(iface, true, true); + + /* Turn off all interfaces */ + conn_mgr_all_if_disconnect(true); + /* Delay required due to the instantaneous behaviour of posix */ + k_sleep(K_MSEC(10)); + conn_mgr_all_if_down(true); + k_sleep(K_MSEC(10)); +} + +ZTEST(wifi_kv_store, test_bad_ssid) +{ + KV_STRING_CONST(ssid, CONFIG_WIFI_SIM_AP_SSID "wrong"); + KV_STRING_CONST(psk, CONFIG_WIFI_SIM_AP_PSK); + struct net_if *iface = net_if_get_first_wifi(); + + /* Write the network configuration */ + zassert_equal(sizeof(ssid), kv_store_write(KV_KEY_WIFI_SSID, &ssid, sizeof(ssid))); + zassert_equal(sizeof(psk), kv_store_write(KV_KEY_WIFI_PSK, &psk, sizeof(psk))); + k_sleep(K_MSEC(200)); + + validate_initial(iface); + + /* Turn on all interfaces */ + conn_mgr_all_if_up(true); + conn_mgr_all_if_connect(true); + + /* Not connected to start with */ + k_sleep(K_SECONDS(1)); + validate_disconnected(iface, true, true); + + /* Turn off all interfaces */ + conn_mgr_all_if_disconnect(true); + /* Delay required due to the instantaneous behaviour of posix */ + k_sleep(K_MSEC(10)); + conn_mgr_all_if_down(true); + k_sleep(K_MSEC(10)); +} + +ZTEST(wifi_kv_store, test_bad_psk) +{ + KV_STRING_CONST(ssid, CONFIG_WIFI_SIM_AP_SSID); + KV_STRING_CONST(psk, CONFIG_WIFI_SIM_AP_PSK "wrong"); + struct net_if *iface = net_if_get_first_wifi(); + + /* Write the network configuration */ + zassert_equal(sizeof(ssid), kv_store_write(KV_KEY_WIFI_SSID, &ssid, sizeof(ssid))); + zassert_equal(sizeof(psk), kv_store_write(KV_KEY_WIFI_PSK, &psk, sizeof(psk))); + k_sleep(K_MSEC(200)); + + validate_initial(iface); + + /* Turn on all interfaces */ + conn_mgr_all_if_up(true); + conn_mgr_all_if_connect(true); + + /* Not connected to start with */ + k_sleep(K_SECONDS(1)); + validate_disconnected(iface, true, true); + + /* Turn off all interfaces */ + conn_mgr_all_if_disconnect(true); + /* Delay required due to the instantaneous behaviour of posix */ + k_sleep(K_MSEC(10)); + conn_mgr_all_if_down(true); + k_sleep(K_MSEC(10)); +} + +static void test_before(void *fixture) +{ + struct net_if *iface = net_if_get_first_wifi(); + + wifi_sim_in_network_range(true); + conn_mgr_if_set_flag(iface, CONN_MGR_IF_NO_AUTO_CONNECT, true); + conn_mgr_if_set_flag(iface, CONN_MGR_IF_PERSISTENT, false); + conn_mgr_if_set_timeout(iface, CONN_MGR_IF_NO_TIMEOUT); + kv_store_delete(KV_KEY_WIFI_SSID); + kv_store_delete(KV_KEY_WIFI_PSK); +} + +ZTEST_SUITE(wifi_kv_store, NULL, NULL, test_before, NULL, NULL); diff --git a/tests/net/conn_mgr/wifi_kv_store/testcase.yaml b/tests/net/conn_mgr/wifi_kv_store/testcase.yaml new file mode 100644 index 000000000..c74008ae5 --- /dev/null +++ b/tests/net/conn_mgr/wifi_kv_store/testcase.yaml @@ -0,0 +1,8 @@ +common: + tags: infuse net +tests: + net.conn_mgr.wifi_kv_store: + platform_allow: + - native_sim + integration_platforms: + - native_sim diff --git a/west.yml b/west.yml index 21ac10d6b..6e2db48cd 100644 --- a/west.yml +++ b/west.yml @@ -12,7 +12,7 @@ manifest: projects: - name: zephyr - revision: 7d42b49d4988a1d3a1b90865b26b0f25e451d381 + revision: f4ae8512ba439fc248f40cd1496e2974edfb33de # Limit imported repositories to reduce clone time import: name-allowlist: