Wifi on nRF7002dk with micropython. Scanning works but connecting to a network doesn't.

Hello.

We're trying to expose and use the Wifi stack in micropython in our project for the nRF7002. We've managed to get Wifi scanning to work (based on the sample code), but for whatever reason, connecting to a network does not work. I will provide below as many relevant files as possible:

# This file is part of the MicroPython project, http://micropython.org/
#
# The MIT License (MIT)
#
# Copyright 2020 NXP
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(micropython)

set(MICROPY_PORT_DIR    ${CMAKE_CURRENT_SOURCE_DIR})
set(MICROPY_DIR         ${MICROPY_PORT_DIR}/../..)
set(MICROPY_TARGET      micropython)

include(${MICROPY_DIR}/py/py.cmake)
include(${MICROPY_DIR}/extmod/extmod.cmake)

set(MICROPY_SOURCE_PORT
    main.c
    help.c
    machine_i2c.c
    machine_spi.c
    machine_pin.c
    machine_timer.c
    machine_rtc.c
    modbluetooth_zephyr.c
    modsocket.c
    modzephyr.c
    modzsensor.c
    mphalport.c
    uart_core.c
    zephyr_device.c
    zephyr_storage.c
    mpthreadport.c
    modnfc.c
    nvmc.c
    network_wlan.c
    #modprovisioning.c
)
list(TRANSFORM MICROPY_SOURCE_PORT PREPEND ${MICROPY_PORT_DIR}/)

set(MICROPY_SOURCE_SHARED
    libc/printf.c
    readline/readline.c
    runtime/gchelper_generic.c
    runtime/interrupt_char.c
    runtime/mpirq.c
    runtime/pyexec.c
    runtime/stdout_helpers.c
    timeutils/timeutils.c
)
list(TRANSFORM MICROPY_SOURCE_SHARED PREPEND ${MICROPY_DIR}/shared/)

set(MICROPY_SOURCE_LIB
    oofatfs/ff.c
    oofatfs/ffunicode.c
    littlefs/lfs1.c
    littlefs/lfs1_util.c
    littlefs/lfs2.c
    littlefs/lfs2_util.c
)
list(TRANSFORM MICROPY_SOURCE_LIB PREPEND ${MICROPY_DIR}/lib/)

# Save the manifest file set from the cmake command line.
set(MICROPY_USER_FROZEN_MANIFEST ${MICROPY_FROZEN_MANIFEST})

set(MICROPY_SOURCE_QSTR
    ${MICROPY_SOURCE_PY}
    ${MICROPY_SOURCE_EXTMOD}
    ${MICROPY_SOURCE_SHARED}
    ${MICROPY_SOURCE_LIB}
    ${MICROPY_SOURCE_PORT}
)

zephyr_get_include_directories_for_lang(C includes)
zephyr_get_system_include_directories_for_lang(C system_includes)
zephyr_get_compile_definitions_for_lang(C definitions)
zephyr_get_compile_options_for_lang(C options)

set(MICROPY_CPP_FLAGS_EXTRA ${includes} ${system_includes} ${definitions} ${options})

zephyr_library_named(${MICROPY_TARGET})

zephyr_library_include_directories(
    ${MICROPY_INC_CORE}
    ${MICROPY_PORT_DIR}
    ${CMAKE_CURRENT_BINARY_DIR}
    ${ZEPHYR_BASE}/../modules/crypto/mbedtls/include
    ${ZEPHYR_BASE}/subsys/net/ip
    ${CMAKE_CURRENT_LIST_DIR}/../../lib/sdk-nrf/boards/nordic/nrf7002dk
)

# Set the frozen manifest file. Note if MICROPY_FROZEN_MANIFEST is set from the cmake
# command line, then it will override the default and any manifest set by the board.
if (MICROPY_USER_FROZEN_MANIFEST)
    set(MICROPY_FROZEN_MANIFEST ${MICROPY_USER_FROZEN_MANIFEST})
elseif (NOT MICROPY_FROZEN_MANIFEST)
    set(MICROPY_FROZEN_MANIFEST ${CMAKE_CURRENT_LIST_DIR}/boards/manifest.py)
endif()

zephyr_library_compile_options(
    -std=gnu99 -fomit-frame-pointer
    -std=gnu99
    -fomit-frame-pointer
    -Os  # Optimize for size
)

zephyr_library_compile_definitions(
    NDEBUG
    MP_CONFIGFILE=<${CONFIG_MICROPY_CONFIGFILE}>
    MICROPY_HEAP_SIZE=${CONFIG_MICROPY_HEAP_SIZE}
    FFCONF_H=\"${MICROPY_OOFATFS_DIR}/ffconf.h\"
    MICROPY_VFS_FAT=$<BOOL:${CONFIG_MICROPY_VFS_FAT}>
    MICROPY_VFS_LFS1=$<BOOL:${CONFIG_MICROPY_VFS_LFS1}>
    MICROPY_VFS_LFS2=$<BOOL:${CONFIG_MICROPY_VFS_LFS2}>
)

zephyr_library_sources(${MICROPY_SOURCE_QSTR})
zephyr_library_link_libraries(kernel)

add_dependencies(${MICROPY_TARGET} zephyr_generated_headers)

include(${MICROPY_DIR}/py/mkrules.cmake)

target_sources(app PRIVATE
    src/zephyr_start.c
    src/zephyr_getchar.c
)

target_link_libraries(app PRIVATE ${MICROPY_TARGET})

The Kconfig:

# This file is part of the MicroPython project, http://micropython.org/
#
# The MIT License (MIT)
#
# Copyright 2020 NXP
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

menu "MicroPython Options"

config MICROPY_CONFIGFILE
	string "Configuration file"
	default "mpconfigport_minimal.h"

config MICROPY_HEAP_SIZE
	int "Heap size"
	default 49152

config MICROPY_VFS_FAT
	bool "FatFS file system"

config MICROPY_VFS_LFS1
	bool "LittleFs version 1 file system"

config MICROPY_VFS_LFS2
	bool "LittleFs version 2 file system"
config CONNECTION_IDLE_TIMEOUT
	int "Time to be waited for a station to connect"
	default 30

choice WIFI_NM_WPA_SUPPLICANT_LOG_LEVEL_CHOICE
    default WIFI_NM_WPA_SUPPLICANT_LOG_LEVEL_DBG
endchoice

config NRF70_QSPI_ENCRYPTION_KEY
	string "16 bytes QSPI encryption key, only for testing purposes"
	depends on BOARD_NRF7002DK_NRF5340_CPUAPP
	help
	  Specify the QSPI encryption key

config STA_CONN_TIMEOUT_SEC
	int "Overall Connection timeout i.e., time to be waited for a station to connect and get an IP address"
	# Zephyr DHCP retry is 1 minute, so set the default to 70 seconds
	default 70
	# 512 has no special meaning, just a reasonable upper limit
	range 0 512
	help
	  Specify the connection timeout, in seconds. This is the overall timeout i.e., time to be waited for
	  a station to connect and get an IP address. DHCP retries should be taken into account when setting
	  this value. If the timeout is set to 0, the connection will not timeout.

config STA_SAMPLE_START_WIFI_THREAD_STACK_SIZE
	int "Stack size for Wi-Fi start thread"
	default 4096
	help
	  Set the stack size for the Wi-Fi start thread.
endmenu # MicroPython Options

source "Kconfig.zephyr"

/*
 * This file is part of the MicroPython project, http://micropython.org/
 *
 * Development of the code in this file was sponsored by Microbric Pty Ltd
 * and Mnemote Pty Ltd
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2016, 2017 Nick Moore @mnemote
 * Copyright (c) 2017 "Eric Poulsen" <[email protected]>
 *
 * Based on esp8266/modnetwork.c which is Copyright (c) 2015 Paul Sokolovsky
 * And the ESP IDF example code which is Public Domain / CC0
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <string.h>

#include "py/objlist.h"
#include "py/runtime.h"
#include "py/mphal.h"
#include "extmod/modnetwork.h"
#include "modnetwork.h"


#if MICROPY_PY_NETWORK_WLAN

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(wifimod, CONFIG_LOG_DEFAULT_LEVEL);

#include <zephyr/kernel.h>
#include <stdio.h>
#include <stdlib.h>
#include <zephyr/shell/shell.h>
#include <zephyr/sys/printk.h>
#include <zephyr/init.h>

#include <zephyr/net/net_if.h>
#include <zephyr/net/wifi_mgmt.h>
#include <zephyr/net/wifi_utils.h>
#include <net/wifi_ready.h>
#include <zephyr/net/net_event.h>
#include <zephyr/net/ethernet.h>
#include <zephyr/net/ethernet_mgmt.h>

#include <zephyr/drivers/gpio.h>

#include "net_private.h"

#define WIFI_SHELL_MODULE "wifi"

#ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS_ONLY
#define WIFI_SHELL_MGMT_EVENTS (NET_EVENT_WIFI_RAW_SCAN_RESULT |                \
				NET_EVENT_WIFI_SCAN_DONE)
#else
#define WIFI_SHELL_MGMT_EVENTS (NET_EVENT_WIFI_SCAN_RESULT |		\
				NET_EVENT_WIFI_SCAN_DONE |		\
				NET_EVENT_WIFI_RAW_SCAN_RESULT)
#endif
#define SCAN_TIMEOUT_MS 10000
#define WIFI_MAC_MAX_LEN 17

static uint32_t scan_result;
static struct net_mgmt_event_callback wifi_shell_mgmt_cb;
static struct net_mgmt_event_callback net_shell_mgmt_cb;

/* The devicetree node identifier for the "led0" alias. */
#define LED0_NODE DT_ALIAS(led0)

#define STATUS_POLLING_MS   300
#define LED_SLEEP_TIME_MS   100

static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);

static K_SEM_DEFINE(wifi_ready_state_changed_sem, 0, 1);
static bool wifi_ready_status;

#ifdef CONFIG_WIFI_READY_LIB
void start_wifi_thread(void);
#define THREAD_PRIORITY K_PRIO_COOP(CONFIG_NUM_COOP_PRIORITIES - 1)
K_THREAD_DEFINE(start_wifi_thread_id, CONFIG_STA_SAMPLE_START_WIFI_THREAD_STACK_SIZE,
	start_wifi_thread, NULL, NULL, NULL,
	THREAD_PRIORITY, 0, -1);
#endif // CONFIG_WIFI_READY_LIB

static struct {
	const struct shell *sh;
	union {
		struct {
			uint8_t connected	: 1;
			uint8_t connect_result	: 1;
			uint8_t disconnect_requested	: 1;
			uint8_t _unused		: 5;
		};
		uint8_t all;
	};
} context;

void toggle_led(void)
{
	int ret;

	if (!device_is_ready(led.port)) {
		LOG_ERR("LED device is not ready");
		return;
	}

	ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
	if (ret < 0) {
		LOG_ERR("Error %d: failed to configure LED pin", ret);
		return;
	}

	while (1) {
		if (context.connected) {
			gpio_pin_toggle_dt(&led);
			k_msleep(LED_SLEEP_TIME_MS);
		} else {
			gpio_pin_set_dt(&led, 0);
			k_msleep(LED_SLEEP_TIME_MS);
		}
	}
}

K_THREAD_DEFINE(led_thread_id, 1024, toggle_led, NULL, NULL, NULL,
		7, 0, 0);

static int cmd_wifi_status(void)
{
	struct net_if *iface = net_if_get_default();
	struct wifi_iface_status status = { 0 };

	if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, iface, &status,
				sizeof(struct wifi_iface_status))) {
		LOG_INF("Status request failed");

		return -ENOEXEC;
	}

	LOG_INF("==================");
	LOG_INF("State: %s", wifi_state_txt(status.state));

	if (status.state >= WIFI_STATE_ASSOCIATED) {
		uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")];

		LOG_INF("Interface Mode: %s",
		       wifi_mode_txt(status.iface_mode));
		LOG_INF("Link Mode: %s",
		       wifi_link_mode_txt(status.link_mode));
		LOG_INF("SSID: %.32s", status.ssid);
		LOG_INF("BSSID: %s",
		       net_sprint_ll_addr_buf(
				status.bssid, WIFI_MAC_ADDR_LEN,
				mac_string_buf, sizeof(mac_string_buf)));
		LOG_INF("Band: %s", wifi_band_txt(status.band));
		LOG_INF("Channel: %d", status.channel);
		LOG_INF("Security: %s", wifi_security_txt(status.security));
		LOG_INF("MFP: %s", wifi_mfp_txt(status.mfp));
		LOG_INF("RSSI: %d", status.rssi);
	}
	return 0;
}

K_SEM_DEFINE(scan_sem, 0, 1);

#if defined CONFIG_WIFI_NRF70_SKIP_LOCAL_ADMIN_MAC
static bool local_mac_check(const uint8_t *const mac)
{
return ((mac[0] & 0x02) ||
((mac[0] == 0x00) && (mac[1] == 0x00) && (mac[2] == 0x5E)));
}
#endif /* CONFIG_WIFI_NRF70_SKIP_LOCAL_ADMIN_MAC */


// struct wifi_scan_result wifi_entries[100] = {0};
struct wifi_scan_result *wifi_entries;
uint8_t wifi_entries_idx=0;

static void handle_wifi_scan_result(struct net_mgmt_event_callback *cb)
{
	const struct wifi_scan_result *entry =
		(const struct wifi_scan_result *)cb->info;
	uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")];
	uint8_t ssid_print[WIFI_SSID_MAX_LEN + 1];
	
	wifi_entries[wifi_entries_idx] = *entry;
	wifi_entries_idx++;

	scan_result++;

	if (scan_result == 1U) {
		printk("%-4s | %-32s %-5s | %-4s | %-4s | %-5s | %s\n",
		       "Num", "SSID", "(len)", "Chan", "RSSI", "Security", "BSSID");
	}

	strncpy(ssid_print, entry->ssid, sizeof(ssid_print) - 1);
	ssid_print[sizeof(ssid_print) - 1] = '\0';

#if defined CONFIG_WIFI_NRF70_SKIP_LOCAL_ADMIN_MAC
	__ASSERT(!local_mac_check(entry->mac), "Locally administered MAC found: %s\n", ssid_print);
#endif /* CONFIG_WIFI_NRF70_SKIP_LOCAL_ADMIN_MAC */

	printk("%-4d | %-32s %-5u | %-4u | %-4d | %-5s | %s\n",
			scan_result, ssid_print, entry->ssid_length,
			entry->channel, entry->rssi,
			wifi_security_txt(entry->security),
			((entry->mac_length) ?
			net_sprint_ll_addr_buf(entry->mac, WIFI_MAC_ADDR_LEN, mac_string_buf,
						sizeof(mac_string_buf)) : ""));
}

static void handle_wifi_scan_done(struct net_mgmt_event_callback *cb)
{
	const struct wifi_status *status =
		(const struct wifi_status *)cb->info;

	if (status->status) {
		LOG_ERR("Scan request failed (%d)", status->status);
	} else {
		printk("Scan request done\n");
	}

	scan_result = 0U;
	k_sem_give(&scan_sem);
}

static void handle_wifi_connect_result(struct net_mgmt_event_callback *cb)
{
	const struct wifi_status *status =
		(const struct wifi_status *) cb->info;

	if (context.connected) {
		return;
	}

	if (status->status) {
		LOG_ERR("Connection failed (%d)", status->status);
	} else {
		LOG_INF("Connected");
		context.connected = true;
	}

	context.connect_result = true;
}

static void handle_wifi_disconnect_result(struct net_mgmt_event_callback *cb)
{
	const struct wifi_status *status =
		(const struct wifi_status *) cb->info;

	if (!context.connected) {
		return;
	}

	if (context.disconnect_requested) {
		LOG_INF("Disconnection request %s (%d)",
			 status->status ? "failed" : "done",
					status->status);
		context.disconnect_requested = false;
	} else {
		LOG_INF("Received Disconnected");
		context.connected = false;
	}

	// cmd_wifi_status();
}

static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb,
				     uint32_t mgmt_event, struct net_if *iface)
{
	switch (mgmt_event) {
	case NET_EVENT_WIFI_SCAN_RESULT:
		handle_wifi_scan_result(cb);
		break;
#ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS
	case NET_EVENT_WIFI_RAW_SCAN_RESULT:
		handle_raw_scan_result(cb);
		break;
#endif
	case NET_EVENT_WIFI_SCAN_DONE:
		handle_wifi_scan_done(cb);
		break;
	case NET_EVENT_IPV4_DHCP_BOUND:
		LOG_INF("Wifi: Got IP via DHCP");
		break;
	case NET_EVENT_WIFI_CONNECT_RESULT:
		LOG_INF("Wi-Fi connect result: status...");
		handle_wifi_connect_result(cb);
		break;
	case NET_EVENT_WIFI_DISCONNECT_RESULT:
		LOG_INF("Wi-Fi disconnect result: status...");
		handle_wifi_disconnect_result(cb);
		break;
	default:
		break;
	}
}

static void print_dhcp_ip(struct net_mgmt_event_callback *cb)
{
	/* Get DHCP info from struct net_if_dhcpv4 and print */
	const struct net_if_dhcpv4 *dhcpv4 = cb->info;
	const struct in_addr *addr = &dhcpv4->requested_ip;
	char dhcp_info[128];

	net_addr_ntop(AF_INET, addr, dhcp_info, sizeof(dhcp_info));

	printk("DHCP IP address: %s\r\n", dhcp_info);
}

static void net_mgmt_event_handler(struct net_mgmt_event_callback *cb,
	uint32_t mgmt_event, struct net_if *iface)
{
	switch (mgmt_event) {
	case NET_EVENT_IPV4_DHCP_BOUND:
		LOG_INF("Net MGMT: Got IP via DHCP");
		print_dhcp_ip(cb);
		break;
	default:
		break;
	}
}

/* AP Mode Configuration */
#define WIFI_AP_SSID       "ESP32-AP"
#define WIFI_AP_PSK        ""
#define WIFI_AP_IP_ADDRESS "192.168.4.1"
#define WIFI_AP_NETMASK    "255.255.255.0"

/* STA Mode Configuration */
#define WIFI_SSID "RT"     		/* Replace `SSID` with WiFi ssid. */
#define WIFI_PSK  "WelcomeToTheFuture"	/* Replace `PASSWORD` with Router password. */

void net_mgmt_callback_init(void)
{
	memset(&context, 0, sizeof(context));

	net_mgmt_init_event_callback(&wifi_shell_mgmt_cb,
				     wifi_mgmt_event_handler,
				     WIFI_SHELL_MGMT_EVENTS);

	net_mgmt_add_event_callback(&wifi_shell_mgmt_cb);

	net_mgmt_init_event_callback(&net_shell_mgmt_cb,
				     net_mgmt_event_handler,
				     NET_EVENT_IPV4_DHCP_BOUND);

	net_mgmt_add_event_callback(&net_shell_mgmt_cb);

	printk("Starting %s with CPU frequency: %d MHz\r\n", CONFIG_BOARD, SystemCoreClock/MHZ(1));
	k_sleep(K_SECONDS(1));
}

#ifdef CONFIG_WIFI_READY_LIB
void wifi_ready_cb(bool wifi_ready)
{
	LOG_DBG("Is Wi-Fi ready?: %s", wifi_ready ? "yes" : "no");
	wifi_ready_status = wifi_ready;
	k_sem_give(&wifi_ready_state_changed_sem);
}

static int register_wifi_ready(void)
{
	int ret = 0;
	wifi_ready_callback_t cb;
	struct net_if *iface = net_if_get_first_wifi();

	if (!iface) {
		LOG_ERR("Failed to get Wi-Fi interface");
		return -1;
	}

	cb.wifi_ready_cb = wifi_ready_cb;

	LOG_DBG("Registering Wi-Fi ready callbacks");
	ret = register_wifi_ready_callback(cb, iface);
	if (ret) {
		LOG_ERR("Failed to register Wi-Fi ready callbacks %s", strerror(ret));
		return ret;
	}

	return ret;
}
#endif /* CONFIG_WIFI_READY_LIB */

static int wifi_connect(void)
{
	int ret = 0;
	printk("BEGIN \r\n");
	net_mgmt_callback_init();
	printk("END \r\n");
#ifdef CONFIG_WIFI_READY_LIB
	// ret = register_wifi_ready();
	// if (ret) {
	// 	return ret;
	// }
	k_thread_start(start_wifi_thread_id);
#else
	start_app();
#endif /* CONFIG_WIFI_READY_LIB */


	printk("Connection requested\r\n");

	return ret;

	// return 0;
}

int start_app(void)
{
#if defined(CONFIG_BOARD_NRF7002DK_NRF7001_NRF5340_CPUAPP) || \
	defined(CONFIG_BOARD_NRF7002DK_NRF5340_CPUAPP)
	if (strlen(CONFIG_NRF70_QSPI_ENCRYPTION_KEY)) {
		int ret;
		char key[QSPI_KEY_LEN_BYTES];

		ret = bytes_from_str(CONFIG_NRF70_QSPI_ENCRYPTION_KEY, key, sizeof(key));
		if (ret) {
			LOG_ERR("Failed to parse encryption key: %d\n", ret);
			return 0;
		}

		LOG_DBG("QSPI Encryption key: ");
		for (int i = 0; i < QSPI_KEY_LEN_BYTES; i++) {
			LOG_DBG("%02x", key[i]);
		}
		LOG_DBG("\n");

		ret = qspi_enable_encryption(key);
		if (ret) {
			LOG_ERR("Failed to enable encryption: %d\n", ret);
			return 0;
		}
		LOG_INF("QSPI Encryption enabled");
	} else {
		LOG_INF("QSPI Encryption disabled");
	}
#endif /* CONFIG_BOARD_NRF700XDK_NRF5340 */

	LOG_INF("Static IP address (overridable): %s/%s -> %s",
		CONFIG_NET_CONFIG_MY_IPV4_ADDR,
		CONFIG_NET_CONFIG_MY_IPV4_NETMASK,
		CONFIG_NET_CONFIG_MY_IPV4_GW);

	while (1) {
#ifdef CONFIG_WIFI_READY_LIB
		int ret;

		LOG_INF("Waiting for Wi-Fi to be ready");
		ret = k_sem_take(&wifi_ready_state_changed_sem, K_FOREVER);
		if (ret) {
			LOG_ERR("Failed to take semaphore: %d", ret);
			return ret;
		}

check_wifi_ready:
		if (!wifi_ready_status) {
			LOG_INF("Wi-Fi is not ready");
			/* Perform any cleanup and stop using Wi-Fi and wait for
			 * Wi-Fi to be ready
			 */
			continue;
		}
#endif /* CONFIG_WIFI_READY_LIB */
		wifi_connect();

		while (!context.connect_result) {
			cmd_wifi_status();
			k_sleep(K_MSEC(STATUS_POLLING_MS));
		}

		if (context.connected) {
			cmd_wifi_status();
#ifdef CONFIG_WIFI_READY_LIB
			ret = k_sem_take(&wifi_ready_state_changed_sem, K_FOREVER);
			if (ret) {
				LOG_ERR("Failed to take semaphore: %d", ret);
				return ret;
			}
			goto check_wifi_ready;
#else
			k_sleep(K_FOREVER);
#endif /* CONFIG_WIFI_READY_LIB */
		}
	}

	return 0;
}


	
	
	
#ifdef CONFIG_WIFI_READY_LIB
void start_wifi_thread(void)
{
	start_app();
}
#endif // CONFIG_WIFI_READY_LIB

static mp_obj_t wlan_isconnected(mp_obj_t self_in) {
	struct net_if *iface = net_if_get_wifi_sta();

    if (!iface) {
        return mp_const_false;
    }

    struct wifi_iface_status status = {0};
    int ret = net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, iface,
                       &status, sizeof(struct wifi_iface_status));

    if (ret == 0 && status.state == WIFI_STATE_COMPLETED) {
        return mp_const_true;
    }

    return mp_const_false;
}
static MP_DEFINE_CONST_FUN_OBJ_1(wlan_isconnected_obj, wlan_isconnected);

static bool is_mac_addr_set(struct net_if *iface)
{
	struct net_linkaddr *linkaddr = net_if_get_link_addr(iface);
	struct net_eth_addr wifi_addr;

	if (!linkaddr || linkaddr->len != WIFI_MAC_ADDR_LEN) {
		return false;
	}

	memcpy(wifi_addr.addr, linkaddr->addr, WIFI_MAC_ADDR_LEN);

	return net_eth_is_addr_valid(&wifi_addr);
}

typedef struct _wlan_obj_t {
    mp_obj_base_t base;
    int mode;  // network.STA_IF or network.AP_IF
    bool is_active;
} wlan_obj_t;

static mp_obj_t wlan_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
	mp_arg_check_num(n_args, n_kw, 1, 1, false);
	int mode = mp_obj_get_int(args[0]);
	int ret = 0;
	
	if (mode != 0 && mode != 1) {
		mp_raise_ValueError(MP_ERROR_TEXT("invalid mode"));
	}

	wlan_obj_t *self = m_new_obj(wlan_obj_t);
	self->base.type = &zephyr_network_wlan_type;
	self->mode = mode;
	self->is_active = false;

	net_mgmt_callback_init();
	ret = register_wifi_ready();
	if (ret) {
		return ret;
	}

	if (!is_mac_addr_set(net_if_get_default())) {
		struct net_if *iface = net_if_get_default();
		int ret;
		struct ethernet_req_params params;

		/* Set a local MAC address with Nordic OUI */
		if (net_if_is_admin_up(iface)) {
			ret = net_if_down(iface);
			if (ret < 0 && ret != -EALREADY) {
				printk("Cannot bring down iface (%d)\r\n", ret);
				goto _end;
			}
		}

		ret = net_bytes_from_str(params.mac_address.addr, sizeof(CONFIG_WIFI_MAC_ADDRESS),
					 CONFIG_WIFI_MAC_ADDRESS);
		if (ret) {
			printk("Failed to parse MAC address: %s (%d)\r\n",
				CONFIG_WIFI_MAC_ADDRESS, ret);
			goto _end;
		}

		net_mgmt (NET_REQUEST_ETHERNET_SET_MAC_ADDRESS, iface, &params, sizeof(params));

		ret = net_if_up(iface);
		if (ret < 0 && ret != -EALREADY) {
			printk("Cannot bring up iface (%d)\r\n", ret);
			goto _end;
		}
		printk("OTP not programmed, proceeding with local MAC: %s\r\n", net_sprint_ll_addr(net_if_get_link_addr(iface)->addr, net_if_get_link_addr(iface)->len));
	}

	self->is_active = true;

_end:

	return MP_OBJ_FROM_PTR(self);
}

static mp_obj_t wlan_active(size_t n_args, const mp_obj_t *args) {
    wlan_obj_t *self = MP_OBJ_TO_PTR(args[0]);

    if (n_args == 1) {
        return mp_obj_new_bool(self->is_active);
    } else {
        return mp_const_none;
    }
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_active_obj, 1, 2, wlan_active);

static mp_obj_t network_wlan_scan(mp_obj_t self_in) {
	struct net_if *iface = net_if_get_default();
	struct wifi_scan_params params = {.scan_type = WIFI_SCAN_TYPE_ACTIVE, .bands = 0 };
	mp_obj_t wifi_networks_list = mp_obj_new_list(0, NULL);
	// CLear buffers
	// memset(wifi_entries, 0, sizeof(wifi_entries));
	wifi_entries = calloc(100, sizeof(struct wifi_scan_result));
	wifi_entries_idx=0;

	if (net_mgmt(NET_REQUEST_WIFI_SCAN, iface, &params,
			sizeof(struct wifi_scan_params))) {
				printk("Scan request failed\r\n");
		goto _end;
	}

	printk("Scan requested\n\r");
	k_sem_take(&scan_sem, K_MSEC(SCAN_TIMEOUT_MS));
	
	printk("Found %d networks. \n\r", wifi_entries_idx);
	for (int i=0; i< wifi_entries_idx; i++)
	{
		uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")];
		
		strncpy(mac_string_buf, net_sprint_ll_addr_buf(wifi_entries[i].mac, WIFI_MAC_ADDR_LEN, mac_string_buf, sizeof(mac_string_buf)), strlen(mac_string_buf));
		printk("Network ID: %s & Network MAC: %s \n\r", wifi_entries[i].ssid, mac_string_buf);
		// Debug code
		// printk("Network ID: %s & Network MAC: %s \n\r", wifi_entries[i].ssid, net_sprint_ll_addr_buf(wifi_entries[i].mac, WIFI_MAC_ADDR_LEN, mac_string_buf, sizeof(mac_string_buf)));

		mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL);
		t->items[0] = mp_obj_new_bytes(wifi_entries[i].ssid, wifi_entries[i].ssid_length);
		t->items[1] = mp_obj_new_bytes(mac_string_buf, sizeof(mac_string_buf));
		t->items[2] = MP_OBJ_NEW_SMALL_INT(wifi_entries[i].channel);
		t->items[3] = MP_OBJ_NEW_SMALL_INT(wifi_entries[i].rssi);
		t->items[4] = MP_OBJ_NEW_SMALL_INT(wifi_entries[i].security);
		t->items[5] = mp_const_false; // XXX hidden?
		mp_obj_list_append(wifi_networks_list, MP_OBJ_FROM_PTR(t));
	}
	free(wifi_entries);

	// print our board's own MAC address:
	// ==================================
	const struct net_linkaddr *link_addr = net_if_get_link_addr(iface);

	printk("MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
		link_addr->addr[0], link_addr->addr[1], link_addr->addr[2],
		link_addr->addr[3], link_addr->addr[4], link_addr->addr[5]);
	// ==================================

_end:
	return wifi_networks_list;
}
static MP_DEFINE_CONST_FUN_OBJ_1(network_wlan_scan_obj, network_wlan_scan);

static mp_obj_t network_wlan_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
    enum { ARG_ssid, ARG_key, ARG_bssid };
    static const mp_arg_t allowed_args[] = {
        { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} },
        { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} },
        { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
    };

    // parse args
    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);

    // wifi_config_t wifi_sta_config = {0};

    // // configure any parameters that are given
    // if (n_args > 1) {
    //     size_t len;
    //     const char *p;
    //     if (args[ARG_ssid].u_obj != mp_const_none) {
    //         p = mp_obj_str_get_data(args[ARG_ssid].u_obj, &len);
    //         memcpy(wifi_sta_config.sta.ssid, p, MIN(len, sizeof(wifi_sta_config.sta.ssid)));
    //     }
    //     if (args[ARG_key].u_obj != mp_const_none) {
    //         p = mp_obj_str_get_data(args[ARG_key].u_obj, &len);
    //         memcpy(wifi_sta_config.sta.password, p, MIN(len, sizeof(wifi_sta_config.sta.password)));
    //     }
    //     if (args[ARG_bssid].u_obj != mp_const_none) {
    //         p = mp_obj_str_get_data(args[ARG_bssid].u_obj, &len);
    //         if (len != sizeof(wifi_sta_config.sta.bssid)) {
    //             mp_raise_ValueError(NULL);
    //         }
    //         wifi_sta_config.sta.bssid_set = 1;
    //         memcpy(wifi_sta_config.sta.bssid, p, sizeof(wifi_sta_config.sta.bssid));
    //     }
    //     esp_exceptions(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_sta_config));
    // }

    // esp_exceptions(esp_netif_set_hostname(wlan_sta_obj.netif, mod_network_hostname_data));

    // wifi_sta_reconnects = 0;
    // // connect to the WiFi AP
    // MP_THREAD_GIL_EXIT();
    // esp_exceptions(esp_wifi_connect());
    // MP_THREAD_GIL_ENTER();
    // wifi_sta_connect_requested = true;

	wifi_connect();

    return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_KW(network_wlan_connect_obj, 1, network_wlan_connect);

static const mp_rom_map_elem_t wlan_locals_dict_table[] = {
    { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&wlan_active_obj) },
	{ MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&network_wlan_scan_obj) },
    { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&network_wlan_connect_obj) },
    // { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&wlan_config_obj) },
    // { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&wlan_ifconfig_obj) },
	{ MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&wlan_isconnected_obj) },
};
static MP_DEFINE_CONST_DICT(wlan_locals_dict, wlan_locals_dict_table);

MP_DEFINE_CONST_OBJ_TYPE(
    zephyr_network_wlan_type,
    MP_QSTR_WLAN,
    MP_TYPE_FLAG_NONE,
    make_new, wlan_make_new,
    locals_dict, &wlan_locals_dict
);


#endif // MICROPY_PY_NETWORK_WLAN
0882.nrf7002dk_nrf5340_cpuapp_ns.conf5672.nrf7002dk_nrf5340_cpuapp_ns.overlay70481.prj.confmpconfigport_full.h

We tried enabling:

CONFIG_NET_L2_WIFI_MGMT_LOG_LEVEL_DBG=y

but we're overflowing the flash when we do that:

/opt/nordic/ncs/toolchains/ef4fc6722e/opt/zephyr-sdk/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/bin/ld.bfd: zephyr/zephyr_pre0.elf section `rodata' will not fit in region `FLASH'
/opt/nordic/ncs/toolchains/ef4fc6722e/opt/zephyr-sdk/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/bin/ld.bfd: region `FLASH' overflowed by 33088 bytes
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
FAILED: _sysbuild/sysbuild/images/zephyr-prefix/src/zephyr-stamp/zephyr-build /Users/tudor/Documents/GitHub/micropython_nRF/ports/zephyr/build/_sysbuild/sysbuild/images/zephyr-prefix/src/zephyr-stamp/zephyr-build
cd /Users/tudor/Documents/GitHub/micropython_nRF/ports/zephyr/build/zephyr && /opt/homebrew/bin/cmake --build .
ninja: build stopped: subcommand failed.
FATAL ERROR: command exited with status 1: /opt/homebrew/bin/cmake --build /Users/tudor/Documents/GitHub/micropython_nRF/ports/zephyr/build

In REPL when we try to import the module and run ">>> wlan.connect()", it seems that the interface doesn't initialise/ doesn't do anything and simply disconnects:
>>> MicroPython 51d32015a-dirty on 2025-05-02; zephyr-nrf7002dk with nrf5340
Type "help()" for more information.
>>>
>>>
>>>
>>>
>>>
>>>
>>> import network
>>>
>>> wlan = network.WLAN(network.STA_IF)  # Wi-Fi client
[00:00:00.576,141] <inf> wifi_nrf: Management buffer offload enabled

*** Booting nRF Connect SDK v2.9.1-60d0d6c8d42d ***
*** Using Zephyr OS v3.7.99-ca954a6216c9 ***
[00:00:00.704,620] <inf> net_config: Initializing network
[00:00:00.704,620] <inf> net_config: Waiting interface 1 (0x20009a68) to be up...
[00:00:00.704,803] <inf> net_config: IPv4 address: 192.168.1.99
[00:00:00.704,833] <inf> net_config: Running dhcpv4 client...
[00:00:00.715,118] <inf> wifi_supplicant: wpa_supplicant initialized
Starting nrf7002dk with CPU frequency: 64 MHz
[00:00:43.403,961] <dbg> wifi_supplicant: add_interface: Adding interface wlan0 [1] (0x20009a68)
>>>
>>> wlan.connect()
>>>
>>> wlan.connect()
Starting nrf7002dk with CPU frequency: 64 MHz
[00:00:45.405,731] <inf> wifimod: Static IP address (overridable): 192.168.1.99/255.255.255.0 -> 192.168.1.1
[00:00:45.405,731] <inf> wifimod: Waiting for Wi-Fi to be ready
Starting nrf7002dk with CPU frequency: 64 MHz
Connection requested
Connection requested
[00:00:46.405,944] <inf> wifimod: ==================
[00:00:46.405,975] <inf> wifimod: State: DISCONNECTED
[00:00:46.706,115] <inf> wifimod: ==================
[00:00:46.706,146] <inf> wifimod: State: DISCONNECTED
[00:00:47.006,286] <inf> wifimod: ==================
[00:00:47.006,317] <inf> wifimod: State: DISCONNECTED
[00:00:47.306,457] <inf> wifimod: ==================
[00:00:47.306,488] <inf> wifimod: State: DISCONNECTED
[00:00:47.606,628] <inf> wifimod: ==================
[00:00:47.606,658] <inf> wifimod: State: DISCONNECTED
[00:00:47.906,799] <inf> wifimod: ==================
[00:00:47.906,829] <inf> wifimod: State: DISCONNECTED
[00:00:48.206,970] <inf> wifimod: ==================
[00:00:48.207,000] <inf> wifimod: State: DISCONNECTED
Related